I am trying to decrypt the encrypted string from Rijndael VBA code. Java 8 code
public static void Decrypt() throws Exception{
String mydata = "3m/WeZ1cAUEqexeH64gPehkMdQSRvx7K9TKhtpUfEg==";
byte[] encryptedBytes = Base64.getDecoder().decode(mydata);
byte[] key = Base64.getDecoder().decode("VGhpcnR5VHdvQnl0ZXMzJFRoaXJ0eVR3b0J5dGVzMyQ=");
byte[] iv = Base64.getDecoder().decode("MyRUaHJlZVR3b0J5dGVzMzMkVGhyZWVUd29CeXRlczM=");
PaddedBufferedBlockCipher bufferedBlock = new PaddedBufferedBlockCipher(new CBCBlockCipher(new RijndaelEngine(256)), new PKCS7Padding());
CipherParameters keyAndIV = new ParametersWithIV(new KeyParameter(key), iv);
bufferedBlock.init(false, keyAndIV);
byte[] decryptedBytes = new byte[bufferedBlock.getOutputSize(encryptedBytes.length)];
int processed = bufferedBlock.processBytes(encryptedBytes, 0, encryptedBytes.length, decryptedBytes, 0);
processed += bufferedBlock.doFinal(decryptedBytes, processed);
System.out.println(new String(decryptedBytes, 0, processed, StandardCharsets.UTF_8));
}
Above code is giving me an error "last block incomplete in decryption" in line
processed += bufferedBlock.doFinal(decryptedBytes, processed);
This is the VBA Code encryption:
Function Encrypt(plaintext, aesKey)
Dim cipherBytes, aesKeyBytes, ivKeyBytes, plainBytes() As Byte
Dim utf8, AES, aesEnc, cipherMode As Object
Dim aesIV() As Byte
Set AES = CreateObject("System.Security.Cryptography.RijndaelManaged")
Set utf8 = CreateObject("System.Text.UTF8Encoding")
AES.KeySize = 256
AES.BlockSize = 256
'CipherMode.CBC
AES.Mode = 1
'PaddingMode.PKCS7
AES.Padding = 2
AES.Key = utf8.GetBytes_4("ThirtyTwoBytes3$ThirtyTwoBytes3$")
AES.IV = utf8.GetBytes_4("3$ThreeTwoBytes33$ThreeTwoBytes3")
plainBytes = utf8.GetBytes_4(plaintext)
'plainBytes = B64Decode(plaintext)
'Set aesEnc = AES.CreateEncryptor_2((aesKeyBytes), (ivKeyBytes))
cipherBytes = AES.CreateEncryptor().TransformFinalBlock((plainBytes), 0, UBound(plainBytes))
Encrypt = B64Encode(cipherBytes)
End Function
I am trying to encrypt the data sent by VBA and decrypt and use it. Help me in correcting the Java code to match the VBA code VBA AES CBC encryption
The problem is that in both B64Encode()
and encrypt()
the length of the byte array is specified incorrectly with UBound()
(see Fix 1, Fix 2 in the code). UBound()
returns the largest index, so the length is UBound() + 1
. Alternatively LenB()
can be used.
The following VBA code encrypts a plaintext:
Function Min(a, b)
Min = a
If b < a Then Min = b
End Function
Function B64Encode(bytes)
Set b64Enc = CreateObject("System.Security.Cryptography.ToBase64Transform")
Set utf8 = CreateObject("System.Text.UTF8Encoding")
BlockSize = b64Enc.InputBlockSize
For Offset = 0 To LenB(bytes) - 1 Step BlockSize ' LenB(bytes) - 1 --> UBound(bytes)
Length = Min(BlockSize, LenB(bytes) - Offset) ' LenB(bytes) --> UBound(bytes) + 1 Fix 1
b64Block = b64Enc.TransformFinalBlock((bytes), Offset, Length)
result = result & utf8.GetString((b64Block))
Next
B64Encode = result
End Function
Function encrypt(plaintext)
Set AES = CreateObject("System.Security.Cryptography.RijndaelManaged")
Set utf8 = CreateObject("System.Text.UTF8Encoding")
AES.KeySize = 256
AES.BlockSize = 256
AES.Mode = 1 'CipherMode.CBC
AES.Padding = 2 'PaddingMode.PKCS7
AES.Key = utf8.GetBytes_4("ThirtyTwoBytes3$ThirtyTwoBytes3$")
AES.IV = utf8.GetBytes_4("3$ThreeTwoBytes33$ThreeTwoBytes3")
plainBytes = utf8.GetBytes_4(plaintext)
cipherBytes = AES.CreateEncryptor().TransformFinalBlock((plainBytes), 0, LenB(plainBytes)) ' LenB(plainBytes) --> UBound(plainBytes) + 1 Fix 2
encrypt = B64Encode(cipherBytes)
End Function
Sub encryptData()
Debug.Print encrypt("The quick brown fox jumps over the lazy dog") ' 2WVYo0DvgbKXBUn+/eI/yTvUJs0zYxEN9lU5ytxhJRWPDnRn5y4HuwPjaMSg47gTG4dc2ABL5EyIvDg1N91T5A==
End Sub
which can be decrypted with the following Java code (using BouncyCastle):
public static void Decrypt() throws Exception{
String mydata = "2WVYo0DvgbKXBUn+/eI/yTvUJs0zYxEN9lU5ytxhJRWPDnRn5y4HuwPjaMSg47gTG4dc2ABL5EyIvDg1N91T5A==";
byte[] encryptedBytes = Base64.getDecoder().decode(mydata);
byte[] key = "ThirtyTwoBytes3$ThirtyTwoBytes3$".getBytes(StandardCharsets.UTF_8);
byte[] iv = "3$ThreeTwoBytes33$ThreeTwoBytes3".getBytes(StandardCharsets.UTF_8);
//byte[] key = Base64.getDecoder().decode("VGhpcnR5VHdvQnl0ZXMzJFRoaXJ0eVR3b0J5dGVzMyQ="); // works also with Base64 encoded key and IV
//byte[] iv = Base64.getDecoder().decode("MyRUaHJlZVR3b0J5dGVzMzMkVGhyZWVUd29CeXRlczM=");
PaddedBufferedBlockCipher bufferedBlock = new PaddedBufferedBlockCipher(new CBCBlockCipher(new RijndaelEngine(256)), new PKCS7Padding());
CipherParameters keyAndIV = new ParametersWithIV(new KeyParameter(key), iv);
bufferedBlock.init(false, keyAndIV);
byte[] decryptedBytes = new byte[bufferedBlock.getOutputSize(encryptedBytes.length)];
int processed = bufferedBlock.processBytes(encryptedBytes, 0, encryptedBytes.length, decryptedBytes, 0);
processed += bufferedBlock.doFinal(decryptedBytes, processed);
System.out.println(new String(decryptedBytes, 0, processed, StandardCharsets.UTF_8));
}
Please note that the code uses Rijndael with a block size of 256 bytes and therefore no AES. AES is a subset of Rijndael with a block size of 128 bytes. It makes more sense to apply AES, as this is the standard (Rijndael is not).