You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I've implemented streamed AES-GCM encryption/decryption. That means I am required to call: processBytes() with chunks of data, then I will call doFinal() to flush the remaining buffer and generate/verify MAC.
There are multiple issues which I've managed to address, changes are pretty tiny. They are in my fork: master...tomekit:pc-dart:master
If you find them useful, please go ahead and merge them upstream. I am adding more internal unit tests, however I've limited ability to confirm it's not breaking anything within PointyCastle. If you need more input on these issues or fix, please let me know.
Issue 1
Encrypted cipherText doesn't correspond to input. Some bytes are overwritten by previous contents of _bufBlock.
In a below example I am trying to encrypt: abcdefghijklmnop-qrstuvwxyz123456
whereas, this ends up being encrypted: abcdefghijklmnop-qrstuvwxyz12345q
Example code to reproduce this:
import'dart:convert';
import'dart:typed_data';
import'package:pointycastle/api.dart';
import'package:pointycastle/block/aes.dart';
import'package:pointycastle/block/modes/gcm.dart';
import"package:hex/hex.dart";
voidmain() async {
constTAG_LENGTH=16;
constBLOCK_SIZE=16;
final key =hexToUint8List('88fe0ff8c4eaf468d4cd9d9a9831662488fe0ff8c4eaf468d4cd9d9a98316624');
final nonce =hexToUint8List('3c95422167063c9542216706');
final plaintextPart1 =Uint8List.fromList(utf8.encode("abcdefghijklmnop-"));
final plaintextPart2 =Uint8List.fromList(utf8.encode("qrstuvwxyz123456"));
final cipher =GCMBlockCipher(AESEngine());
cipher.init(true, AEADParameters(KeyParameter(key), TAG_LENGTH*8, nonce, Uint8List(0)));
var bufferOut =Uint8List(plaintextPart1.length);
final bytesProcessed = cipher.processBytes(plaintextPart1, 0, plaintextPart1.length, bufferOut, 0);
bufferOut = bufferOut.sublist(0, bytesProcessed);
var bufferOut2 =Uint8List(plaintextPart2.length);
final bytesProcessed2 = cipher.processBytes(plaintextPart2, 0, plaintextPart2.length, bufferOut2, 0);
bufferOut2 = bufferOut2.sublist(0, bytesProcessed2);
var bufferOut3 =Uint8List(TAG_LENGTH+BLOCK_SIZE);
final bytesProcessed3 = cipher.doFinal(bufferOut3, 0);
bufferOut3 = bufferOut3.sublist(0, bytesProcessed3);
final cipherTextWithMac = bufferOut + bufferOut2 + bufferOut3;
print("Ciphertext: "+HEX.encode(cipherTextWithMac.sublist(0, cipherTextWithMac.length -TAG_LENGTH))); // f0c2b9571faa064c7b730143ef1a8699e871859250fcac171571ee56639d9c9644print("MAC: "+HEX.encode(cipherTextWithMac.sublist(cipherTextWithMac.length -TAG_LENGTH))); // ba49063f7908d98cbb69df8ead55973d// DECRYPTfinal decryptCipher =GCMBlockCipher(AESEngine());
decryptCipher.init(false, AEADParameters(KeyParameter(key), TAG_LENGTH*8, nonce, Uint8List(0)));
final decryptedPlainText = decryptCipher.process(Uint8List.fromList(cipherTextWithMac));
print(" PRE: "+ utf8.decode(plaintextPart1 + plaintextPart2));
print("POST: "+ utf8.decode(decryptedPlainText));
// FAIL:// abcdefghijklmnop-qrstuvwxyz123456// !=// abcdefghijklmnop-qrstuvwxyz12345qassert(utf8.decode(plaintextPart1) + utf8.decode(plaintextPart2) == utf8.decode(decryptedPlainText));
}
Uint8ListhexToUint8List(String hex) {
if (!(hex isString)) {
throw'Expected string containing hex digits';
}
if (hex.length %2!=0) {
throw'Odd number of hex digits';
}
var l = hex.length ~/2;
var result =newUint8List(l);
for (var i =0; i < l; ++i) {
var x =int.parse(hex.substring(i *2, (2* (i +1))), radix:16);
if (x.isNaN) {
throw'Expected hex string';
}
result[i] = x;
}
return result;
}
Issue 2.
During decryption, for some inputs, buffer size returned by getOutputSize is too small.
In some cases there might be up to 16 bytes coming from an internal buffer: _bufBlock.
Change in: getOutputSize was required.
Issue 3.
Decryption doesn't happen until input exceeds 16 bytes (e.g. 17 bytes).
Fix. "base_aead_block_cipher.dart:194", change from: while (len > blockSize) to while (len >= blockSize)
The text was updated successfully, but these errors were encountered:
tomekit
changed the title
AES-GCM stream - malformed cipherText when processBytes() called multiple times before doFinal()
AES-GCM - multiple issues in processBytes(), if called multiple times (e.g. for stream) before doFinal()
Dec 26, 2022
tomekit
changed the title
AES-GCM - multiple issues in processBytes(), if called multiple times (e.g. for stream) before doFinal()
AES-GCM - 3 distinct decryption/encryption issues in processBytes(), if called multiple times (e.g. for stream) before doFinal()
Dec 26, 2022
I've implemented streamed AES-GCM encryption/decryption. That means I am required to call:
processBytes()
with chunks of data, then I will calldoFinal()
to flush the remaining buffer and generate/verify MAC.There are multiple issues which I've managed to address, changes are pretty tiny. They are in my fork: master...tomekit:pc-dart:master
If you find them useful, please go ahead and merge them upstream. I am adding more internal unit tests, however I've limited ability to confirm it's not breaking anything within PointyCastle. If you need more input on these issues or fix, please let me know.
Issue 1
Encrypted cipherText doesn't correspond to input. Some bytes are overwritten by previous contents of _bufBlock.
In a below example I am trying to encrypt:
abcdefghijklmnop-qrstuvwxyz123456
whereas, this ends up being encrypted:
abcdefghijklmnop-qrstuvwxyz12345q
Example code to reproduce this:
Issue 2.
During decryption, for some inputs, buffer size returned by
getOutputSize
is too small.In some cases there might be up to 16 bytes coming from an internal buffer:
_bufBlock
.Change in:
getOutputSize
was required.Issue 3.
Decryption doesn't happen until input exceeds 16 bytes (e.g. 17 bytes).
Fix. "base_aead_block_cipher.dart:194", change from:
while (len > blockSize)
towhile (len >= blockSize)
The text was updated successfully, but these errors were encountered: