Flutter实现与PHP一致的AES-256-CBC加解密功能报错求助
问题:Flutter实现PHP AES-256-CBC加解密时出现IV长度错误
问题背景
现有PHP的AES-256-CBC加解密函数,在Flutter中实现对应逻辑时触发错误:
E/flutter ( 9703): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Invalid argument(s): Initialization vector must be the same length as block size
PHP原函数
public static function encrypt_decrypt($action, $string) { $output = false; $encrypt_method = "AES-256-CBC"; $secret_key = 'R4haSIA'; $secret_iv = 'r$h4sia'; $key = hash('sha256', $secret_key); $iv = substr(hash('sha256', $secret_iv), 0, 16); if ($action == 'encrypt') { $output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv); $output = base64_encode($output); } else if ($action == 'decrypt') { $output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv); } return $output; }
原Flutter代码(报错版本)
String encryptPassword(String password) { final key = encrypt.Key.fromUtf8('R4haSIA'); final iv = encrypt.IV.fromUtf8('r\$h4sia12345678'); // Panjang IV 16 byte final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc)); final encrypted = encrypter.encrypt(password, iv: iv); return encrypted.base64; } Future<void> _login() async { var url = Uri.parse("http://10.0.2.2/config/db/login.php"); var pass_enkripsi = encryptPassword(passwordController.text); var response = await http.post(url, body: { "username": usernameController.text, "password": pass_enkripsi, }); var datauser = jsonDecode(response.body); if (datauser != '') { print('Login Success'); Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => const homepage()), ); } else { print('Login failed'); } }
问题根源
Flutter代码和PHP逻辑存在两处关键不一致:
- 密钥生成错误:PHP对
secret_key做SHA256哈希后作为AES-256密钥(SHA256输出32字节,刚好符合AES-256要求),但Flutter直接用原始7字节字符串作为密钥,长度不足且逻辑不符。 - IV生成错误:PHP对
secret_iv做SHA256哈希后取前16字节作为IV,而Flutter手动拼接字符串凑16字节,生成逻辑完全不同,且这种方式不符合PHP的处理逻辑。
修正后的Flutter代码
需要先在pubspec.yaml中添加依赖:
dependencies: crypto: ^3.0.3 encrypt: ^5.0.1
然后使用以下修正后的代码,确保和PHP逻辑完全对齐:
import 'dart:convert'; import 'package:crypto/crypto.dart'; import 'package:encrypt/encrypt.dart'; // 加密函数,和PHP逻辑完全一致 String encryptPassword(String password) { final secretKey = 'R4haSIA'; final secretIv = 'r\$h4sia'; // 生成密钥:对secretKey做SHA256哈希,取32字节(SHA256输出刚好32字节) final keyBytes = sha256.convert(utf8.encode(secretKey)).bytes; final key = encrypt.Key(keyBytes); // 生成IV:对secretIv做SHA256哈希,取前16字节 final ivHash = sha256.convert(utf8.encode(secretIv)).toString(); final ivBytes = utf8.encode(ivHash.substring(0, 16)); final iv = encrypt.IV(ivBytes); final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc)); // PHP中openssl_encrypt默认使用PKCS7填充,和encrypt包默认一致 final encrypted = encrypter.encrypt(password, iv: iv); return encrypted.base64; } // 可选:对应的解密函数,和PHP decrypt逻辑一致 String decryptPassword(String encryptedPassword) { final secretKey = 'R4haSIA'; final secretIv = 'r\$h4sia'; final keyBytes = sha256.convert(utf8.encode(secretKey)).bytes; final key = encrypt.Key(keyBytes); final ivHash = sha256.convert(utf8.encode(secretIv)).toString(); final ivBytes = utf8.encode(ivHash.substring(0, 16)); final iv = encrypt.IV(ivBytes); final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc)); final decrypted = encrypter.decrypt64(encryptedPassword, iv: iv); return decrypted; } Future<void> _login() async { var url = Uri.parse("http://10.0.2.2/config/db/login.php"); var pass_enkripsi = encryptPassword(passwordController.text); var response = await http.post(url, body: { "username": usernameController.text, "password": pass_enkripsi, }); var datauser = jsonDecode(response.body); if (datauser != '') { print('Login Success'); Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => const homepage()), ); } else { print('Login failed'); } }
关键说明
- 使用
crypto包处理SHA256哈希,确保和PHP的hash('sha256', ...)逻辑完全一致。 - AES-256要求32字节密钥,SHA256哈希刚好输出32字节,直接使用即可。
- AES-CBC的IV必须是16字节,严格按照PHP逻辑对
secret_iv哈希后取前16字节生成。 encrypt包默认使用PKCS7填充,和PHP的openssl_encrypt默认填充方式一致,无需额外配置。
内容的提问来源于stack exchange,提问作者M. Ibnu Wildan
相关产品推荐
相关产品推荐

