0

我正在尝试使用 AES CBC 加密和 Python 中的 PKCS7 填充来加密一些文本,然后在 Dart (Flutter) 中对其进行解密。事实证明,package:pointycastle/paddings/pkcs7.dart当加密文本不需要填充时会引发错误。

这是示例。在这里,我们对一些需要在 Python 中填充的文本进行编码。

import base64
import hashlib
from Crypto.Cipher import AES
from pkcs7 import PKCS7Encoder

secret_text = 'Text that requires padding'

key_text = "some_key"
key = hashlib.sha256(key_text.encode()).digest()
print('key: ', list(key))

iv = hashlib.md5("some_iv_text".encode('utf-8')).digest()
print('iv: ', list(iv))

encoder = PKCS7Encoder()
padded_text = encoder.encode(secret_text)
print('Padded text: ', padded_text.encode('utf-8'))

e = AES.new(key, AES.MODE_CBC, iv)
cipher_text = e.encrypt(padded_text.encode('utf-8'))

print(base64.b64encode(cipher_text).decode('utf-8'))

输出:

key:  [149, 37, 31, 220, 159, 221, 63, 146, 231, 174, 209, 65, 254, 127, 208, 107, 42, 235, 157, 237, 182, 247, 172, 8, 231, 217, 186, 188, 126, 137, 139, 73]
iv:  [205, 35, 149, 118, 23, 255, 66, 222, 206, 81, 138, 188, 169, 122, 96, 164]
Padded text:  b'Text that requires padding\x06\x06\x06\x06\x06\x06'
PygLEjc1Kkjm5qtt5N9vHC0E7TAYVj4xLpsfa4cLiRs=

Process finished with exit code 0

接下来,我们在 Dart 中对其进行解密。

import 'dart:typed_data';
import 'package:encrypt/encrypt.dart';
import 'dart:convert';
import 'package:crypto/crypto.dart';

void main() {
  String encryptedText = 'PygLEjc1Kkjm5qtt5N9vHC0E7TAYVj4xLpsfa4cLiRs=';

  List<int> key_text = utf8.encode("some_key"); // data being hashed
  List<int> key_bytes = sha256.convert(key_text).bytes;

  final key = Key(Uint8List.fromList(key_bytes));

  print('key: $key_bytes');

  Encrypter encrypter =
      Encrypter(AES(key, mode: AESMode.cbc, padding: 'PKCS7'));

  String iv_text = 'some_iv_text';

  Uint8List encrypted = Uint8List.fromList(base64.decode(encryptedText));

  final iv_bytes = md5.convert(utf8.encode(iv_text)).bytes;
  IV iv = IV(Uint8List.fromList(iv_bytes));

  print('iv: $iv_bytes');

  String decrypted = encrypter.decrypt(Encrypted(encrypted), iv: iv);
  print(decrypted);
}

输出:

key: [149, 37, 31, 220, 159, 221, 63, 146, 231, 174, 209, 65, 254, 127, 208, 107, 42, 235, 157, 237, 182, 247, 172, 8, 231, 217, 186, 188, 126, 137, 139, 73]
iv: [205, 35, 149, 118, 23, 255, 66, 222, 206, 81, 138, 188, 169, 122, 96, 164]
Text that requires padding

Process finished with exit code 0

所以,一切正常。

让我们对不需要填充的文本做同样的事情。

import base64
import hashlib
from Crypto.Cipher import AES
from pkcs7 import PKCS7Encoder

secret_text = 'Text that does not require padding..............'

key_text = "some_key"
key = hashlib.sha256(key_text.encode()).digest()
print('key: ', list(key))

iv = hashlib.md5("some_iv_text".encode('utf-8')).digest()
print('iv: ', list(iv))

encoder = PKCS7Encoder()
padded_text = encoder.encode(secret_text)
print('Padded text: ', padded_text.encode('utf-8'))

e = AES.new(key, AES.MODE_CBC, iv)
cipher_text = e.encrypt(padded_text.encode('utf-8'))

print(base64.b64encode(cipher_text).decode('utf-8'))

输出:

key:  [149, 37, 31, 220, 159, 221, 63, 146, 231, 174, 209, 65, 254, 127, 208, 107, 42, 235, 157, 237, 182, 247, 172, 8, 231, 217, 186, 188, 126, 137, 139, 73]
iv:  [205, 35, 149, 118, 23, 255, 66, 222, 206, 81, 138, 188, 169, 122, 96, 164]
Padded text:  b'Text that does not require padding..............'
W2Drr/UfPBTNG4fVPG0Lb/Ax3GAyvjNNx9BlrJcxc2RTNcf2BxT2lyIx1l2ktOYl

Process finished with exit code 0

使用相同的代码在 Dart 中解密:

import 'dart:typed_data';
import 'package:encrypt/encrypt.dart';
import 'dart:convert';
import 'package:crypto/crypto.dart';

void main() {
  String encryptedText = 'W2Drr/UfPBTNG4fVPG0Lb/Ax3GAyvjNNx9BlrJcxc2RTNcf2BxT2lyIx1l2ktOYl';

  List<int> key_text = utf8.encode("some_key"); // data being hashed
  List<int> key_bytes = sha256.convert(key_text).bytes;

  final key = Key(Uint8List.fromList(key_bytes));

  print('key: $key_bytes');

  Encrypter encrypter =
      Encrypter(AES(key, mode: AESMode.cbc, padding: 'PKCS7'));

  String iv_text = 'some_iv_text';

  Uint8List encrypted = Uint8List.fromList(base64.decode(encryptedText));

  final iv_bytes = md5.convert(utf8.encode(iv_text)).bytes;
  IV iv = IV(Uint8List.fromList(iv_bytes));

  print('iv: $iv_bytes');

  String decrypted = encrypter.decrypt(Encrypted(encrypted), iv: iv);
  print(decrypted);
}

输出:

key: [149, 37, 31, 220, 159, 221, 63, 146, 231, 174, 209, 65, 254, 127, 208, 107, 42, 235, 157, 237, 182, 247, 172, 8, 231, 217, 186, 188, 126, 137, 139, 73]
Unhandled exception:
Invalid argument(s): Invalid or corrupted pad block
#0      PKCS7Padding.padCount (package:pointycastle/paddings/pkcs7.dart:42:7)
#1      PaddedBlockCipherImpl.doFinal (package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart:112:30)
#2      PaddedBlockCipherImpl.process (package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart:74:25)
#3      AES.decrypt (package:encrypt/src/algorithms/aes.dart:63:22)
#4      Encrypter.decryptBytes (package:encrypt/src/encrypter.dart:25:17)
#5      Encrypter.decrypt (package:encrypt/src/encrypter.dart:31:17)
#6      main (package:zno_ua_mova/decypher_bug_reproduce.dart:28:32)
#7      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19)
#8      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)
iv: [205, 35, 149, 118, 23, 255, 66, 222, 206, 81, 138, 188, 169, 122, 96, 164]

Process finished with exit code 255

原来异常是由这个代码块抛出的package:pointycastle/paddings/pkcs7.dart:42:7

if (count > data.length || count == 0) {
  throw ArgumentError('Invalid or corrupted pad block');
}

当解密工作(第一种情况)时,变量是:

count: 6
data.length: 16

当解密不起作用时(第二种情况),变量是:

count: 46
data.length: 16

pointycastle pkcs7 库有什么问题吗,还是我以错误的方式使用它?

4

1 回答 1

0

好的,问题出在 Python pkcs7 库中。它的实现不遵循 PKCS7 RFC,并且当其长度 mod blocksize 等于 0 时,不会将填充字节添加到字符串中。Github 问题已经存在

于 2022-02-10T15:40:20.697 回答