У меня есть NestJS API, который шифрует и расшифровывает строку со следующим кодом.
export const encryptIV = async (data:string)=>{
try{
const iv = Buffer.from('q2Q@w3W#').toString('hex');
const secretKey = 'H4WtkvK4qyehIe2kjQfH7we1xIHFK67e';
const key = (await promisify(scrypt)(secretKey, 'salt', 32)) as Buffer;
const cipher = createCipheriv(alg, key, iv);
let encryptedText = cipher.update(data,'utf-8','hex');
encryptedText += cipher.final('hex');
return `${encryptedText}`;
} catch (e){
return '';
}
}
export const decryptIV = async (data:string)=>{
try{
if (data.length>0){
const iv = Buffer.from('q2Q@w3W#').toString('hex');
const secretKey = 'H4WtkvK4qyehIe2kjQfH7we1xIHFK67e';
const key = (await promisify(scrypt)(secretKey, 'salt', 32)) as Buffer;
const decipher = createDecipheriv(alg, key, iv);
let decryptedText = decipher.update(data,'hex','utf-8');
decryptedText += decipher.final('utf-8');
return decryptedText;
} else {
return '';
}
} catch (e){
return '';
}
}
Расшифровка в JS:
IV = "7132514077335723"
SecretKey = "H4WtkvK4qyehIe2kjQfH7we1xIHFK67e"
EncryptedData = "222ef6e4c66c3dfdea9cf1f4828f436e"
AfterDecryption = "28c9c0e555b71fda"
ALG = "aes-256-ctr"
Я пытаюсь расшифровать свои зашифрованные данные в dart, используя пакет «encrypt: ^ 5.0.3» со следующим кодом:
void decrypt() {
try{
final hexIv = "222ef6e4c66c3dfdea9cf1f4828f436e";
final ivHexIv = enc.IV.fromUtf8("7132514077335723");
final ivKey = enc.Key.fromUtf8('H4WtkvK4qyehIe2kjQfH7we1xIHFK67e');
final enc.Encrypter encrypterIv = enc.Encrypter(enc.AES(ivKey,mode: enc.AESMode.ctr));
final String decrypted =encrypterIv.decrypt64(hexIv, iv: ivHexIv);
setState(() {
text=decrypted;
});
} catch (e){
debugPrint(e.toString());
}
}
В этом коде я получаю сообщение об ошибке «Длина входных данных должна быть кратна размеру блока шифра».
В коде Dart есть три ошибки:
Получение ключа с помощью сценария, используемого в коде NodeJS, отсутствует.
Пакет шифрования не поддерживает scrypt. Одним из возможных пакетов Dart, предоставляющих scrypt, является пакет pointycastle.
Обратите внимание, что пакет шифрования — это всего лишь оболочка pointycastle, поэтому, вероятно, имеет смысл вообще исключить пакет шифрования и использовать вместо него непосредственно пакет pointycastle.
В коде NodeJS используются значения по умолчанию для стоимости (N: 16384), размера блока (r: 8) и распараллеливания (p: 1), см. crypto.scrypt(). Эти значения также необходимо применять в коде Dart.
Отключение заполнения по умолчанию PKCS#7 отсутствует. В отличие от криптомодуля NodeJS, пакет шифрования не отключает автоматически заполнение для режимов потокового шифрования, таких как CTR.
Зашифрованный текст должен быть декодирован в шестнадцатеричном формате, а не в формате Base64.
Возможное исправление:
import 'dart:convert';
import 'package:encrypt/encrypt.dart' as enc;
import 'package:pointycastle/export.dart';
...
final hexIv = "222ef6e4c66c3dfdea9cf1f4828f436e";
final ivHexIv = enc.IV.fromUtf8("7132514077335723");
final scryptParams = ScryptParameters(16384, 8, 1, 32, utf8.encode('salt')); // Fix 1: apply scrypt KDF
final scrypt = KeyDerivator('scrypt')..init(scryptParams);
final rawKey = scrypt.process(utf8.encode('H4WtkvK4qyehIe2kjQfH7we1xIHFK67e'));
final ivKey = enc.Key(rawKey);
final enc.Encrypter encrypterIv = enc.Encrypter(enc.AES(ivKey,mode: enc.AESMode.ctr, padding: null)); // Fix 2: disable padding
final String decrypted = encrypterIv.decrypt16(hexIv, iv: ivHexIv); // Fix 3: hex decode
print("Decrypted:" + decrypted); // Decrypted:28c9c0e555b71fda