What it means in practice: "Using the same nonce with the same key more than once leads to catastrophic loss of security."
See original GitHub issueHello,
It’s is not an issue per si, but, this repo does not have Discussions tab enabled.
I’m try using the AeadAlgorithm.XChaCha20Poly1305, and I little bit confused when read:
Note
Using the same nonce with the same key more than once leads to catastrophic loss of security.
To prevent nonce reuse when encrypting multiple plaintexts with the same key, it is recommended to increment the previous nonce; a randomly generated nonce is not suitable.
In my scenario I need to encrypt
some data and decrypt
this data in another moment, like an Token
:
>. Request: `my-web-api/token/generate`
>. Response: Some `ciphertext` generated by `XChaCha20Poly1305` in `Base64` format.
But when I tried to use the recommended practices in nonce
value(increment) I can’t Decrypt
data. In my thinking I need the suitable nonce
to do the correct data decryption, but, how will I know the appropriate one, if I auto-incremented the value? I need always extern/public
the nonce
I used? Like:
“Encrypt”
>. Request: `my-web-api/token/generate`
>. Response: Some `ciphertext` generated by `XChaCha20Poly1305` in `Base64` format + `nonce`.
“Decrypt”
>. Request: `my-web-api/token/validate`
>. Body: `ciphertext` in `Base64` format with `nonce`.
Some foo
code example:
class Program
{
public static byte[] ExportedKey;
static void Main(string[] args)
{
const string json =
@"{'Id':'62fea73265676bb8c06749a7','TriadKey':'111155555555555555555555555555555555555555555151513321321321654654654897897654654321321112','IsValid':false,'ExpirationDate':'2022-08-19T20:55:14.6146798Z'}";
Aes256Gcm(AeadAlgorithm.Aes256Gcm, "Z8c0kX9ATszSsKCAROHnZw==", json);
Console.ReadLine();
}
private static void Aes256Gcm(AeadAlgorithm aeadAlgorithm, string nonceText, string dataText)
{
// create a new key pair
var creationParameters = new KeyCreationParameters
{
ExportPolicy = KeyExportPolicies.AllowPlaintextArchiving
};
using var key = Key.Create(aeadAlgorithm, creationParameters);
ExportedKey = key.Export(KeyBlobFormat.NSecSymmetricKey);
File.WriteAllBytes("private-secret-key.nsec", ExportedKey);
// generate some data to be signed
var data = Encoding.UTF8.GetBytes(dataText);
var nonce = Encoding.UTF8.GetBytes(nonceText);
// increment nonce
nonce[0]++;
// sign the data using the private key
var ciphertext = aeadAlgorithm.Encrypt(key: key, nonce: nonce, plaintext: data, associatedData: null);
Console.WriteLine($"Encrypted Data:\n{Convert.ToBase64String(ciphertext)}\n");
// DUMB: simulates "new request" `my-web-api/token/validate` = NEW NONCE/INCREMENTED
nonce[0]++;
Decrypt(aeadAlgorithm, nonce, ciphertext);
}
private static void Decrypt(AeadAlgorithm aeadAlgorithm, byte[] nonce, byte[] ciphertext)
{
// re-import it
using var key = Key.Import(aeadAlgorithm, ExportedKey, KeyBlobFormat.NSecSymmetricKey);
var decryptedPlaintext = aeadAlgorithm.Decrypt(key, nonce, default, ciphertext);
Console.WriteLine
(
decryptedPlaintext is null
? "Data decryption failed."
: $"Decrypted Data:\n{Encoding.UTF8.GetString(decryptedPlaintext)}\n"
);
}
}
OUTPUT: “Data decryption failed.” - Because use different
nouce
What would be the proper way to deal with this scenario?
Cheers! 😁
Issue Analytics
- State:
- Created a year ago
- Comments:6 (2 by maintainers)
Top GitHub Comments
Thanks @samuel-lucas6!
@igorgomeslima Yes, you could prepend the nonce to the ciphertext (e.g. using
Array.Copy()
, the LINQ.Concat()
, etc) before converting the whole thing to a Base64 string. Then you convert the Base64 to a byte array and retrieve the nonce as bytes from the beginning.