1. *** New version of B4J is available ***
    B4J v7.8
    Dismiss Notice

B4J Question AES128 ECB Encrypt

Discussion in 'B4J Questions' started by aaronk, Aug 23, 2019.

  1. aaronk

    aaronk Well-Known Member Licensed User

    Hi,

    I am trying to encrypt a message using AES128 ECB.

    I ended up working out how to decrypt the message, but can't work out how to encrypt the message back again.

    I have tried used the following code..
    (not sure if this is correct or not)

    Code:
    Sub Encrypt As String
        
        
    Dim Key As String = "0123456789ABCDEF" ' MDEyMzQ1Njc4OUFCQ0RFRg==
        Dim bc As ByteConverter
        
    Dim kg As KeyGenerator
        
        
    Dim C As Cipher
        C.Initialize(
    "AES/ECB/PKCS5Padding")
        
        kg.Initialize(
    "AES")
        kg.KeyFromBytes(Key.GetBytes(
    "UTF8"))
          
        
    Dim textToEncrypt As String = "0000754C//00409D27558D//05.03.10//02.00.44//Hello"
        
    Dim textBytes() As Byte = textToEncrypt.GetBytes("ASCII")
        
    Log($"textBytes.Length = ${textBytes.Length}"$)
        
    Log(bc.HexFromBytes(textBytes))
        
    Dim textEncryptedBytes() As Byte = C.Encrypt(textBytes, kg.Key, False)
        
    Log($"textEncryptedBytes.Length = ${textEncryptedBytes.Length}"$)
        
    Log(bc.HexFromBytes(textEncryptedBytes))
     
        
    Dim textLength As Int  = textBytes.Length
        
    Log($"textLength = ${textLength}"$)
        
    Dim byteBlocks As Int = textLength / 16
        
    If (textLength Mod 16) > 0 Then byteBlocks = byteBlocks + 1
        
    Log($"byteBlocks * 16 = ${byteBlocks *16}"$)
        
    Dim textPadded(byteBlocks * 16As Byte
        bc.ArrayCopy(textBytes, 
    0, textPadded, 0, textBytes.Length)
        
    Log($"textPadded.Length = ${textPadded.Length}"$)
        
    Log(bc.HexFromBytes(textPadded))
        
    For x = 0 To byteBlocks - 1
            
    Dim buffer(16As Byte
            bc.ArrayCopy(textPadded, x * 
    16, buffer, 016)
            
    Dim bufferEncrypted() As Byte = C.Encrypt(buffer, kg.Key, False)
            
    Log($"bufferEncrypted: ${bc.StringFromBytes(bufferEncrypted,"UTF-8")}"$)
        
    Next

    End Sub
    It seems to log:

    textBytes.Length = 49
    30303030373534432F2F3030343039443237353538442F2F30352E30332E31302F2F30322E30302E34342F2F48656C6C6F
    textEncryptedBytes.Length = 64
    CB517EF65D218017C806EE2D4CF03E1A7859FD08E48E1F1D799E9A8D8593041ED6BC07D879092756A99BE059CA98BFEBAB2E5093707E61AC225B3B5C1B3F8D06
    textLength = 49
    byteBlocks * 16 = 64
    textPadded.Length = 64
    30303030373534432F2F3030343039443237353538442F2F30352E30332E31302F2F30322E30302E34342F2F48656C6C6F000000000000000000000000000000
    bufferEncrypted: �Q~�]!���-L�>4�3l�5Vs�c���
    bufferEncrypted: xY��y�����4�3l�5Vs�c���
    bufferEncrypted: ּ�y 'V���Yʘ��4�3l�5Vs�c���
    bufferEncrypted: E׿%R=���0�t���4�3l�5Vs�c���

    However the final message should be:
    �q�!DAZ��R��:f/�Ŝ��h�U�0h�V��ƅHw��s�Č)�o�yZ��%v��_,"

    Any ideas on what I have done wrong ?
     
  2. OliverA

    OliverA Expert Licensed User

    A)
    You are not using the same key/same input/or combo of both. If you go to this site (https://www.devglan.com/online-tools/aes-encryption-decryption) and enter

    0000754C//00409D27558D//05.03.10//02.00.44//Hello

    for your text to be encrypted and select ECB as the mode with 128 bit key size and enter

    0123456789ABCDEF

    as your key and pick HEX output, it will produce the same output as above

    CB517EF65D218017C806EE2D4CF03E1A7859FD08E48E1F1D799E9A8D8593041ED6BC07D879092756A99BE059CA98BFEBAB2E5093707E61AC225B3B5C1B3F8D06

    Therefore 1) Your key is not correct, or 2) your input string is not correct or 3) both key and input are incorrect

    B)
    This does not affect you yet, but you have the incorrect padding. In your previous post you posted the VB code that is used for encryption (https://www.b4x.com/android/forum/threads/aes128-ecb-decrypt.108828/#post-680483). That code uses zero padding. Therefore you need to use zero padding in your encryption formula. Zero padding is not an option with what Java includes, but by including Bouncy Castle, you get the zero padding option. The code I posted in the other thread shows you how to include Bouncy Castle as an encryption provider that allows you to use zero padding without managing your own padding (which you should not. Encryption is already hard enough without complicating things).
     
  3. aaronk

    aaronk Well-Known Member Licensed User

    Isn't that correct? (maybe I am getting confused with all this encryption thing)

    This part of the code (from my first post):
    Code:
    bc.HexFromBytes(textEncryptedBytes)
    is returning:
    CB517EF65D218017C806EE2D4CF03E1A7859FD08E48E1F1D799E9A8D8593041ED6BC07D879092756A99BE059CA98BFEBAB2E5093707E61AC225B3B5C1B3F8D06

    This is the same HEX as shown on https://www.devglan.com/online-tools/aes-encryption-decryption

    Encrypt:
    0000754C//00409D27558D//05.03.10//02.00.44//Hello
    AES 128
    Secret key 0123456789ABCDEF
    Output as HEX
    This is returning the following.
    CB517EF65D218017C806EE2D4CF03E1A7859FD08E48E1F1D799E9A8D8593041ED6BC07D879092756A99BE059CA98BFEBAB2E5093707E61AC225B3B5C1B3F8D06

    Isn't that what I need ?

    Here is how I did the decrypting:
    Code:
    Sub Decrypt(value() As Byte) As String

        
    Dim raw() As Byte = value
        bb.Initialize
        bb.Append(raw)
        
    Dim binaryflag() As Byte = Array As Byte(0x330x360x370x300x420x420x390x460x2f,0x2f,0x31,0x2f,0x2f)
        
    If bb.IndexOf(binaryflag) > -1 Then
            
    Dim msgbytes() As Byte = bb.SubArray2(13,bb.IndexOf2(Array As Byte(0x0),13)) ' use the index of the zerobyte to mark the "end".
        End If

        kg.Initialize(
    "AES")
        kg.KeyFromBytes(Key.GetBytes(
    "UTF8"))
        
        C.Initialize(
    "AES/ECB/NoPadding")

        msgbytes = C.Decrypt(msgbytes, kg.Key, 
    False)

        
    Return BConv.StringFromBytes(msgbytes, "UTF8").Trim
        
    End Sub
    Above works fine.

    I tried:
    Code:
    Sub Encrypt(textToEncrypt As StringAs String
        
        
    Dim Key As String = "0123456789ABCDEF"
        
    Dim bc As ByteConverter
        
    Dim kg As KeyGenerator
        
        
    Dim C As Cipher
        C.Initialize(
    "AES/ECB/PKCS5Padding")
        
        kg.Initialize(
    "AES")
        kg.KeyFromBytes(Key.GetBytes(
    "UTF8"))
        
        
    Dim textBytes() As Byte = textToEncrypt.GetBytes("ASCII")
        
    Log($"textBytes.Length = ${textBytes.Length}"$)
        
    Log(bc.HexFromBytes(textBytes))   
        
        
    Dim textEncryptedBytes() As Byte = C.Encrypt(textBytes, kg.Key, False)
        
    Log($"textEncryptedBytes.Length = ${textEncryptedBytes.Length}"$)
        
    Log(bc.HexFromBytes(textEncryptedBytes))
        
        
    Return bc.StringFromBytes(textEncryptedBytes,"ASCII")
        
    End Sub
    This encrypts the message, and returns the value, but I think it's wrong for some reason.

    Original Encrypted message is:
    3670BB9F//1//�Q~�]!���-L�>xY��y�����ּ�y 'V���Yʘ���d��q{�ۺ�Y��

    When I decrypt it:
    Code:
    Log("Decrypt = " & Decrypt(Packet.Data))
    it logs:
    Decrypt = 0000754C//00409D27558D//05.03.10//02.00.44//Hello

    Which is correct.

    If I encrypt the message:
    Code:
    Log("Encrypt = " & Encrypt("0000754C//00409D27558D//05.03.10//02.00.44//Hello"))
    It returns:
    Encrypt = �Q~�]!���-L�>xY���y��������y 'V���Y�����.P�p~a�"[;\?�

    It looks like I have it done wrong, but can't work out the encryption function. Been trying all day :(

    The AES key is 0123456789ABCDEF during all my testing.
     
  4. OliverA

    OliverA Expert Licensed User

    Read point B again. You are using the wrong padding for the encryption.
     
  5. Erel

    Erel Administrator Staff Member Licensed User

    You are still making the same mistake.

    This line is completely wrong:
    Code:
    Return bc.StringFromBytes(textEncryptedBytes,"ASCII")
    As I've previous wrote (https://www.b4x.com/android/forum/threads/aes128-ecb-decrypt.108828/#post-680140):

    Never convert "random" bytes to string.
    Only bytes that represent a string can be converted to a string.

    Worth repeating: never convert random bytes to string. It will not work.

    Use base64 encoding to convert the bytes to string.

    Encrypted data doesn't represent a string.
     
  6. aaronk

    aaronk Well-Known Member Licensed User

    I did try base64 encoding, but couldn't get it to work as well.

    Are you able to help with the encryption function?

    I am not 100% on how to do this, and getting totally confused with this.
     
  7. Erel

    Erel Administrator Staff Member Licensed User

    You seem to be ignoring my suggestions. I'm not sure how I can help here...
     
  8. aaronk

    aaronk Well-Known Member Licensed User

    I am not ignoring the suggestions, just don't understand how to do it as everything I try doesn't work.

    Do you mean:

    Code:
    Sub Encrypt
        
    Dim bc As ByteConverter
        
        
    Dim textToEncrypt As String = "0000754C//00409D27558D//05.03.10//02.00.44//Hello"
        
        
    Log("textToEncrypt hex = " & bc.HexFromBytes(textToEncrypt.GetBytes("UTF8")))
        
        
    Dim Key As String = "0123456789ABCDEF"
        
        
    Dim kg As KeyGenerator
        
        
    Dim C As Cipher
        C.Initialize(
    "AES/ECB/PKCS5Padding")
        
        kg.Initialize(
    "AES")
        kg.KeyFromBytes(Key.GetBytes(
    "UTF8"))
        
        
    Dim textBytes() As Byte = textToEncrypt.GetBytes("ASCII")
        
    Log($"textBytes.Length = ${textBytes.Length}"$)
        
    Log(bc.HexFromBytes(textBytes))
        
        
    Dim textEncryptedBytes() As Byte = C.Encrypt(textBytes, kg.Key, False)
        
    Log($"textEncryptedBytes.Length = ${textEncryptedBytes.Length}"$)
        
    Log("HexFromBytes = " & bc.HexFromBytes(textEncryptedBytes))
        
        
    Dim su As StringUtils
        
    Log(su.EncodeBase64(textEncryptedBytes))
            
    End Sub
     
  9. Erel

    Erel Administrator Staff Member Licensed User

    Return su.EncodeBase64(textEncryptedBytes)
     
  10. OliverA

    OliverA Expert Licensed User

    If you are trying to replicate the code that he have shown here https://www.b4x.com/android/forum/threads/aes128-ecb-decrypt.108828/#post-680483, then you need to work on the raw data bytes of the incoming/outgoing packet. Looking at that code (the VB/whatever code), the encryption steps are as follows:

    0) Create a buffer to hold encrypted data (of a fixed size IOBuffSize)
    1) Figure out how many pad bytes (zeroes) are needed to 16 byte align the byte array data
    2) Re-dim the incoming byte array to the new size (size of original array + number of pad bytes)
    3) Manually pad new re-dimmed incoming byte array
    4) In a loop, start encrypting the incoming byte array from the 14th position, 16 bytes at a time and store results in encrypted data buffer
    5) Write encrypted data buffer to incoming data buffer from position 14 and on

    So first, how does VB convert a string to bytes? What encoding does it use? The same encoding has to be used on the B4J side (for both the packet data and the key bytes used to encrypt the data). One of the things I notice with the VB code is that the key is pass ByVal. So if any changes are made to the key, the encryption changes, the output changes. So make sure that the key is really the key you think you use on the VB side or the encoding on the VB side will not match the encoding on the B4J side.

    So a method that should produce the same results as your VB function could be:

    Code:
    Sub Encrypt(data() As Byte, key() As Byte) As Byte()
       
    Dim kg As KeyGenerator
       
    Dim C As Cipher
       
    Dim bc As ByteConverter
       
    Dim bb As B4XBytesBuilder ' Part of B4XCollections library
       bb.Initialize
       
       kg.Initialize(
    "AES")
       kg.KeyFromBytes(key)
       
       C.Initialize(
    "AES/ECB/ZeroBytePadding"' We let crypto library take care of padding. We're lazy

       
    'Extract first 13 bytes from data()   
       Dim firstThirteenBytes(13As Byte
       bc.ArrayCopy(data, 
    0, firstThirteenBytes, 013)
       
       
    'Extract data to be encrypted from data()
       Dim toEncryptBytes(data.Length - 13As Byte
       bc.ArrayCopy(data, 
    13, toEncryptBytes, 0, data.Length - 13)
       
       
    'Encrypt
       Dim encryptedBytes() As Byte = C.Encrypt(toEncryptBytes, kg.Key, False)

       
    'Recreate the data packet from first 13 bytes from data() and encrypted information
       bb.Append(firstThirteenBytes)
       bb.Append(encryptedBytes)
       
    Return(bb.ToArray)
    End Sub
    So the steps now are just:
    1) Split packet into two parts
    2) Encrypt second part
    3) Create packet from first part and newly encrypted data

    Usage:
    Code:
    'Non-UI application (console / server application)
    #Region Project Attributes
       
    #CommandLineArgs:
       
    #MergeLibraries: True
    #End Region

    #AdditionalJar: bcprov-jdk15on-160.jar
    '       External Libraries:
    '           #AdditionalJar: bcprov-jdk15on-160
    '           Library can be found here: https://www.bouncycastle.org/download/bcprov-jdk15on-160.jar

    Sub Process_Globals
       
    End Sub

    Sub AppStart (Args() As String)
       
    Dim joSecurity As JavaObject
       joSecurity.InitializeStatic(
    "java.security.Security")
    #if B4J
       Dim jo As JavaObject
       jo.InitializeNewInstance("org.bouncycastle.jce.provider.BouncyCastleProvider", Null)
       joSecurity.RunMethod("addProvider", Array As Object (jo))
    #else if B4A
       ' Seems to just work as of Android 5.1 (oldest version I have)
    '   Dim jo As JavaObject
    '   jo.InitializeNewInstance("org.spongycastle.jce.provider.BouncyCastleProvider", Null)
    '   joSecurity.RunMethod("insertProviderAt", Array As Object (jo, 1))
    #else
       LOG("ERROR: UNSUPPORTED PLATFORM")
       Return
    #End If

       
    Dim bc As ByteConverter
       
       
    Dim stringData As String = "3670BB9F//1//0000754C//00409D27558D//05.03.10//02.00.44//Hello"
       
    Dim stringPassword As String = "0123456789ABCDEF"
       
       
    Dim bytesData() As Byte = stringData.GetBytes("ASCII"' This needs to match the encoding used on the VB side
       Dim bytesPassword() As Byte = stringPassword.GetBytes("ASCII"' This needs to match the encoding used on the VB Side
       
       
    Log($"bytesData: ${bc.HexFromBytes(bytesData)}"$)           'Should match VB's byte data if dumped to HEX
       Log($"bytesPassword: ${bc.HexFromBytes(bytesPassword)}"$)   'Should match VB's byte key if dumped to HEX
       
       
    Dim encryptedPacket() As Byte = Encrypt(bytesData, bytesPassword)
       
    'encryptedPacket() now contains the data packet that needs to be sent via UDP
       
       
    Log($"encryptedPacket: ${bc.HexFromBytes(encryptedPacket)}"$)   'Should match VB's encrypted packet if dumped to HEX
       
    End Sub
     
    DonManfred and aaronk like this.
  11. aaronk

    aaronk Well-Known Member Licensed User

    @OliverA, thanks for your detail reply. Makes a lot of sense now :)
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice