使用 pointycastle 进行 AES 加密

问题描述 投票:0回答:1

我是密码学领域的新手,我正在尝试在 flutter 中执行 AES 加密和解密功能,我正在使用 pointycastle (而且我不想更改包),问题是当我正在尝试解密

这是代码:

Future<String> aesEncrypt(String plainText, key, iv) async {
    final convertedText = utf8.encode(plainText);
    final keyBytes = base64Decode(key);
    final ivbytes = base64Decode(iv);

    final keyParams = KeyParameter(keyBytes);
    final params = ParametersWithIV(keyParams, ivbytes);

    final cipher = BlockCipher('AES/CBC')..init(true, params);

    final paddedData = _padData(convertedText);
    final encryptedBytes = cipher.process(paddedData);
    return base64Encode(encryptedBytes);
  }

  Future<String> aesDecrypt(String encryptedText, key, iv) async {
    final data = base64Decode(encryptedText);
    
    final keyBytes = base64Decode(key);
    final ivbytes = base64Decode(iv);

    final keyParams = KeyParameter(keyBytes);
    final params = ParametersWithIV(keyParams, ivbytes);

    final cipher = BlockCipher('AES/CBC')..init(false, params);

    final decryptedBytes = cipher.process(data);
    final unpaddedData = _unpadData(decryptedBytes);

    return utf8.decode(unpaddedData);
  }

  Uint8List _padData(Uint8List data) {
    final blockSize = 16;
    final padLength = blockSize - (data.length % blockSize);
    final paddedData = Uint8List(data.length + padLength)..setAll(0, data);
    for (int i = data.length; i < paddedData.length; i++) {
      paddedData[i] = padLength;
    }
    return paddedData;
  }

  Uint8List _unpadData(Uint8List data){
    final padLength = data[data.length - 1];
    return Uint8List.sublistView(data, 0, data.length - padLength);
  }

  String generateKey(){
    final random = math.Random.secure();

    //Generate random key
    final keyBytes = Uint8List(16);
    for(int i = 0; i < keyBytes.length; i++){
      keyBytes[i] = random.nextInt(256);
    }

    return base64Encode(keyBytes);
  }

  String generateIV(){
    final random = math.Random.secure();

    //Generate random key
    final ivBytes = Uint8List(16);
    for(int i = 0; i < ivBytes.length; i++){
      ivBytes[i] = random.nextInt(256);
    }

    return base64Encode(ivBytes);
  }

(保留生成密钥和 iv 功能实际上相同的事实),

错误出现在 _unpadData 函数中的

return Uint8List.sublistView(data, 0, data.length - padLength);

错误是:发生异常。 RangeError (RangeError (end): 无效值: 不在包含范围 0..16: -89)

有人知道为什么会发生这种情况吗?

flutter cryptography pointycastle
1个回答
0
投票

AES/CBC(PKCS#7Padding 使用 PointyCastle 更容易实现(例如支持 PKCS#7 Padding):

import 'dart:typed_data';
import 'package:pointycastle/export.dart';
...
Uint8List crypt(bool isEncrypt, Uint8List data, Uint8List key, Uint8List iv) {
  final params = ParametersWithIV<KeyParameter>(KeyParameter(key), iv);
  final paddingParams = PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null>(params, null);
  final cipher = CBCBlockCipher(AESEngine());
  final paddingCipher = PaddedBlockCipherImpl(PKCS7Padding(), cipher)
    ..init(isEncrypt, paddingParams);
  return paddingCipher.process(data);
}

使用示例:

import 'dart:convert';
...
final key = utf8.encode('01234567890123456789012345678901'); // For the real world: Use a random byte sequence as key or derive the key from a password with a KDF
final iv = utf8.encode('0987654321098765'); // For the real world: generate a random IV for each encryption and pass it with the ciphertext
final plaintext = utf8.encode('The quick brown fox jumps over the lazy dog');
final ciphertext = crypt(true, plaintext, key, iv); // encrypt
final decrypted = crypt(false, ciphertext, key, iv); // decrypt
print(base64Encode(ciphertext)); // viKpiZpMB+dBsLo6RuwKcVanKFyPHfLLxm4PlEWTAHxrPJ43KrA2y67sC6dBFsO4
print(utf8.decode(decrypted)); // The quick brown fox jumps over the lazy dog

请注意,现在应该使用经过身份验证的加密,例如GCM 模式。

此外,为了避免密钥/IV 重用,应为每次加密生成一个随机 IV(并与 IV 一起传递到解密端,通常是串联的)。这对于基于 CTR 的模式(例如 GCM)尤其重要。

© www.soinside.com 2019 - 2024. All rights reserved.