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.
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)
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
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!
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
AES is a variant of Rijndael which has a fixed blocksize of 128 bits, and a key size of 128, 192, or 256bits...
- 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.
An initialization vector (IV) is an arbitrary number that can be used along with a secret key for data encryption. This number, also called a nonce, is employed only one time in any session. ... The IV length is usually comparable to the length of the encryption key or block of the cipher in use.
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.
B4X:
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)
B4X:
Sub AES_Encrypt(input As String, IV As String, pass As String) As 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
B4X:
Sub AES_Decrypt(input As String, IV As String, pass As String) As 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!