首页 > 解决方案 > Java 中的加密和 Flutter 中的解密 (AES-256)

问题描述

我正在尝试在我的代码中实现加密,我使用 java 作为移动应用程序的后端和 dart,但我无法在颤动中解密代码。

这是用于加密的 java 代码 此 java 代码取自此博客

    public void encrypt(String item) throws Exception {
    byte[] ivBytes;
    String password="Hello";
    /*you can give whatever you want for password. This is for testing purpose*/
    SecureRandom random = new SecureRandom();
    byte bytes[] = new byte[20];
    random.nextBytes(bytes);
    byte[] saltBytes = bytes;
    // Derive the key
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(),saltBytes,65556,256);

    SecretKey secretKey = factory.generateSecret(spec);
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

    System.out.println("saltBytes : " + saltBytes);


    //encrypting the word
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secret);
    AlgorithmParameters params = cipher.getParameters();
    ivBytes =   params.getParameterSpec(IvParameterSpec.class).getIV();
    System.out.println("ivBytes : " + ivBytes);

    byte[] encryptedTextBytes = cipher.doFinal(item.getBytes("UTF-8"));
    //prepend salt and vi
    byte[] buffer = new byte[saltBytes.length + ivBytes.length + encryptedTextBytes.length];
    System.arraycopy(saltBytes, 0, buffer, 0, saltBytes.length);
    System.arraycopy(ivBytes, 0, buffer, saltBytes.length, ivBytes.length);
    System.arraycopy(encryptedTextBytes, 0, buffer, saltBytes.length + ivBytes.length, encryptedTextBytes.length);
    String val =   new Base64().encodeToString(buffer);
    System.out.println(val);


}

现在在 dart 中,我使用了多个插件,但无法解密 dart 中的代码。对于 dart 解密,我从这个stackoverflow 讨论中获取了代码。
Dart 的实现是这样的

  static Uint8List decrypt(String ciphertext,) {
Uint8List ciphertextlist = base64.decode(ciphertext);
print('ciphertextlist => $ciphertextlist');
Uint8List key = generateKey("Hello");
print('key => $key');
CBCBlockCipher cipher = new CBCBlockCipher(new AESFastEngine());

int iv = cipher.blockSize;
Uint8List ivIntList = Uint8List.fromList(iv.toString().codeUnits);

ParametersWithIV<KeyParameter> params =
    new ParametersWithIV<KeyParameter>(new KeyParameter(key), ivIntList);
PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null>
    paddingParams =
    new PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null>(
        params, null);
PaddedBlockCipherImpl paddingCipher =
    new PaddedBlockCipherImpl(new PKCS7Padding(), cipher);
paddingCipher.init(false, paddingParams);
var val = paddingCipher.process(ciphertextlist);
print('val => $val');}
  


static Uint8List generateKey(String passphrase) {
Uint8List passphraseInt8List = Uint8List.fromList(passphrase.codeUnits);
Uint8List salt = Uint8List.fromList('20'.codeUnits);

KeyDerivator derivator = PBKDF2KeyDerivator(HMac(SHA1Digest(), 16));
Pbkdf2Parameters params = Pbkdf2Parameters(salt, 65556, 256);
derivator.init(params);
return derivator.process(passphraseInt8List);

运行代码后,我收到此错误。

Invalid argument(s): Initialization vector must be the same length as block size

标签: javaflutterdartencryptionaes

解决方案


Dart 代码缺少盐、IV 和密文的分离。添加decrypt()

var salt = ciphertextlist.sublist(0, 20);
var iv = ciphertextlist.sublist(20, 20 + 16);
var encrypted = ciphertextlist.sublist(20 + 16);

必须将盐传递给generateKey()并在那里使用以派生密钥,iv 和密文应用如下:

Uint8List key = generateKey("Hello", salt);
...
//int iv = cipher.blockSize;
//Uint8List ivIntList = Uint8List.fromList(iv.toString().codeUnits);
ParametersWithIV<KeyParameter> params = new ParametersWithIV<KeyParameter>(new KeyParameter(key), iv);
...
var val = paddingCipher.process(encrypted);
...
String decrypted = new String.fromCharCodes(val);
print(decrypted);

generateKey()必须考虑传递的盐,而且摘要块大小和密钥大小不正确,因此需要进行以下更改:

static Uint8List generateKey(String passphrase, Uint8List salt) {           // pass salt
  Uint8List passphraseInt8List = Uint8List.fromList(passphrase.codeUnits);
  //Uint8List salt = Uint8List.fromList('20'.codeUnits);
  KeyDerivator derivator = PBKDF2KeyDerivator(HMac(SHA1Digest(), 64));      // 64 byte block size
  Pbkdf2Parameters params = Pbkdf2Parameters(salt, 65556, 32);              // 32 byte key size
  derivator.init(params);
  return derivator.process(passphraseInt8List);
}

通过这些更改,解密可以在我的机器上运行。


推荐阅读