我在将flutter中的加密与我的BE服务中的加密匹配时遇到问题,两个系统中的密钥和iv是相同的,我不知道我在flutter中做错了什么,但它无法解密BE发送的消息服务。这是BE服务中的加密和解密函数。
func EncryptData(data string) (string, error) {
var key = []byte(config.CipherConfig.Key)
var iv = []byte(config.CipherConfig.Iv)
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
ciphertext := make([]byte, aes.BlockSize+len(data))
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], []byte(data))
return hex.EncodeToString(ciphertext[aes.BlockSize:]), nil
}
// Function to decrypt data
func DecryptData(encryptedData string) (string, error) {
var key = []byte(config.CipherConfig.Key)
var iv = []byte(config.CipherConfig.Iv)
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
ciphertext, err := hex.DecodeString(encryptedData)
if err != nil {
return "", err
}
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(ciphertext, ciphertext)
return string(ciphertext), nil
}
这里的flutter部分,我使用了加密包,结果似乎不正确。我不是创建 BE 的人,所以我不完全理解它的作用,我需要在我的 flutter 代码中更改哪些内容才能使结果匹配? (秘钥和iv已经一样了)
static String encrypt(String data) {
final iv = IV.fromUtf8(Env.iv);
final encrypter = Encrypter(AES(Key.fromUtf8(Env.secretKey), mode: AESMode.cfb64));
return encrypter.encrypt(data, iv: iv).base16;
}
static String decrypt(String data) {
final iv = IV.fromUtf8(Env.iv);
final encrypter = Encrypter(AES(Key.fromUtf8(Env.secretKey), mode: AESMode.cfb64));
return encrypter.decrypt16(data, iv: iv);
}
CFB模式需要指定段大小(段大小定义每个加密步骤加密的位数)。 Go 代码使用 128 位,Dart 代码使用 64 位,因此两种代码不兼容。
加密包不允许更改段大小,因此必须替换该库。 加密是PointyCastle库的一些功能的包装。后者支持128位的段大小,因此可以直接使用PointyCastle。
PointyCastle 实现没有考虑到这一点,并且要求明文长度是段大小的整数倍。
要使用
PointyCastle 实现加密 any 长度的明文,必须在加密之前将明文填充到所需的长度,并且必须将生成的密文缩短填充字节数。由于明文长度已知,因此任何填充,例如零填充,可以使用。
在解密过程中,密文必须在解密前填充到所需的长度,并且所得的明文必须缩短填充字节数。
PointyCastle 使用 CFB-128 加密任意长度的明文,并且与 Go 代码兼容:
import 'dart:convert';
import 'dart:typed_data';
import 'package:convert/convert.dart';
import 'package:pointycastle/export.dart';
String encrypt(String plaintext){
var key = utf8.encode("01234567890123456789012345678901"); // for the test only
var iv = utf8.encode("abcdefghijklmnop"); // for the test only
var pt = utf8.encode(plaintext);
var keyParam = KeyParameter(key);
var params = ParametersWithIV(keyParam, iv);
// Zero pad plaintext
var aesBlockSize = 16;
var padLength = (aesBlockSize - (pt.length % aesBlockSize)) % aesBlockSize;
var ptPadded = Uint8List(pt.length + padLength)..setAll(0, pt);
// Encrypt
var cipher = BlockCipher("AES/CFB-128");
cipher.init(true, params);
var ctPadded = Uint8List(ptPadded.length);
for (int offset = 0; offset < ptPadded.length;) {
int len = cipher.processBlock(ptPadded, offset, ctPadded, offset);
offset += len;
}
// Remove padding
var ct = ctPadded.sublist(0, pt.length);
return hex.encode(ct);
}
String decrypt(String ciphertext) {
var key = utf8.encode("01234567890123456789012345678901"); // for the test only
var iv = utf8.encode("abcdefghijklmnop"); // for the test only
var ct = hex.decode(ciphertext);
var keyParam = KeyParameter(key);
var params = ParametersWithIV(keyParam, iv);
// Zero pad ciphertext
var aesBlockSize = 16;
var padLength = (aesBlockSize - (ct.length % aesBlockSize)) % aesBlockSize;
var ctPadded = Uint8List(ct.length + padLength)..setAll(0, ct);
// Decrypt
var cipher = BlockCipher("AES/CFB-128");
cipher.init(false, params);
var ptPadded = Uint8List(ctPadded.length);
for (int offset = 0; offset < ctPadded.length;) {
int len = cipher.processBlock(ctPadded, offset, ptPadded, offset);
offset += len;
}
// Remove padding
var pt = ptPadded.sublist(0, ct.length);
return utf8.decode(pt);
}
由于密钥/IV 对的重用是一个漏洞,因此如果密钥是固定的,则应为每次加密使用随机 IV。 IV 不是秘密的,并且与密文一起传递(通常是串联的)。