AESDecrypt method
Perform an ECIES decryption using AES for the symmetric cipher.
cipherText
- The buffer to decrypt. Note that the buffer in this instance has a very specific
encoding format called "BIE1" or "Electrum ECIES". It is in essence a serialization format with a
built-in checksum.
- bytes
0 - 4
: Magic value. Literally "BIE1". - bytes
4 - 37
: Compressed Public Key - bytes
37 - (length - 32)
: Actual cipherText - bytes
length - 32
: (last 32 bytes) Checksum valu
recipientPrivateKey
- Private Key of the receiving party
Implementation
List<int> AESDecrypt(List<int> cipherText, SVPrivateKey recipientPrivateKey){
//AES Cipher is calculated as
//1) S = recipientPrivateKey o senderPublicKey
//2) cipher = S.x
if (cipherText.length < 37){
throw Exception('Buffer is too small ');
}
final magic = utf8.decode(cipherText.sublist(0, 4));
if ( magic != 'BIE1'){
throw Exception('Not a BIE1-encoded buffer');
}
final senderPubkeyBuffer = cipherText.sublist(4, 37);
final senderPublicKey = SVPublicKey.fromHex(HEX.encode(senderPubkeyBuffer));
//calculate S = recipientPrivateKey o senderPublicKey
final S = (senderPublicKey.point * recipientPrivateKey.privateKey)!; //point multiplication
final cipher = S.x;
if (cipherText.length - tagLength <= 37 ){
throw Exception('Invalid Checksum detected. Combined sum of Checksum and Message makes no sense');
}
//validate the checksum bytes
final pubkeyS = SVPublicKey.fromXY(S.x!.toBigInteger()!, S.y!.toBigInteger()!);
final pubkeyBuffer = HEX.decode(pubkeyS.getEncoded(true));
final pubkeyHash = SHA512Digest().process(pubkeyBuffer as Uint8List);
//initialization vector parameters
final iv = pubkeyHash.sublist(0, 16);
final kE = pubkeyHash.sublist(16, 32);
final kM = pubkeyHash.sublist(32, 64);
final message = Uint8List.fromList(cipherText.sublist(0, cipherText.length - tagLength));
final hmac = _calculateHmac(kM, message);
final messageChecksum = cipherText.sublist(cipherText.length - tagLength, cipherText.length);
if (!ListEquality().equals(messageChecksum, hmac)){
throw Exception('HMAC checksum failed to validate');
}
//decrypt!
CipherParameters params = PaddedBlockCipherParameters(ParametersWithIV(KeyParameter(kE), iv), null);
BlockCipher decryptionCipher = PaddedBlockCipher("AES/CBC/PKCS7");
decryptionCipher.init(false, params);
final decrypted = decryptionCipher.process(cipherText.sublist(37, cipherText.length - tagLength) as Uint8List);
return decrypted;
}