【发布时间】:2022-01-06 21:54:18
【问题描述】:
我有两个函数用 AES-GCM 算法加密和解密数据,但使用 cryptography 包。我不认为它不好,它帮助了我很多,但我想翻译它们,以便我可以使用 pointycastle 包来处理我所有不同的加密和解密算法。
使用加密包的功能有:
Future<CipherDataHolder> cipher(String clearValue) async {
final algorithm = AesGcm.with256bits(nonceLength: 12); //128bits MAC default
final SecretKey secretKey = await algorithm.newSecretKey();
final List<int> nonce = algorithm.newNonce();
final secretBox = await algorithm.encrypt(
utf8.encode(clearValue),
secretKey: secretKey,
nonce: nonce,
);
String cipherText = base64.encode(secretBox.concatenation());
String passphrase = base64.encode(await secretKey.extractBytes());
return CipherDataHolder(ciphertext: cipherText, passphrase: passphrase);
}
Future<String> decrypt(CipherDataHolder secretData) async {
final Uint8List cipherData = base64.decode(secretData.ciphertext);
final Uint8List ciphertext = cipherData.sublist(12, cipherData.length - 16);
final Uint8List iv = cipherData.sublist(0, 12);
final Uint8List mac = cipherData.sublist(cipherData.length - 16);
List<int> passphrase = base64.decode(secretData.passphrase);
final SecretKey secretKey = SecretKey(passphrase);
final SecretBox secretBox = SecretBox(ciphertext, nonce: iv, mac: Mac(mac));
final List<int> clearValue = await AesGcm.with256bits().decrypt(secretBox, secretKey: secretKey);
return utf8.decode(clearValue);
}
CipherDataHolder 只是一个保存值的类
class CipherDataHolder {
CipherDataHolder({required this.ciphertext, required this.passphrase});
String ciphertext;
String passphrase;
}
/////////////////////////////////////// ///////////////////////p>
更新
/////////////////////////////////////// ///////////////////////p>
这是我迄今为止尝试翻译这些函数的方法
使用pointycastle包的功能有:
Future<CipherDataHolder> cipherWithGCMyPointyCastle({required String clearValue}) async {
final Uint8List key = genKey(); //32 bytes key
final Uint8List nonce = generateRandomNonce(); //12 bytes nonce
final List<int> plainTextBytes = utf8.encode(clearValue);
final cipher = pointy.GCMBlockCipher(pointy.AESEngine())
..init(
true, // encrypt
pointy.AEADParameters(
pointy.KeyParameter(key), // the 256 bit (32 byte) key
128, //Mac length
nonce, // the 12 byte nonce
Uint8List(0), // empty extra data
));
//Last 16 is mac data, rest is plaintext Bytes
Uint8List cipherTextBytes = cipher.process(Uint8List.fromList(plainTextBytes));
//Concatenate nonce + cipherText + mac bytes
String cipherText = base64.encode(concatenateCipherData(nonceBytes: cipher.nonce, cipherTextBytes: cipherTextBytes.sublist(0, cipherTextBytes.length - 16), macBytes: cipher.mac));
return CipherDataHolder(ciphertext: cipherText, passphrase: base64.encode(key));
}
Future<String> decryptWithGCMyPointyCastle(CipherDataHolder secretData) async {
final Uint8List cipherData = base64.decode(secretData.ciphertext);
final Uint8List ciphertext = cipherData.sublist(12, cipherData.length - 16); //Rest between 12 and last 16
final Uint8List nonce = cipherData.sublist(0, 12); //First 12 bytes
final Uint8List mac = cipherData.sublist(cipherData.length - 16); //last 16 bytes
List<int> passphrase = base64.decode(secretData.passphrase);
final cipher = pointy.GCMBlockCipher(pointy.AESEngine())
..init(
false, // decrypt
pointy.AEADParameters(
pointy.KeyParameter(Uint8List.fromList(passphrase)),
128,
nonce,
Uint8List(0),
));
BytesBuilder bb = BytesBuilder();
bb.add(ciphertext);
bb.add(mac);
Uint8List ciphertextWithTag = bb.toBytes();
return String.fromCharCodes(cipher.process(ciphertextWithTag));
}
我还是有些疑惑,不知道自己做的对不对。但是密码和解密现在正在工作,当我对数据进行加密时,我使用加密包得到了类似的结果。
现在的主要问题是当我用pointycastle加密时,例如这个值:abc123|@#¢∞¬÷“”≠
密码学结果:abc123|@#¢∞¬÷“”≠
pointycastle 的结果:abc123|@#¢â¬÷âââ
我知道这可能是某种编码问题,但我不知道在哪里 :( 问题出在哪里或我做错了什么?
这些是辅助功能
Uint8List concatenateCipherData({required List<int> nonceBytes, required List<int> cipherTextBytes, required List<int> macBytes}) {
int n = cipherTextBytes.length + nonceBytes.length + macBytes.length;
Uint8List result = Uint8List(n);
int i = 0;
result.setAll(i, nonceBytes);
i += nonceBytes.length;
result.setAll(i, cipherTextBytes);
i += cipherTextBytes.length;
result.setAll(i, macBytes);
return result;
}
Uint8List generateRandomNonce() {
final _sGen = Random.secure();
final _seed = Uint8List.fromList(List.generate(32, (n) => _sGen.nextInt(256)));
pointy.SecureRandom sec = pointy.SecureRandom("Fortuna")..seed(pointy.KeyParameter(_seed));
return sec.nextBytes(12);
}
Uint8List genKey() {
final _sGen = Random.secure();
final _seed = Uint8List.fromList(List.generate(32, (n) => _sGen.nextInt(256)));
pointy.SecureRandom sec = pointy.SecureRandom("Fortuna")..seed(pointy.KeyParameter(_seed));
return sec.nextBytes(32);
}
【问题讨论】:
-
这不是一个问题,这是一个作业——你的作业。
-
@MaartenBodewes 添加了调试细节,抱歉
-
你似乎越来越近了。由于这个问题已经结束,我建议你问一个有确切问题的新问题。一些建议:(1)你如何生成种子通常对于随机数来说已经足够好了——不需要使用 fortuna。 (2) 在
nextInt中将255替换为256(3) 如果您确实使用了fortuna - 只需制作一个pc.SecureRandom并重复使用它 (4) 进行调试,使用固定密钥和随机数,例如0,0,0,0,.....0,0,0 和 1,1,1,1,1,1,1,1,1,1,1,1 并比较加密的结果 -两种方法都给出相同的结果吗? -
和(6)我相信这是颠倒过来的//前16个是mac数据,其余是明文字节密文的后16个字节大概是mac。跨度>
-
“密码短语似乎只是原始代码中随机密钥的 base 64 编码。我想知道您是否应该删除密文末尾的 16 个字节。这通常是为 MAC 保留的,但这似乎是单独生成的。
标签: flutter security encryption aes-gcm pointycastle