Android Question [SOLVED] Decrypt with AES/CBC/PKCS7Padding From C# Encrypt

AHilberink

Active Member
Licensed User
Longtime User
Hi,

I am having trouble to decrypt a string encrypted by a C# code.

To decrypt in C# I use:
B4X:
        //Decrypt
        public static string DecryptString(string cipherText, string passPhrase)
        {
            byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
            byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
            PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
            byte[] keyBytes = password.GetBytes(keysize / 8);
            RijndaelManaged symmetricKey = new RijndaelManaged();
            symmetricKey.Mode = CipherMode.CBC;
            symmetricKey.Padding = PaddingMode.PKCS7;
            ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
            MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
            CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
            byte[] plainTextBytes = new byte[cipherTextBytes.Length];
            int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
            memoryStream.Close();
            cryptoStream.Close();
            return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
        }

where keysize=256

I tried the following B4A code to decrypt:
B4X:
Sub Decryptcbc(enc As String)
    Dim Bconv As ByteConverter
    Dim key(0) As Byte
    Dim data(0) As Byte
    Dim iv(0) As Byte
    Dim Lock As String
    Dim Sleutel As String
    Dim c As Cipher
    Dim su As StringUtils
    Dim kg As KeyGenerator
    
    Lock="alhbcde8qwrtyz27"
    iv = Lock.GetBytes("UTF8")
   
    c.Initialize("AES/CBC/PKCS7Padding") 
    c.InitialisationVector = iv
    Sleutel="Jaap123456789012"
    kg.Initialize("AES")
    kg.KeyFromBytes(Sleutel.GetBytes("UTF8"))
    key = Sleutel.GetBytes("UTF8")
    Msgbox(Bconv.HexFromBytes(key), "Key " & key.Length & " bytes")
    data = su.DecodeBase64(enc)
    Msgbox(Bconv.HexFromBytes(data), "Encrypted is " & data.Length & " bytes")
    data = c.Decrypt(data, kg.Key, True)
    Msgbox(Bconv.StringFromBytes(data, "UTF8"), "Decrypted")
End Sub

I think the trouble is in:
B4X:
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
byte[] keyBytes = password.GetBytes(keysize / 8);

which is not the same as:
B4X:
    kg.Initialize("AES")
    kg.KeyFromBytes(Sleutel.GetBytes("UTF8"))

Based on other thread I found the following Javacode:
B4X:
        byte[] password = PassPhrase.getBytes("ASCII");
        byte[] salt = PKCS5S1ParametersGenerator.PKCS5PasswordToBytes(SaltValue.toCharArray());

        PKCS5S1ParametersGenerator generator = new PasswordDeriveBytes(new SHA1Digest());
        generator.init(password, salt, PasswordIterations);

        byte[] key = ((KeyParameter)generator.generateDerivedParameters(32*8)).getKey();

But I have no knowledge of using Javacode directly in B4A and I don't know if the above Javacode is the solution.

Can someone help me?

Kind regards,
André
 

AHilberink

Active Member
Licensed User
Longtime User
Code with Msgbox = broken code. First step is to replace it with Log.

Your C# doesn't use any salt.
AES = 128 key size. I'm not sure that it is the same size as your C# code.

I will replace Msgbox with Log. I had this code from an old thread and didn't replace it yet.

The keysize I use in my C# is based on 256.
Is it possible to use the same size within Android/B4A?
 
Upvote 0

KMatle

Expert
Licensed User
Longtime User
AES-256: Key 32 Bytes (256 Bits / 8)
AES-128: Key 16 Bytes (128 / 8)
IV: 16 Bytes (both)

Check if IV, Key and Salt looks the same and IV and Salt are located at the same position. Don't use strings, only use bytes (maybe there's a string conversation problem here) for a test (like 16/32 bytes of zeroes for a quick test).
 
Upvote 0

AHilberink

Active Member
Licensed User
Longtime User
AES-256: Key 32 Bytes (256 Bits / 8)
AES-128: Key 16 Bytes (128 / 8)
IV: 16 Bytes (both)

Check if IV, Key and Salt looks the same and IV and Salt are located at the same position. Don't use strings, only use bytes (maybe there's a string conversation problem here) for a test (like 16/32 bytes of zeroes for a quick test).

How can I use AES-256: Key 32 Bytes (256 Bits / 8) within Android?

I also tried Keysize of 128 within my C# encryption. I did not succeed in decrypting it from B4A. I think it has something to do with the keysize or blocksize.
Can somebody help translating my C# code in the first post to B4A?

The encryptingcode is pretty the same:
B4X:
        //Encrypt
        public static string EncryptString(string plainText, string passPhrase)
        {
            byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
            Console.WriteLine(initVectorBytes.Length);
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
            PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
            byte[] keyBytes = password.GetBytes(keysize / 8);
            Console.WriteLine(keyBytes.Length);
            RijndaelManaged symmetricKey = new RijndaelManaged();
            symmetricKey.Mode = CipherMode.CBC;
            symmetricKey.Padding = PaddingMode.PKCS7;
            ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
            MemoryStream memoryStream = new MemoryStream();
            CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
            cryptoStream.FlushFinalBlock();
            byte[] cipherTextBytes = memoryStream.ToArray();
            Console.WriteLine(cipherTextBytes.Length);
            memoryStream.Close();
            cryptoStream.Close();
            return Convert.ToBase64String(cipherTextBytes);
        }

This is the error I got on decrypting using encrypt library:
B4X:
synchroniseer_decryptcbc (java line: 457)
javax.crypto.IllegalBlockSizeException: error:1e00007b:Cipher functions:OPENSSL_internal:WRONG_FINAL_BLOCK_LENGTH
    at com.android.org.conscrypt.NativeCrypto.EVP_CipherFinal_ex(Native Method)
    at com.android.org.conscrypt.OpenSSLCipher$EVP_CIPHER.doFinalInternal(OpenSSLCipher.java:602)
    at com.android.org.conscrypt.OpenSSLCipher.engineDoFinal(OpenSSLCipher.java:365)
    at javax.crypto.Cipher.doFinal(Cipher.java:2055)
    at anywheresoftware.b4a.agraham.encryption.CipherWrapper.doFinal(CipherWrapper.java:140)
    at anywheresoftware.b4a.agraham.encryption.CipherWrapper.Decrypt(CipherWrapper.java:150)
    at b4a.example.aesencryption._v5(aesencryption.java:53)
    at ciris.relaties.synchroniseer._decryptcbc(synchroniseer.java:457)
    at ciris.relaties.synchroniseer$ResumableSub_Synchroniseren.resume(synchroniseer.java:819)
    at anywheresoftware.b4a.BA.checkAndRunWaitForEvent(BA.java:267)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:207)
    at anywheresoftware.b4a.keywords.Common$11.run(Common.java:1178)
    at android.os.Handler.handleCallback(Handler.java:883)
    at android.os.Handler.dispatchMessage(Handler.java:100)
    at android.os.Looper.loop(Looper.java:241)
    at android.app.ActivityThread.main(ActivityThread.java:7604)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)

Kind regards,
André
 
Last edited:
Upvote 0

OliverA

Expert
Licensed User
Longtime User
The keysize I use in my C# is based on 256.
Is it possible to use the same size within Android/B4A?
From my research, no. Why? Because your code uses PasswordDeriveBytes. Doing some research on this Class, Java code that emulates this class is good for up to a 20 byte password. Anything above that is an unknown. Why? Even though Microsoft based this class on an encryption standard, that standard is only good for key sizes of up to 20 bytes. In order to accommodate larger key sizes, Microsoft implemented their own algorithm. Unless you have the source for that algorithm, it will be hard to reproduce it in Java. The lesson here is to ensure to use standard compliant encryption methods when hoping to build a cross platform/cross language solution.

Looks like the answer is a maybe. The code I linked below seems to be a Java implementation based on the Mono source (got to love smart/resourceful individuals). You would have to implement it (easiest would be to drop the Java code in a new class and use JavaObject to access the code) and then compare the output of the code with the output of the PasswordDreiveBytes class.

I also tried Keysize of 128 within my C# encryption. I did not succeed in decrypting it from B4A. I think it has something to do with the keysize or blocksize.
No, it has something to do with the PasswordDeriveBytes class. You'll need to implement this class for B4A, be it via the method you found (a link would have been nice) or another method linked below. Once you have something that is equivalent to that class (creating the same key with the same input(s)), you can then test if the other steps are interoperable. It could be that your next snag may be RijndaelManaged. But only testing would tell.

How can I use AES-256: Key 32 Bytes (256 Bits / 8) within Android?
Just use a 32 byte key? Android supports 256 bit encryption.

Links:
 
Last edited:
Upvote 0

AHilberink

Active Member
Licensed User
Longtime User
Thanks to OliverA I found the problem in PasswordDeriveBytes within the C# source. I decide to do not use this methode.

Also I found the problem in Decoding. It seems I did Base64 Encode twice. Once in C# code and once sending it to my server database.

For those how need crossplatform C# - B4A maybe this codes will help. For me it works fine now.

CODE FOR C#:
B4X:
private const string initVector = "alhbcde8qwrtyz27";
private const string passPhrase = "Jaap123456789012";

//Encrypt
        public static string EncryptString(string plainText)
        {
            byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
            byte[] keyBytes = Encoding.UTF8.GetBytes(passPhrase);
            RijndaelManaged symmetricKey = new RijndaelManaged();
            symmetricKey.Mode = CipherMode.CBC;
            symmetricKey.Padding = PaddingMode.PKCS7;
            ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
            MemoryStream memoryStream = new MemoryStream();
            CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
            cryptoStream.FlushFinalBlock();
            byte[] cipherTextBytes = memoryStream.ToArray();
            memoryStream.Close();
            cryptoStream.Close();
            return Convert.ToBase64String(cipherTextBytes);
        }
        //Decrypt
        public static string DecryptString(string cipherText)
        {
            byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
            byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
            byte[] keyBytes = Encoding.UTF8.GetBytes(passPhrase);
            RijndaelManaged symmetricKey = new RijndaelManaged();
            symmetricKey.Mode = CipherMode.CBC;
            symmetricKey.Padding = PaddingMode.PKCS7;
            ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
            MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
            CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
            byte[] plainTextBytes = new byte[cipherTextBytes.Length];
            int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
            memoryStream.Close();
            cryptoStream.Close();
            return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
        }

CODE FOR B4A:
B4X:
Sub Encrypt(enc As String) As String
    Dim Bconv As ByteConverter
    Dim data(0) As Byte
    Dim iv(0) As Byte
    Dim ivstr As String
    Dim Sleutel As String
    Dim c As Cipher
    Dim su As StringUtils
    Dim kg As KeyGenerator

    c.Initialize("AES/CBC/PKCS7Padding")
    ivstr = "alhbcde8qwrtyz27"
    iv = ivstr.GetBytes("UTF8")
    c.InitialisationVector = iv
    Sleutel= "Jaap123456789012"
    kg.Initialize("DES")
    kg.KeyFromBytes(Sleutel.GetBytes("UTF8"))
    
    data = Bconv.StringToBytes(enc, "UTF8")
    data = c.Encrypt(data, kg.Key,True)
    Return su.EncodeBase64(data)
End Sub

Sub Decrypt(enc As String) As String
    Dim Bconv As ByteConverter
    Dim data(0) As Byte
    Dim iv(0) As Byte
    Dim ivstr As String
    Dim Sleutel As String
    Dim c As Cipher
    Dim su As StringUtils
    Dim kg As KeyGenerator

    c.Initialize("AES/CBC/PKCS7Padding")
    ivstr = "alhbcde8qwrtyz27"
    iv = ivstr.GetBytes("UTF8")
    c.InitialisationVector = iv
    Sleutel= "Jaap123456789012"
    kg.Initialize("DES")
    kg.KeyFromBytes(Sleutel.GetBytes("UTF8"))
    
    data = su.DecodeBase64(enc)
    data = c.Decrypt(data, kg.Key, True)
    Return Bconv.StringFromBytes(data, "UTF8")
End Sub

Thanks all for helping me with this thread.

Kind regards,
André
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
For those how need crossplatform C# - B4A maybe this codes will help. For me it works fine now.
Another thing you may look into is B4XEncryption ( https://www.b4x.com/android/forum/threads/b4xencryption.48177/#content ).Another member of the forum (@Chris Lee ) created a .NET version (https://www.b4x.com/android/forum/threads/cross-platform-encryption-with-net.89943/). The benefit of using this is that it uses a salt (It is done internally, managed for you) and works across B4A/i/J
 
Upvote 0
Top