Django中用Fernet加密,PHP解密失败问题求助
PHP解密Django Fernet加密值失败的解决方法
问题描述
尝试在PHP中解密Django用Fernet加密的数据库值时,触发报错:
Decryption failed: error:0606508A:digital envelope routines:EVP_DecryptFinal_ex:data not multiple of block length
使用的代码如下:
$encryption_key = Using same key from django; $ekyc = Wallet::find('1'); $value= $ekyc->address; $decodedData = base64_decode(strtr($value, '-_', '+/')); echo "Decoded Data: " . bin2hex($decodedData) . "<br>"; // Extract the initialization vector (IV) and ciphertext $ivSize = openssl_cipher_iv_length('aes-128-cbc'); $iv = substr($decodedData, 0, $ivSize); $ciphertext = substr($decodedData, $ivSize); echo "IV: " . bin2hex($iv) . "<br>"; // Replace 'aes-128-cbc' with the appropriate cipher and mode if needed $decrypted_data = openssl_decrypt($ciphertext, 'aes-128-cbc', $encryption_key, OPENSSL_RAW_DATA, $iv); if ($decrypted_data === false) { die('Decryption failed: ' . openssl_error_string()); } dd($decrypted_data);
问题原因
你的代码未遵循Fernet的规范格式,导致核心参数解析错误:
- Fernet结构解析错误:Fernet二进制格式为
版本号(1字节) + 时间戳(8字节) + IV(16字节) + 密文 + HMAC(32字节),你直接从开头截取IV,会把版本号、时间戳混入IV,导致IV无效,密文位置错位。 - 密钥处理错误:Django的Fernet密钥是base64url编码的32字节数据,需解码后拆分出前16字节的AES密钥和后16字节的HMAC密钥,直接使用原始密钥字符串会导致加密密钥不匹配。
- 密文包含冗余数据:你截取的
ciphertext包含了HMAC校验部分,这部分不属于AES解密的有效内容,会导致密文长度不符合AES块大小要求,触发报错。
解决方法
按照Fernet规范正确解析数据、处理密钥,可选添加HMAC验证确保数据完整性:
完整可运行代码
// 替换为你的Django Fernet密钥 $fernetKey = "your-django-fernet-key-here"; $ekyc = Wallet::find('1'); $encryptedValue = $ekyc->address; // 1. 处理Fernet密钥:解码并拆分AES和HMAC密钥 $decodedKey = base64_decode(strtr($fernetKey, '-_', '+/')); $aesKey = substr($decodedKey, 0, 16); $hmacKey = substr($decodedKey, 16, 16); // 2. 解析Fernet加密数据:拆分各组成部分 $decodedData = base64_decode(strtr($encryptedValue, '-_', '+/')); $iv = substr($decodedData, 9, 16); // IV从第10字节开始(索引9),长度16 $ciphertext = substr($decodedData, 25, -32); // 密文从第26字节到倒数32字节前(排除HMAC) $hmac = substr($decodedData, -32); // 最后32字节是HMAC校验值 // 3. 可选:验证HMAC,确保数据未被篡改 $expectedHmac = hash_hmac('sha256', substr($decodedData, 0, -32), $hmacKey, true); if (!hash_equals($hmac, $expectedHmac)) { die('HMAC验证失败,数据可能被篡改'); } // 4. AES-128-CBC解密并去除PKCS#7填充 $decrypted = openssl_decrypt( $ciphertext, 'aes-128-cbc', $aesKey, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv ); $padding = ord(substr($decrypted, -1)); $decrypted = substr($decrypted, 0, -$padding); dd($decrypted);
内容的提问来源于stack exchange,提问作者newdevhere1
相关产品推荐
相关产品推荐

