I have been trying to convert an AES
decryption function from Java
to Dart
.
It uses AES
with, IV and salt. No padding operations are performed.
This is the Java code:
public byte[] Decrypt(byte[] Data, String Password) throws InvalidKeyException, InvalidAlgorithmParameterException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
byte[] salt = new byte[8];
byte[] iv = new byte[16];
System.arraycopy(Data, 0, salt, 0, 8);
System.arraycopy(Data, 8 , iv, 0, 16);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec =
new PBEKeySpec(Password.toCharArray(),salt, 1024, 128);
SecretKey tmp = factory.generateSecret(keySpec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher d = Cipher.getInstance("AES/CBC/PKCS5Padding");
d.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
byte[] t = new byte[Data.length - 24];
System.arraycopy(Data, 24, t, 0, t.length);
return d.doFinal(t);
}
and this is my Dart attempt:
static Uint8List? decrypt(String ciphertext, String password) {
Uint8List rawCipher = base64.decode(ciphertext);
var salt = rawCipher.sublist(0, 0 + 8);
var iv = rawCipher.sublist(8, 8 + 16);
var encrypted = rawCipher.sublist(8 + 16);
Uint8List key = generateKey(password, salt);
print('key => $key');
CBCBlockCipher cipher = CBCBlockCipher(AESEngine());
ParametersWithIV<KeyParameter> params =
ParametersWithIV<KeyParameter>(KeyParameter(key), iv);
PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null>
paddingParams =
PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null>(
params, null);
PaddedBlockCipherImpl paddingCipher =
PaddedBlockCipherImpl(PKCS7Padding(), cipher);
paddingCipher.init(false, paddingParams);
var val = paddingCipher.process(encrypted);
String res = String.fromCharCodes(val);
print('res => $res');
return val;
}
static Uint8List generateKey(String passphrase, Uint8List salt) {
Uint8List passphraseInt8List = Uint8List.fromList(passphrase.codeUnits);
KeyDerivator derivator = PBKDF2KeyDerivator(HMac(SHA1Digest(), 32));
Pbkdf2Parameters params = Pbkdf2Parameters(salt, 1024, 16);
derivator.init(params);
return derivator.process(passphraseInt8List);
}
base64 encrypted string :
7MT6+nT/grYuh6vAwMGtt/2YXddNbdPY2uijM3HrHQ4q5Iv8Q8zm2emMuuXtaMdHHDId23hNYdrs
rhK2pUXfvRE7S/evuQa2UwjV9PsSMicSFxT8LZgOYsjL73zGuUGGhCTqk3NwtXGSzNsPMMAMsjOO
bbrl5N42TAouLvsaOmiMqjDYPItE3l0GfVYtdIf3vDN5hc7wUDI0Kq4WuXLDaSEK1IyO90KY4+LC
fc/9hwRv1iW96UK71wEYeWL1UV6ij3ACRNTR4uM=
password:
fafafafa
The Dart
code produces an exception:
Unhandled exception:
Invalid argument(s): Invalid or corrupted pad block
,which I suspect happens because in the Dart
code, I make use of PKCS7Padding
while in my code there is not padding performed on the data.
I am a bit lost, I couldn't find a way to process the data while using salt
without unpadding.
If I skip the PaddedBlockCipherImpl
and plain call
CBCBlockCipher cipher = CBCBlockCipher(AESEngine());
ParametersWithIV<KeyParameter> params =
ParametersWithIV<KeyParameter>(KeyParameter(key), iv);
cipher.init(false, params);
var val = cipher.process(encrypted);
String res = String.fromCharCodes(val);
print('res => $res');
I get garbage values.
You are using the wrong block size in the HMAC - it should be 64 bytes. Change generateKey
to this:
Uint8List generateKey(String passphrase, Uint8List salt) {
final derivator = PBKDF2KeyDerivator(HMac(SHA1Digest(), 64))
..init(Pbkdf2Parameters(salt, 1024, 16));
return derivator.process(utf8.encode(passphrase) as Uint8List);
}
It's tidier to create the cipher in a few lines like this:
final cipher = PaddedBlockCipherImpl(
PKCS7Padding(),
CBCBlockCipher(AESEngine()),
)..init(
false,
PaddedBlockCipherParameters(
ParametersWithIV(KeyParameter(key), iv),
null,
),
);
final pt = cipher.process(encrypted);