How to decrypt AES 256 CBC with Dart
The generateBase64Key
or generateKey
methods of the PBKDF2
package expect a string for the salt. In the implementation of these methods, the salt is UTF8 encoded.
Typically, a salt is randomly generated and therefore contains byte sequences that are incompatible with the UTF8 encoding. It is not known how the salt used here was generated. However, it contains (like a randomly generated salt) byte sequences that are incompatible with the UTF8 encoding. For this reason the PBKDF2
package applied is unsuitable for key derivation in this case. In my opinion, the choice of the string type for a salt is a poor design.
The cryptography
package, on the other hand, provides a Pbkdf2
implementation that processes the salt as a Uint8List
and is thus suitable. This library also supports AES/CBC, so it makes sense to use this library for the decryption as well.
The following implementation decrypts the posted ciphertext:
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);
with
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;
}
and returns as result:
{"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"}
The cryptography
package must be referenced in the pubspec.yaml in the dependencies section, here:
cryptography: ^1.4.1
Yasin ilhan
Updated on December 26, 2022Comments
-
Yasin ilhan over 1 year
I want to convert below PHP script to dart i tried a lot case but nothing help me.
I have tried following code; But throw an exception here encrypter.decrypt method.
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; }
for demo content ;
Initialize the aes_secret
$aes_secret = '123456ac';
Demo content;
$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, 0, 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); } }
-
Topaco over 3 yearsSO is not a code writing service. Please post your most recent dart code and describe your problems.
-
Yasin ilhan over 3 years@Topaco i shared the code.
-