gpt4 book ai didi

php - Flutter/Dart AES-256-CBC 从 PHP 加密解密

转载 作者:行者123 更新时间:2023-12-04 14:10:26 25 4
gpt4 key购买 nike

谁能帮我找出使用 AES-256-CBC 在 PHP 中加密的数据的解密算法。我尝试了很多不同的方法,但我认为我在尝试复制在 Dart 中重新创建它们的 Key/IV 的方法时搞砸了,并不断收到异常,例如:

RangeError (end): Invalid value: Not in inclusive range 0..16:
进行加密的PHP代码(由于加密字符串由第三方提供,因此无法更改)如下:
function encrypt( $string, $encrypt=true) {
$secret_key = 'SuperSecretKey';
$secret_iv = 'SuperSecretBLOCK';
$output = false;
$encrypt_method = "AES-256-CBC";
$key = hash( 'sha256', $secret_key );
$iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );
if($encrypt) {
$output = base64_encode( openssl_encrypt( $string, $encrypt_method, $key, 0, $iv ) );
} else {
$output = openssl_decrypt( base64_decode( $string ), $encrypt_method, $key, 0, $iv );
}
return $output;
}
例如,如果调用 PHP 中的加密例程来加密字符串“This is a Test!”,结果将是:
ZHArWURDY2FkelBtSGY5c1AzdTNBZz09
正是这个结果,我试图在 Dart 中解密,但没有任何运气!
这是我到目前为止导致上述异常的原因:
import 'package:encrypt/encrypt.dart';
import 'package:crypto/crypto.dart';
import 'dart:convert' show utf8;

String extractPayload(String payload) {
String strPwd = 'SuperSecretKey';
String strIv = 'SuperSecretBLOCK';
var iv = sha256.convert(utf8.encode(strIv));
var key = sha256.convert(utf8.encode(strPwd));
IV ivObj = IV.fromUtf8(iv.toString());
Key keyObj = Key.fromUtf8(key.toString());
final encrypter = Encrypter(AES(keyObj));
final decrypted = encrypter.decrypt(Encrypted.from64(payload), iv: ivObj);
print(decrypted);
return decrypted;
}
欢迎任何建议,
谢谢

最佳答案

PHP 代码有许多不必要的弱点,使移植变得复杂:

  • 散列时,结果以十六进制编码的字符串形式返回,不幸的是,这是 hash 的默认值。功能。将结果作为二进制数据返回会更有意义(但为此,必须将第三个参数显式设置为 TRUE )。在这种情况下,作为十六进制字符串返回有两个缺点:
  • 由于每个字节用两个字符表示,所以SHA256的32字节hash用64个字符表示,也就是64个字节。这被用作 AES-256 key (因为在实现过程中可能错误地假设了二进制数据),导致无效的 key ,因为 AES-256 key 的大小正好是 32 个字节。 PHP 通过截断太长的键(太短的键用 0 值填充)来解决这个问题,即只使用前 32 个字节作为键。关于跨平台实现,在 key 无效的情况下显示错误消息会更有用,而不是应用任意和不透明规则 secret 生成有效 key 。
  • 对于十六进制字符串,数字 (a-f) 可以使用大写或小写字母,具体取决于平台。如果是跨平台实现的情况,则会生成不同的 key 。这里这并不重要,因为 PHP 和 Dart 使用小写字母。
  • openssl_encrypt Base64默认对密文进行编码, openssl_decrypt 默认情况下需要 Base64 编码的密文。这可以通过标志 OPENSSL_RAW_DATA 禁用。 ,但在当前代码中并非如此。同时密文在加密时是显式Base64编码的,所以是双Base64编码。类似地,在解密密文时,它是显式 Base64 解码的,因此它也是双 Base64 解码。这种冗余是没有意义的,只会不必要地膨胀密文并降低性能。

  • 此外,Dart 代码采用了错误的默认值:加密包使用 SIC(或 CTR)作为默认模式。由于 CBC 是在 PHP 代码中指定的,因此必须在 Dart 代码中明确指定此模式。
    以下 Dart 实现解密密文 ZHArWURDY2FkelBtSGY5c1AzdTNBZz09:
    import 'package:encrypt/encrypt.dart' as EncryptPack;
    import 'package:crypto/crypto.dart' as CryptoPack;
    import 'dart:convert' as ConvertPack;

    String extractPayload(String payload) {
    String strPwd = "SuperSecretKey";
    String strIv = 'SuperSecretBLOCK';
    var iv = CryptoPack.sha256.convert(ConvertPack.utf8.encode(strIv)).toString().substring(0, 16); // Consider the first 16 bytes of all 64 bytes
    var key = CryptoPack.sha256.convert(ConvertPack.utf8.encode(strPwd)).toString().substring(0, 32); // Consider the first 32 bytes of all 64 bytes
    EncryptPack.IV ivObj = EncryptPack.IV.fromUtf8(iv);
    EncryptPack.Key keyObj = EncryptPack.Key.fromUtf8(key);
    final encrypter = EncryptPack.Encrypter(EncryptPack.AES(keyObj, mode: EncryptPack.AESMode.cbc)); // Apply CBC mode
    String firstBase64Decoding = new String.fromCharCodes(ConvertPack.base64.decode(payload)); // First Base64 decoding
    final decrypted = encrypter.decrypt(EncryptPack.Encrypted.fromBase64(firstBase64Decoding), iv: ivObj); // Second Base64 decoding (during decryption)
    return decrypted;
    }
    下面的测试返回明文 这是一个测试!
    String plaintext = extractPayload("ZHArWURDY2FkelBtSGY5c1AzdTNBZz09");
    print(plaintext); // This is a Test!

    关于php - Flutter/Dart AES-256-CBC 从 PHP 加密解密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64933327/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com