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);
}