Android Tutorial [B4x] AES Encryption (lessons learned & best practice)

Discussion in 'Tutorials & Examples' started by KMatle, Oct 4, 2018.

  1. KMatle

    KMatle Expert Licensed User

    Last weekend I migrated my XAMPP test environment (Apache/PHP/MySql). It came with PHP 7.x. Yesterday I wanted to test one of my Apps using AES and Mcrypt for it in PHP but it didn't work no more. I noticed that MCrypt was deprecated anyway and even was removed due to security and other issues from PHP 7.x. So I starded searching for an alternative for PHP which is matching B4x (I use agraham's Encryption lib: https://www.b4x.com/android/forum/threads/base64-and-encryption-library.6839/#content)

    Soon I came across OpenSSL which I use for RSA encryption on the PHP side for some years and tried to migrate my code to it. Until then I was using AES-128 Bit. After reading some articles I learned some new things which I want to write down here. Using AES is quite simple if you know the details. Not knowing these details makes your encryption usafe.

    Even on my production servers which use RSA (https://) I use AES addtionally and encrypt ALL data I send/receive to/from them.

    However: AES uses

    - a key (the data is encrypted with this key). The key is either 128, 192 or 256 Bits long (aka AES-128, AES-192 and AES-256). As a string it has a length of 16,24 or 32 chars/bytes. So noch chance to use other lengths

    - an optional IV (initialization vector). If you use a key only once, all is good. Using the same key all the time (e.g. for years) is a security leak! Why? AES uses fixed blocks to organize the encryption. If you encrypt with a key, the sequence of the blocks is always the same without IV. If you encrypt word documents, a lot of may start with "Dear Sir or Madam...." (or similar) the position of this text is always the same. Knowing this makes it very easy to hack your key. Using an IV "randomizes" these blocks which makes it safe again.

    This only works when you use ONE key for a long time and use a different IV for every message you encrypt. By the way the IV MUST have a length of 128 Bits (or 16 Bytes). So how does this work? How do I transfer the IV to the receipient of the message?

    Easy: Keep the key secret. The IV can be transfered non-encrypted (e.g. combine the 16 Bytes long IV and the encrypted message. Get the first 16 Bytes when you receive the message and the rest is the encrypted message. Any method will do.

    Examples:

    Generate random IV (always 128 Bits or 16 Bytes long!). I use just letters and numbers as a string (which will be later converted to Bytes). You can use any Byte you want but be careful when you send the IV because when it contains other chars it may be concerted (URL encoded, special chars, etc.) which causes problems.

    Code:
    Sub GenerateIV As String
        
    Dim PWC As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
        
    Dim IV As String
        
    For i=0 To 15
            IV=IV & PWC.CharAt(
    Rnd(0,PWC.Length))
        
    Next
        
    Return IV
    End Sub
    Encrypt (AES-256) = 32 Chars/Bytes long (32 * 8 = 256)

    Input=Text to encrypt
    IV=The just generated IV
    pass=your key (exact 32 Chars long here for AES-256, 16 for AES-128)

    Code:
    Sub AES_Encrypt(input As String, IV As String, pass As StringAs String

        
    Dim inputB() As Byte = input.GetBytes("UTF8")
        
    Dim passB() As Byte = pass.GetBytes("UTF8")
        
    Dim IVb() As Byte = IV.GetBytes("UTF8")
      
        
    Dim kg As KeyGenerator
        
    Dim C As Cipher
     
        kg.Initialize(
    "AES"'Yes, AES only
        kg.KeyFromBytes(passB)
     
        C.Initialize(
    "AES/CBC/PKCS5Padding")
        C.InitialisationVector = IVb
     
        
    Dim datas() As Byte = C.Encrypt(inputB, kg.Key, True)
     
        
    Return SU.EncodeBase64(datas)
    End Sub
    The resut is a Base64 encoded string

    Decrypt:

    Use same Key AND IV you used for encryption!

    Input: Base64 encoded string
    IV: See encryption
    Pass: See encryption

    Code:
    Sub AES_Decrypt(input As String, IV As String, pass As StringAs String

        
    Dim inputB() As Byte = SU.DecodeBase64(input)
        
    Dim passB() As Byte = pass.GetBytes("UTF8")
        
    Dim IVb() As Byte = IV.GetBytes("UTF8")
      
        
    Dim kg As KeyGenerator
        
    Dim C As Cipher
     
        kg.Initialize(
    "AES")
        kg.KeyFromBytes(passB)
     
        C.Initialize(
    "AES/CBC/PKCS5Padding")
        C.InitialisationVector = IVb
     
        
    Dim datas() As Byte = C.Decrypt(inputB, kg.Key, True)
     
        
    Return BytesToString(datas, 0, datas.Length, "UTF8")

    End Sub
    PHP-Side: https://www.b4x.com/android/forum/threads/b4x-php-compatibility-thread.84473/#post-616967

    Discussion on Stackoverflow: https://stackoverflow.com/questions/9049789/aes-encryption-key-versus-iv

    Wiki: https://en.wikipedia.org/wiki/Initialization_vector

    Lessons learned:

    1. Always use an IV!
    2. Never re-use the same IV again!
    3. For every message generate a new IV!
    4. Update your apps (for me: I need to update my apps and some of my tutorials :))
    5. Don't panic if your backend-server uses https:// (RSA) (it's quite safe)
    6. Not using https:// is VERY unsafe
    5. Happy en-/decryption!
     
    Rubsanpe, udg, asales and 10 others like this.
  2. JohnC

    JohnC Well-Known Member Licensed User

    Thank you for taking the time to share your experiences - I am sure it will save many of us a lot of time :)
     
    KMatle likes this.
  3. fbritop

    fbritop Active Member Licensed User

    @KMatle great piece of code!. Although I'm having some issues.

    I try your functions with:

    Code:
    Sub EncryptText(text As StringAs String
        
    Dim inputB() As Byte = text.GetBytes("utf8")
        
    Dim passB() As Byte = "1234567812345678".GetBytes("utf8")
        
    Dim IVb() As Byte ="1234567812345678".GetBytes("utf8")
        
    Dim  su As StringUtils
        
    Dim kg As KeyGenerator
        
    Dim C As Cipher
        kg.Initialize(
    "AES")
        kg.KeyFromBytes(passB)
         C.Initialize(
    "AES/CBC/PKCS5Padding")
        C.InitialisationVector = IVb
        
    Dim datas() As Byte = C.Encrypt(inputB, kg.Key, True)
        
    Return su.EncodeBase64(datas)
    End Sub

    Sub DecryptText(text As StringAs String
        
    Dim inputB() As Byte = text.GetBytes("utf8")
        
    Dim passB() As Byte = "1234567812345678".GetBytes("utf8")
        
    Dim IVb() As Byte ="1234567812345678".GetBytes("utf8")
        
    Dim kg As KeyGenerator
        
    Dim C As Cipher
        kg.Initialize(
    "AES")
        kg.KeyFromBytes(passB)
        C.Initialize(
    "AES/CBC/PKCS5Padding")
        C.InitialisationVector = IVb
        
    Dim datas() As Byte = C.Decrypt(inputB, kg.Key, True)
        
    Return BytesToString(datas, 0, datas.Length, "UTF8")
    End Sub

    It outputs correctly when I encrypt, but when I try do decrypt then encrypted, it outputs and error:
    javax.crypto.IllegalBlockSizeException: error:1e00007b:Cipher functions:OPENSSL_internal:WRONG_FINAL_BLOCK_LENGTH for the line that does the "C.Decrypt" function.

    The call is made like this:
    Code:
    dim qrCode as String=EncryptText("TEST1")
    Log(qrCode)
    '-->Prints MwokvR3ICrCKK4deYqssLQ==
    Log(DecryptText(qrCode))<-- Error


     
  4. OliverA

    OliverA Expert Licensed User

    This line is wrong. Remember, the input string to your decrypt function is a Base64 encoded string. You have to decode the string from Base64, not just turn that string into a Byte array. Look at the AES_Decrypt method again.

    Note/update: Why not just use B4XEnryption (https://www.b4x.com/android/forum/threads/b4xencryption.48177/) instead of trying to roll your own. It takes care of generating a random IV (it really needs to be. If you always use a fixed IV, you may as well not use one) and it salts the password, without you having to lift a finger. Plus it works with B4J, B4A and B4i.
     
    KMatle likes this.
  5. fbritop

    fbritop Active Member Licensed User

    Thanks @OliverA
    I'm trying that one two!, and I just found the reference to complete the circle with an IIS Server with this DLL:

    https://github.com/chrisleeuk/B4XEncryption.net from @Chris Lee. The problem until I found this DLL was how to Decrypt/Encrypt at my server side with B4X Encryption was not posible (not yet, because I just started testing this DLL).

    Thanks
    FBP
     
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