From 8092c691d598abcee26c87f19d231b6c94123363 Mon Sep 17 00:00:00 2001 From: Ziya Suzen Date: Tue, 31 Mar 2026 12:36:46 +0100 Subject: [PATCH] crypto: wipe intermediate key material after use Ed25519 sign left expanded key (az), nonce (r), and hram arrays on the heap after signing. X25519 ScalarMult left the clamped private key copy. TweetNaCl CryptoBox and CryptoBoxOpen left the shared key and DH intermediate. Add try/finally blocks to wipe these with Array.Clear. Best-effort in managed .NET since the GC may have already copied the arrays, but reduces the number of live copies. --- NATS.NKeys/NaCl/Internal/Ed25519Ref10/sign.cs | 11 +- NATS.NKeys/NaCl/TweetNaCl.cs | 27 ++++- NATS.NKeys/X25519/X25519.cs | 102 +++++++++--------- 3 files changed, 87 insertions(+), 53 deletions(-) diff --git a/NATS.NKeys/NaCl/Internal/Ed25519Ref10/sign.cs b/NATS.NKeys/NaCl/Internal/Ed25519Ref10/sign.cs index 25580b8..94f66d4 100644 --- a/NATS.NKeys/NaCl/Internal/Ed25519Ref10/sign.cs +++ b/NATS.NKeys/NaCl/Internal/Ed25519Ref10/sign.cs @@ -75,9 +75,10 @@ public static void crypto_sign( byte[] m, int moffset, int mlen, byte[] sk, int skoffset) { - byte[] az, r, hram; + byte[] az = null, r = null, hram = null; GroupElementP3 R; - var hasher = new Sha512(); + using var hasher = new Sha512(); + try { hasher.Update(sk, skoffset, 32); az = hasher.Finalize(); @@ -105,6 +106,12 @@ public static void crypto_sign( Array.Copy(s, 0, sig, sigoffset + 32, 32); CryptoBytes.Wipe(s); } + finally + { + if (az != null) CryptoBytes.Wipe(az); + if (r != null) CryptoBytes.Wipe(r); + if (hram != null) CryptoBytes.Wipe(hram); + } } } } diff --git a/NATS.NKeys/NaCl/TweetNaCl.cs b/NATS.NKeys/NaCl/TweetNaCl.cs index 0e46894..442e630 100644 --- a/NATS.NKeys/NaCl/TweetNaCl.cs +++ b/NATS.NKeys/NaCl/TweetNaCl.cs @@ -185,7 +185,14 @@ public static Byte[] CryptoBoxKeypair(Byte[] secretKey) public static Byte[] CryptoBoxBeforenm(Byte[] publicKey, Byte[] secretKey) { Byte[] s = CryptoScalarmult(secretKey, publicKey); - return CryptoCoreHSalsa20(_0, s, Sigma); + try + { + return CryptoCoreHSalsa20(_0, s, Sigma); + } + finally + { + Array.Clear(s, 0, s.Length); + } } /// @@ -231,7 +238,14 @@ public static Byte[] CryptoBoxOpenAfternm(Byte[] cipheredMessage, Byte[] nonce, public static Byte[] CryptoBox(Byte[] message, Byte[] nonce, Byte[] publicKey, Byte[] secretKey) { Byte[] k = CryptoBoxBeforenm(publicKey, secretKey); - return CryptoBoxAfternm(message, nonce, k); + try + { + return CryptoBoxAfternm(message, nonce, k); + } + finally + { + Array.Clear(k, 0, k.Length); + } } /// @@ -249,7 +263,14 @@ public static Byte[] CryptoBox(Byte[] message, Byte[] nonce, Byte[] publicKey, B public static Byte[] CryptoBoxOpen(Byte[] cipheredMessage, Byte[] nonce, Byte[] publicKey, Byte[] secretKey) { Byte[] k = CryptoBoxBeforenm(publicKey, secretKey); - return CryptoBoxOpenAfternm(cipheredMessage, nonce, k); + try + { + return CryptoBoxOpenAfternm(cipheredMessage, nonce, k); + } + finally + { + Array.Clear(k, 0, k.Length); + } } /// diff --git a/NATS.NKeys/X25519/X25519.cs b/NATS.NKeys/X25519/X25519.cs index 59b49b5..26e770d 100644 --- a/NATS.NKeys/X25519/X25519.cs +++ b/NATS.NKeys/X25519/X25519.cs @@ -20,61 +20,67 @@ internal static class Curve25519 private static byte[] ScalarMult(byte[] input, byte[] baseIn) { var e = new byte[32]; + try + { + Array.Copy(input,e,32); //copy(e[:], input[:]) + e[0] &= 248; + e[31] &= 127; + e[31] |= 64; + + FieldElement x1, x2, z2, x3, z3, tmp0, tmp1; + z2 = new FieldElement(); + // feFromBytes(&x1, base) + x1 = new FieldElement(baseIn); //SECOND NUMBER + //feOne(&x2) + x2 = new FieldElement(); + x2.One(); + //feCopy(&x3, &x1) + x3 = new FieldElement(); + FieldElement.Copy(ref x3,x1); + //feOne(&z3) + z3 = new FieldElement(); + z3.One(); - Array.Copy(input,e,32); //copy(e[:], input[:]) - e[0] &= 248; - e[31] &= 127; - e[31] |= 64; + int swap = 0; + for (int pos = 254; pos >= 0; pos--) { + byte b = Convert.ToByte(e[pos / 8] >> (pos & 7)); + b &= 1; + swap ^= (int)(b); + FieldElement.CSwap(ref x2, ref x3, swap); + FieldElement.CSwap(ref z2, ref z3, swap); + swap = (int) (b); - FieldElement x1, x2, z2, x3, z3, tmp0, tmp1; - z2 = new FieldElement(); - // feFromBytes(&x1, base) - x1 = new FieldElement(baseIn); //SECOND NUMBER - //feOne(&x2) - x2 = new FieldElement(); - x2.One(); - //feCopy(&x3, &x1) - x3 = new FieldElement(); - FieldElement.Copy(ref x3,x1); - //feOne(&z3) - z3 = new FieldElement(); - z3.One(); + tmp0 = x3 - z3; //feSub(&tmp0, &x3, &z3) + tmp1 = x2 - z2; //feSub(&tmp1, &x2, &z2) + x2 += z2; //feAdd(&x2, &x2, &z2) + z2 = x3 + z3; //feAdd(&z2, &x3, &z3) + z3 = tmp0.Multiply(x2); + z2 = z2.Multiply(tmp1); + tmp0 = tmp1.Square(); + tmp1 = x2.Square(); + x3 = z3 + z2; //feAdd(&x3, &z3, &z2) + z2 = z3 - z2; //feSub(&z2, &z3, &z2) + x2 = tmp1.Multiply(tmp0); + tmp1 -= tmp0;//feSub(&tmp1, &tmp1, &tmp0) + z2 = z2.Square(); + z3 = tmp1.Mul121666(); + x3 = x3.Square(); + tmp0 += z3; //feAdd(&tmp0, &tmp0, &z3) + z3 = x1.Multiply(z2); + z2 = tmp1.Multiply(tmp0); + } - int swap = 0; - for (int pos = 254; pos >= 0; pos--) { - byte b = Convert.ToByte(e[pos / 8] >> (pos & 7)); - b &= 1; - swap ^= (int)(b); FieldElement.CSwap(ref x2, ref x3, swap); FieldElement.CSwap(ref z2, ref z3, swap); - swap = (int) (b); - tmp0 = x3 - z3; //feSub(&tmp0, &x3, &z3) - tmp1 = x2 - z2; //feSub(&tmp1, &x2, &z2) - x2 += z2; //feAdd(&x2, &x2, &z2) - z2 = x3 + z3; //feAdd(&z2, &x3, &z3) - z3 = tmp0.Multiply(x2); - z2 = z2.Multiply(tmp1); - tmp0 = tmp1.Square(); - tmp1 = x2.Square(); - x3 = z3 + z2; //feAdd(&x3, &z3, &z2) - z2 = z3 - z2; //feSub(&z2, &z3, &z2) - x2 = tmp1.Multiply(tmp0); - tmp1 -= tmp0;//feSub(&tmp1, &tmp1, &tmp0) - z2 = z2.Square(); - z3 = tmp1.Mul121666(); - x3 = x3.Square(); - tmp0 += z3; //feAdd(&tmp0, &tmp0, &z3) - z3 = x1.Multiply(z2); - z2 = tmp1.Multiply(tmp0); + z2 = z2.Invert(); + x2 = x2.Multiply(z2); + return x2.ToBytes(); + } + finally + { + Array.Clear(e, 0, e.Length); } - - FieldElement.CSwap(ref x2, ref x3, swap); - FieldElement.CSwap(ref z2, ref z3, swap); - - z2 = z2.Invert(); - x2 = x2.Multiply(z2); - return x2.ToBytes(); } /// /// X25519 returns the result of the scalar multiplication (scalar * point),