问题描述
我想将下面的 PHP 脚本转换为 dart 我尝试了很多案例,但没有任何帮助。
我尝试过以下代码;但是这里 encrypter.decrypt 方法抛出异常。
import 'package:encrypt/encrypt.dart' as EncryptPack;
import 'package:crypto/crypto.dart' as CryptoPack;
import 'dart:convert' as ConvertPack;
void main(List<String> arguments) {
var decrypt = extractPayload('$encryptedResopnse');
print(decrypt);
}
String extractPayload(String encryptedResopnse) {
if (encryptedResopnse == null) {
return '';
}
var separated = encryptedResopnse.split(':');
var secret = 'abcd123';
var data = ConvertPack.base64Decode(separated[0].trim());
var iv = CryptoPack.sha256.convert(data).toString().substring(0,16);
var salt = CryptoPack.sha256.convert(data).toString().substring(16,32);
var cipherText = CryptoPack.sha256.convert(data).toString().substring(64);
print('cipherText : ${cipherText}');
var ivObj = EncryptPack.IV.fromBase64(iv);
var generator = PBKDF2(hashAlgorithm: CryptoPack.sha1);
var hash = generator.generateBase64Key(secret,salt,2048,32);
print('hash : $hash');
var keyObj = EncryptPack.Key.fromBase64(hash);
final encrypter = EncryptPack.Encrypter(
EncryptPack.AES(keyObj,mode: EncryptPack.AESMode.cbc)); // Apply CBC mode
print(cipherText);
var firstBase64Decoding = cipherText; // First Base64 decoding
print(firstBase64Decoding);
final decrypted = encrypter.decrypt(
EncryptPack.Encrypted.fromBase64(firstBase64Decoding),iv: ivObj);
return decrypted;
}
演示内容;
初始化 aes_secret
$aes_secret = '123456ac';
演示内容;
$ encryptedResopnse = “dBluiiVaHxhRcWJPaEip9kCGXDwufk3mfp8Xe9ioh9UKu6xL + CHUZrKvuf3xI7P1vFpvyyJ2Vz2Q3ieLEuRHk7NOinZU82FNdE3SOc9D2JTUFkif5ye3rVfQ7O39DpBnV41CduEP0OsASA8cr / RChqhulVHsaw6oUP0mg79M3Jlnpbab0EqlWRQx3k85rcajmov4cYLmsja ++ p2Lyw / BgOTKDf / yw3NWiK73Ot4P3C6urUiFNUCQTaOHCas1Sa8Wl0udQo1viyApuCE9 + Ll1SGnUu26uNy5RR55IFLVnAHuIOBDePjdAw3DapAtLFnSd + FrVjYcUuevMMliSy3PHiZU66qdyx8YSn13tYH6KGFxC / kvPsi5dLGorQ1TdNR5fxZGrpnQXEEIwWYSiF8LA0AJzVqpRoXs9PkEseCUnH1Sj5sBQgXQc0RA8vHWf3n2X / cABLEWaRHHlBlZjqjJXl0uKSgAWC3JoelABGSuSCvL3GJhn9SuSV6 + jCOftb6UCmw7LzalKB7UNIQPJ1vMtKl3 + 38RKDwp7a4xpdlln + IPP + R2aGuobuhk9ySSJYN3GCn7MoC / uaCAR0aEYsIHP1BQ + UgOPOsQFZEVdKMrFLJsJ3HtQ1fQxqpPQ13TClWCOyZu + W + 1q4W + 8CBJuI4l4Em + 91”;
class AesEncryption {
private static $encryptionMethod = 'aes-256-cbc';
private static $blockSize = 16;
private static $keySize = 32; // in bytes - so 256 bit for aes-256
private static $iterations = 2048;
public static function sign($data,$key) {
return hash_hmac('sha256',$data,$key);
}
/**
* @param string $encryptedContent
* @param string $secret
* @return string
*/
public static function decrypt(string $encryptedContent,string $secret) {
if (!$encryptedContent) {
return "";
}
// Separate payload from potential hmac
$separated = explode(":",trim($encryptedContent));
// Extract HMAC if signed
$hmac = (isset($separated[1])) ? $separated[1] : null;
// Convert data-string to array
$data = base64_decode($separated[0]);
// Then we remove the iv and salt to fetch the original text
$iv = substr($data,self::$blockSize);
//echo($iv);
$salt = substr($data,self::$blockSize,self::$blockSize);
// We finally extract the ciphertext
$cipherText = substr($data,self::$blockSize * 2);
// Generate Key
$key = hash_pbkdf2('sha1',$secret,$salt,self::$iterations,self::$keySize,true);
// Check https://www.PHP.net/manual/en/function.openssl-decrypt.PHP
return openssl_decrypt($cipherText,self::$encryptionMethod,$key,OPENSSL_RAW_DATA,$iv);
}
}
解决方法
generateBase64Key
包的 generateKey
或 PBKDF2
方法需要一个字符串作为盐。在这些方法的实现中,salt是UTF8编码的。
通常,salt 是随机生成的,因此包含与 UTF8 编码不兼容的字节序列。不知道这里使用的盐是如何产生的。但是,它包含(如随机生成的盐)与 UTF8 编码不兼容的字节序列。因此,在这种情况下,应用的 PBKDF2
包不适合密钥派生。在我看来,为盐选择字符串类型是一个糟糕的设计。
另一方面,cryptography
包提供了一个 Pbkdf2
实现,它将盐作为 Uint8List
处理,因此是合适的。该库还支持 AES/CBC,因此也可以使用该库进行解密。
以下实现对发布的密文进行解密:
var encryptedResopnse = 'dBluiiVaHxhRcWJPaEip9kCGXDwufk3mFp8Xe9ioh9UKu6xL+CHUZrKvuf3xI7P1vFpvyyJ2Vz2Q3ieLEuRHk7NOinZU82FNdE3SOc9D2JTUFkif5ye3rVfQ7O39DpBnV41CduEP0OsASA8cr/RChqhulVHsaw6oUP0mg79M3Jlnpbab0EqlWRQx3k85rcajmov4cYLmsja++p2Lyw/BgOTKDf/yw3NWiK73Ot4P3C6urUiFNUCQTaOHCas1Sa8Wl0udQo1viyApuCE9+Ll1SGnUu26uNy5RR55IFLVnAHuIOBDePjdAw3DapAtLFnSd+FrVjYcUuevMMliSy3PHiZU66qdyx8YSn13tYH6KGFxC/kvPsi5dLGorQ1TdNR5fxZGRPNQXEEIwWYSiF8LA0AJzVqpRoXs9PkEseCUnH1Sj5sBQgXQc0RA8vHWf3n2X/cABLEWaRHHlBlZjqjJXl0uKSgAWC3JoelABGSuSCvL3GJhn9SuSV6+jCOftb6UCmw7LzalKB7UNIQPJ1vMtKl3+38RKDwp7a4xpdlln+IPp+R2aGuobuhk9ySSJYN3GCn7MoC/uaCAR0aEYsIHP1BQ+UgOPOsQFZEVdKMrFLJsJ3HtQ1fQxqpPQ13TClWCOyZu+w+1q4W+8CBJuI4l4Em+91aMT4xm7FWB/RhmUN8hfsHk7EATW8CkRGF4zFGKKdeN9zzGM0ViZYv30PARg8W2SJRKoZkaMOgZXtE/8D9fWzrmNDdHBCbMt0yrGycBbn8/b3JLQkcqxzY6VnWrBR1VJ66OB1mH5i6ejDrkxLx5VvkdKf3fcoKEZ/FptZK4zUwXgHJIF/YLChsYUj2mX9Ox18ZZi9vBG9L5vONc0GuQ31FzjwG77yGrJrS4mVi76uaifu7Thd6TiYXuu7OaFBl9+lPMvfHf+wWRqLQbgDoVtOXvND5e4LncWPHZbEjHGwO9I/MnVjMnH6nSbKER63Na8XBUIwsSlJwrswa3fLNInJA1/qGBb9nrVNzKLRfvku1UPvavDP1WxsTEzg0gH8Ui6KzBoBOd9IK/7ZtmSmSug5Ig8GAZ0R/kR7DnSs4ekxKxmcCJ95YVyf9fx0Vlw2oB9iOoUaHM3OITeldfMtoM=';
var secret = 'abcd123';
var decrypt = extractPayload(encryptedResopnse,secret);
print(decrypt);
与
import 'dart:convert' as ConvertPack;
import 'package:cryptography/cryptography.dart' as CryptographyPack;
...
String extractPayload(String encryptedResopnse,String secret) {
if (encryptedResopnse == null) {
return '';
}
// Separate data
// Note: Authentication not considered (separated: size = 1; see ciphertext and PHP code (hmac derived but unused))
var separated = encryptedResopnse.split(':');
var data = ConvertPack.base64Decode(separated[0].trim());
var iv = data.sublist(0,16);
var salt = data.sublist(16,32);
var cipherText = data.sublist(32);
// Derive key
var generator = CryptographyPack.Pbkdf2(
macAlgorithm: CryptographyPack.Hmac(CryptographyPack.sha1),iterations: 2048,bits: 256,);
var hash = generator.deriveBitsSync(
ConvertPack.utf8.encode(secret),nonce: CryptographyPack.Nonce(salt)
);
// Decrypt
var decrypted = CryptographyPack.aesCbc.decryptSync(
cipherText,secretKey: CryptographyPack.SecretKey(hash),nonce: CryptographyPack.Nonce(iv));
var plaintext = ConvertPack.utf8.decode(decrypted);
return plaintext;
}
并作为结果返回:
{"nofollow":false,"id":"2226521","title":"When You Say Nothing At All","album":"Ronan","albumID":"237798","artist":"Ronan Keating","artistID":"52715","track":"6","year":"1999","duration":"258.00","coverArt":"323816","ArtistArt":1002340723,"allowoffline":1,"genre":"Pop","AlbumArt":"323816","keywords":["When You Say Nothing At All","Ronan Keating","Ronan"],"languageid":2,"bitrates":"24,256","hexcolor":"#b43931","cleardetails":1,"bitrate":64,"size":"2108905","releasedate":"1999-01-01","explicit":"0","extras":"eyJyZXF1ZXN0dHlwZWlkIjo...","saveprogress":0,"lyrics":"true","is_podcast":0,"is_original":1,"location":"https:\\\/\\\/some audio file\u2019s URL","debugurl":"http:\\\/\\\/some URL","debugurldata":"http:\\\/\\\/some URL","hash":"b1229af8b0078e0b9ec9e203e3b32b7c","plays":"593963","likes":"13705"}
必须在 dependencies 部分的 pubspec.yaml 中引用 cryptography
包,here:
cryptography: ^1.4.1