-1

I have two functions witch cipher and decrypt data with AES-GCM algorithm but using cryptography package. I don't think its bad, it helped me a lot, but I want to translate them so I can use pointycastle package for all my different encryption and decryption algorithms.

Functions using cryptography package are:

Future<CipherDataHolder> cipher(String clearValue) async {
    final algorithm = AesGcm.with256bits(nonceLength: 12); //128bits MAC default
    final SecretKey secretKey = await algorithm.newSecretKey();
    final List<int> nonce = algorithm.newNonce();

    final secretBox = await algorithm.encrypt(
      utf8.encode(clearValue),
      secretKey: secretKey,
      nonce: nonce,
    );

    String cipherText = base64.encode(secretBox.concatenation());
    String passphrase = base64.encode(await secretKey.extractBytes());
    return CipherDataHolder(ciphertext: cipherText, passphrase: passphrase);
}
Future<String> decrypt(CipherDataHolder secretData) async {
  final Uint8List cipherData = base64.decode(secretData.ciphertext);
  final Uint8List ciphertext  = cipherData.sublist(12, cipherData.length - 16);
  final Uint8List iv = cipherData.sublist(0, 12);
  final Uint8List mac = cipherData.sublist(cipherData.length - 16);

  List<int> passphrase = base64.decode(secretData.passphrase);
  final SecretKey secretKey = SecretKey(passphrase);
  final SecretBox secretBox = SecretBox(ciphertext, nonce: iv, mac: Mac(mac));
  final List<int> clearValue = await AesGcm.with256bits().decrypt(secretBox, secretKey: secretKey);

  return utf8.decode(clearValue);
}

CipherDataHolder is just a class to hold the values

class CipherDataHolder {
  CipherDataHolder({required this.ciphertext, required this.passphrase});
  String ciphertext;
  String passphrase;
}

/////////////////////////////////////////////////////////////////////

UPDATE

/////////////////////////////////////////////////////////////////////

Here is what I have tried till now to translate those functions

Functions using pointycastle package are:

Future<CipherDataHolder> cipherWithGCMyPointyCastle({required String clearValue}) async {
    final Uint8List key = genKey(); //32 bytes key
  final Uint8List nonce = generateRandomNonce();  //12 bytes nonce
  final List<int> plainTextBytes = utf8.encode(clearValue);

  final cipher = pointy.GCMBlockCipher(pointy.AESEngine())
    ..init(
        true, // encrypt
        pointy.AEADParameters(
          pointy.KeyParameter(key), // the 256 bit (32 byte) key
          128,  //Mac length
          nonce, // the 12 byte nonce
          Uint8List(0), // empty extra data
        ));

  //Last 16 is mac data, rest is plaintext Bytes
  Uint8List cipherTextBytes = cipher.process(Uint8List.fromList(plainTextBytes));

  //Concatenate nonce + cipherText + mac bytes
  String cipherText = base64.encode(concatenateCipherData(nonceBytes: cipher.nonce, cipherTextBytes: cipherTextBytes.sublist(0, cipherTextBytes.length - 16), macBytes: cipher.mac));
  return CipherDataHolder(ciphertext: cipherText, passphrase: base64.encode(key));
}
  Future<String> decryptWithGCMyPointyCastle(CipherDataHolder secretData) async {
      final Uint8List cipherData = base64.decode(secretData.ciphertext);
  final Uint8List ciphertext = cipherData.sublist(12, cipherData.length - 16); //Rest between 12 and last 16
  final Uint8List nonce = cipherData.sublist(0, 12); //First 12 bytes
  final Uint8List mac = cipherData.sublist(cipherData.length - 16); //last 16 bytes

  List<int> passphrase = base64.decode(secretData.passphrase);

  final cipher = pointy.GCMBlockCipher(pointy.AESEngine())
        ..init(
            false, // decrypt
            pointy.AEADParameters(
              pointy.KeyParameter(Uint8List.fromList(passphrase)),
              128,
              nonce,
              Uint8List(0),
            ));

  BytesBuilder bb = BytesBuilder();
  bb.add(ciphertext);
  bb.add(mac);
  Uint8List ciphertextWithTag = bb.toBytes();

  return String.fromCharCodes(cipher.process(ciphertextWithTag));
}

I still have some doubts and I don't know if I'm doing things right. But cipher and decrypt are working now and when I cipher data I'm getting similar results with cryptography package.

Main problem now is that when I cipher with pointycastle, for example this value: abc123|@#¢∞¬÷“”≠

Results with cryptography: abc123|@#¢∞¬÷“”≠

Results with pointycastle: abc123|@#¢â¬÷âââ

I understand it can be some kind of codification problem, but I don't see where :( Where could be the problem or What am I doing wrong?

These are the auxiliar functions

  Uint8List concatenateCipherData({required List<int> nonceBytes, required List<int> cipherTextBytes, required List<int> macBytes}) {
    int n = cipherTextBytes.length + nonceBytes.length + macBytes.length;
    Uint8List result = Uint8List(n);

    int i = 0;
    result.setAll(i, nonceBytes);
    i += nonceBytes.length;

    result.setAll(i, cipherTextBytes);
    i += cipherTextBytes.length;

    result.setAll(i, macBytes);

    return result;
  }

  Uint8List generateRandomNonce() {
    final _sGen = Random.secure();
    final _seed = Uint8List.fromList(List.generate(32, (n) => _sGen.nextInt(256)));
    pointy.SecureRandom sec = pointy.SecureRandom("Fortuna")..seed(pointy.KeyParameter(_seed));
    return sec.nextBytes(12);
  }
  Uint8List genKey() {
    final _sGen = Random.secure();
    final _seed = Uint8List.fromList(List.generate(32, (n) => _sGen.nextInt(256)));
    pointy.SecureRandom sec = pointy.SecureRandom("Fortuna")..seed(pointy.KeyParameter(_seed));
    return sec.nextBytes(32);
  }
Antonycx
  • 209
  • 3
  • 14
  • 1
    This is not a question, it's an assignment - **your** assignment. – Maarten Bodewes Jan 06 '22 at 22:37
  • @MaartenBodewes Added debugging details, sorry for that – Antonycx Jan 11 '22 at 17:21
  • 1
    You seem to be getting close. As this question has been closed, I suggest you ask a new one(s) with precise problems. Some suggestions: (1) how you are generating the seed would normally be good enough for random numbers - no need to use fortuna. (2) replace `255` with `256` in `nextInt` (3) if you do use fortuna - just make one `pc.SecureRandom` and reuse it (4) for debugging, use fixed keys and nonce, e.g. 0,0,0,0,.....0,0,0 and 1,1,1,1,1,1,1,1,1,1,1,1 and compare the results of encrypting something - do both ways give the same result? – Richard Heap Jan 11 '22 at 17:37
  • and (5) why code the creation of the decrypt cipher differently? Just copy/paste and change `true` to `false` – Richard Heap Jan 11 '22 at 17:40
  • 1
    and (6) I believe this is reversed *//First 16 is mac data, rest is plaintext Bytes* The last 16 bytes of the ciphertext are probably the mac. – Richard Heap Jan 11 '22 at 17:45
  • 1
    The "passphrase just seems to be a base 64 encoding of the random key in the original code. I wonder if you should remove 16 bytes at the end of the ciphertext. That is usually reserved for the MAC, but that seems to be generated separately. – Maarten Bodewes Jan 11 '22 at 20:08
  • Thank you, @RichardHeap and all, It's working now, but I have different results when decrypt, do you know why ? – Antonycx Jan 13 '22 at 02:26
  • As this question got closed, you should accept this answer and create a new question with your new specific question. As in all good questions, show your code, test data, actual and expected results. – Richard Heap Jan 13 '22 at 14:37

1 Answers1

3

All the pointcastle ciphers are instantiated in basically the same way. Here's the way to instantiate AES/GCM, with examples for the inputs and outputs.

  final keyBytes = Uint8List(32); // dummy key - replace with 256 bit key
  final nonce = Uint8List(12); // dummy nonce - replace with random value
  final plainTextBytes = Uint8List(5); // dummy input - 5 bytes (5 is just an example)

  final cipher = GCMBlockCipher(AESEngine())
    ..init(
        true, // encrypt (or decrypt)
        AEADParameters(
          KeyParameter(keyBytes), // the 256 bit (32 byte) key
          16 * 8, // the mac size (16 bytes)
          nonce, // the 12 byte nonce
          Uint8List(0), // empty extra data
        ));

  final cipherTextBytes = cipher.process(plainTextBytes);
  print(cipherTextBytes.length); // prints 21 = 16 (mac) + 5 (plain text length) 
Richard Heap
  • 48,344
  • 9
  • 130
  • 112