I have a big problem about encryption with AES-GCM.
Between using dotnet and Node.js, the encryption results are slightly different.
Here is the code in Node.js from JOSE using Crypto Library :
var cipher = crypto.createCipheriv("id-aes256-GCM", key, iv);
cipher.setAutoPadding(false);
cipher.setAAD(aad);
var ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
return {
cipher: ciphertext,
tag: cipher.getAuthTag()
}
The same with C# and BouncyCastle library :
var iv = Convert.FromBase64String("3Wey/ctxwAnK7ZRv");
var cipher = new GcmBlockCipher(new AesFastEngine());
var parameters = new AeadParameters(new KeyParameter(key), MacBitSize, iv, aad);
cipher.Init(true, parameters);
//Generate Cipher Text With Auth Tag
var cipherText = new byte[cipher.GetOutputSize(secretMessage.Length)];
var len = cipher.ProcessBytes(secretMessage, 0, secretMessage.Length, cipherText, 0);
cipher.DoFinal(cipherText, len);
var tag = cipher.GetMac();
The authentication tag is completely different, but the ciphertext is nearly the same except 4 bytes that are different.
That is very strange, and I don't understand why this is different for the same cipher because every parameter is the same (iv, key, aad).
Does anyone know what is wrong?
Thanks in advance!
EDIT:
for example I get this with NodeJS : WCgMFNfaGsoHynha+Nl+DYT7MiPiU3mbnnEMMMgbHjepkFObJEM8QT7UoTRt74iwmSsDI6IPqgpCpJwYtg/pre5nwbbZqwLh43QlmOm2xZhbeIXq1xOSapNIG2oAjiSJsij9scMjwwrQrYhBujiMbJqy4ppwyD8w5EiNaUGw3ZzUSTxe3ZSl6Mr8kHnsc3L1NVc+qpRyry1V3N+A2pNuE7VzI3Q3QclD2tAAVXtmF2GfXyY70y9+sdib/cXiqJh8Z8q7aZVTAWCLjWjvBn98N0p8KNY35NvKRmzJSu8tZ20ZBA==
And with dotnet BouncyCastle or other same library : WCgMFNfaGsoHynha+Nl+DYT7MiPiU3mbnnEMMMgbHjepkFObJEM8QT7UoTRt74iwmSsDI6IPqgpCpJwYtg/pre5nwbbZqwLh43QlmOm2xZhbeIXq1xOSapNIG2oAjiSJsij9scMjwwrQrYhBujiMbJqy4ppwyD8w5EiNaUGw3ZzUSTxe3ZSl6Mr8kHnsc3L1NVc+qpRyry1V3N+A2pNuE7VzI3Q3QclD2tAAVXtmF2GfXyY70y94sdib/cXiqJh8Z8q7aeVTAWCLjWjvBn98N0x8KNY35N3KRmzJSu8tZ20Z
The source text is a encoded JSON string from object. Maybe it's serialization of the JSON.
Other things, the ciphertext generated in dotnet is not decryptable in nodeJS, so it's probably a cross platform problem ?
EDIT2:
Here is the code to decrypt in NodeJS :
var jose = require('jose') ;
secret = 'rioa62N/Kvx78wUu6icgvDthco+Ro086WFqT4h4QMj4=';
// retrieve the header
var header = new Buffer('eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiY3R5IjoiSldUIn0=', 'base64') ; // same as in dotnet
// Retreive the intialisation vector
var iv = new Buffer('3Wey/ctxwAnK7ZRv', 'base64'); // same as in dotnet
// Retrieve the cipher text (contains the JWS)
var ciphertext = new Buffer('R2HdWvfZuyNyf9VxZ/FNAkxZQpS9eSTHCnucA32+fB/+Yn1Qnm/HTjHXUsYiO84xv+v7BfiR8Myubb7lWjlCl43TFIB4TIiMPeEI7xLkRzRORnqOfFCktlirwv5Tjzj/vknpaTB1ZLKgIiNxOhZhuPr8S0dLVRm7Sy6tbNPKbUJgBAueg8Q28x3XGonDaznf8SwMVbnqRWD2FSYhoA4aH04iKXyvD9RMECl+/eAzSMpvJAvBCFaASe6A11VF/Jt3nMuOIqMsa93hnS8Y84Idpa9k2glMytS7tD/q2s2olaCs','base64') ;
// Retrieve the authentication tag
var authTag = new Buffer('TMrUu7Q/6trNqJWgrEKwYg==','base64') ;
// get the decryptor
var aes = new jose.jwa('A256GCM') ;
// Compute the aad (base 64 representation of the header)
var aad = new Buffer('eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiY3R5IjoiSldUIn0=', 'base64') ; // same as in dotnet
// The key must be a buffer
var key = new Buffer(secret, 'base64') ;
// Decryption
var plain = aes.decrypt ( ciphertext, authTag, aad, iv, key )
// Display the jwt
console.log ( 'Part 1: ' + header ) ;
console.log ( 'Part 2: ') ;
console.log ( 'Part 3: ' + iv ) ;
console.log ( 'Part 4 :' + plain ) ;
console.log ( 'Part 5: ' + authTag) ;
Here is the code to encrypt in dotnet :
var sharedKey = Convert.FromBase64String("rioa62N/Kvx78wUu6icgvDthco+Ro086WFqT4h4QMj4=");
byte[] key = Convert.FromBase64String("+bGRaL6EPzUCHu0GiNxthgvD3hJN/glKJRQ7B66LJLo=");
var payload = new
{
iss = "XXX",
exp = 1519828214,
//exp = DateTimeOffset.Now.ToUnixTimeSeconds() + 90, // Expiration time is up to 90s, lets play on safe side
sub = "XXX",
secret = Convert.ToBase64String(key)
};
string jwt = JwtUtils.Encode(payload, sharedKey, JwtHashAlgorithm.HS256); // HMACSHA256 enconding
var jweHeader = new { alg = "dir", enc = "A256GCM", cty = "JWT" };
var serializedJweHeader = JsonConvert.SerializeObject(jweHeader, Formatting.None);
var serializedJweHeaderBytes = Encoding.UTF8.GetBytes(serializedJweHeader);
var nonce = Convert.FromBase64String("3Wey/ctxwAnK7ZRv");
var secretMessage = Encoding.UTF8.GetBytes(jwt);
var cipher = new GcmBlockCipher(new AesFastEngine());
var parameters = new AeadParameters(new KeyParameter(sharedKey), 128, nonce, serializedJweHeaderBytes);
cipher.Init(true, parameters);
//Generate Cipher Text With Auth Tag
var cipherText = new byte[cipher.GetOutputSize(secretMessage.Length)];
var len = cipher.ProcessBytes(secretMessage, 0, secretMessage.Length, cipherText, 0);
cipher.DoFinal(cipherText, len); // Convert.ToBase64String(cipherText.Take(225).ToArray()) to have the base64 représentation to set in NodeJS for the decryption, it appears that cipherText has tag so that's why I take only 225 first
var tag = cipher.GetMac(); // Convert.ToBase64String(tag) to have the base64 representation
Here is the result crash of NodeJS whn I try to run the above code :
> crypto.js:183
var ret = this._handle.final();
^
Error: Unsupported state or unable to authenticate data
at Decipheriv.final (crypto.js:183:26)
at Object.decrypt (C:\Program Files\nodejs\node_modules\jose\lib\jwa\content
.js:140:72)
at Object.<anonymous> (C:\Program Files\nodejs\decrypt_jwe_hard.js:35:17)
at Module._compile (module.js:643:30)
at Object.Module._extensions..js (module.js:654:10)
at Module.load (module.js:556:32)
at tryModuleLoad (module.js:499:12)
at Function.Module._load (module.js:491:3)
at Function.Module.runMain (module.js:684:10)
at startup (bootstrap_node.js:187:16)