From d9c526408daf0c379a588d0a10e72ec71b490e0e Mon Sep 17 00:00:00 2001 From: royb Date: Wed, 28 Sep 2022 18:12:41 -0400 Subject: Added Kyber AES support --- crypto/src/pqc/crypto/crystals/kyber/CBD.cs | 4 +- .../src/pqc/crypto/crystals/kyber/KyberEngine.cs | 93 ++++++------ .../src/pqc/crypto/crystals/kyber/KyberIndCpa.cs | 103 ++++--------- .../pqc/crypto/crystals/kyber/KyberKEMExtractor.cs | 11 +- .../pqc/crypto/crystals/kyber/KyberKEMGenerator.cs | 25 ++-- .../crypto/crystals/kyber/KyberKeyPairGenerator.cs | 37 +++-- .../pqc/crypto/crystals/kyber/KyberParameters.cs | 29 ++-- .../crystals/kyber/KyberPrivateKeyParameters.cs | 20 ++- .../crystals/kyber/KyberPublicKeyParameters.cs | 20 ++- crypto/src/pqc/crypto/crystals/kyber/Poly.cs | 31 ++-- crypto/src/pqc/crypto/crystals/kyber/PolyVec.cs | 8 +- crypto/src/pqc/crypto/crystals/kyber/Symmetric.cs | 166 +++++++++++++++++++-- 12 files changed, 341 insertions(+), 206 deletions(-) (limited to 'crypto/src') diff --git a/crypto/src/pqc/crypto/crystals/kyber/CBD.cs b/crypto/src/pqc/crypto/crystals/kyber/CBD.cs index be0ed7296..e87edc007 100644 --- a/crypto/src/pqc/crypto/crystals/kyber/CBD.cs +++ b/crypto/src/pqc/crypto/crystals/kyber/CBD.cs @@ -21,7 +21,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber { short a = (short)((d >> (4 * j + 0)) & 0x3); short b = (short)((d >> (4 * j + eta)) & 0x3); - r.Coeffs[8 * i + j] = (short) (a - b); + r.m_coeffs[8 * i + j] = (short) (a - b); } } break; @@ -39,7 +39,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber { short a = (short)((d >> (6 * j + 0)) & 0x7); short b = (short)((d >> (6 * j + 3)) & 0x7); - r.Coeffs[4 * i + j] = (short)(a - b); + r.m_coeffs[4 * i + j] = (short)(a - b); } } break; diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberEngine.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberEngine.cs index 556803e57..bf9d5ee3c 100644 --- a/crypto/src/pqc/crypto/crystals/kyber/KyberEngine.cs +++ b/crypto/src/pqc/crypto/crystals/kyber/KyberEngine.cs @@ -1,6 +1,5 @@ using System; -using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; @@ -10,7 +9,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber { private SecureRandom m_random; private KyberIndCpa m_indCpa; - // Constant Parameters public const int N = 256; public const int Q = 3329; @@ -24,6 +22,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber public const int Eta2 = 2; public int IndCpaMsgBytes = SymBytes; + public Symmetric Symmetric { get; private set; } // Parameters @@ -45,7 +44,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber public int CryptoPublicKeyBytes { get; private set; } public int CryptoCipherTextBytes { get; private set; } - internal KyberEngine(int k) + public KyberEngine(int k, bool usingAes) { K = k; switch (k) @@ -65,8 +64,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber PolyCompressedBytes = 160; PolyVecCompressedBytes = K * 352; break; - default: - break; } PolyVecBytes = k * PolyBytes; @@ -83,6 +80,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber CryptoPublicKeyBytes = PublicKeyBytes; CryptoCipherTextBytes = CipherTextBytes; + if (usingAes) + { + Symmetric = new Symmetric.AesSymmetric(); + } + else + { + Symmetric = new Symmetric.ShakeSymmetric(); + } + m_indCpa = new KyberIndCpa(this); } @@ -91,83 +97,71 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber m_random = random; } - internal void UpdateSeed(byte[] seed) + internal void GenerateKemKeyPair(out byte[] t, out byte[] rho, out byte[] s, out byte[] hpk, out byte[] nonce) { - m_random.SetSeed(seed); - } + byte[] pk, sk; + m_indCpa.GenerateKeyPair(out pk, out sk); + s = Arrays.CopyOfRange(sk, 0, IndCpaSecretKeyBytes); + + hpk = new byte[32]; + Symmetric.Hash_h(hpk, pk, 0); + + nonce = new byte[SymBytes]; + m_random.NextBytes(nonce); + + t = Arrays.CopyOfRange(pk, 0, IndCpaPublicKeyBytes - 32); + rho = Arrays.CopyOfRange(pk, IndCpaPublicKeyBytes - 32, IndCpaPublicKeyBytes); - internal void GenerateKemKeyPair(byte[] pk, byte[] sk) - { - Sha3Digest Sha3Digest256 = new Sha3Digest(256); - m_indCpa.GenerateKeyPair(pk, sk); - Array.Copy(pk, 0, sk, IndCpaSecretKeyBytes, IndCpaPublicKeyBytes); - Sha3Digest256.BlockUpdate(pk, 0, PublicKeyBytes); - Sha3Digest256.DoFinal(sk, SecretKeyBytes - 2 * SymBytes); - m_random.NextBytes(sk, SecretKeyBytes - SymBytes, SymBytes); } internal void KemEncrypt(byte[] cipherText, byte[] sharedSecret, byte[] pk) { + byte[] randBytes = new byte[SymBytes]; byte[] buf = new byte[2 * SymBytes]; byte[] kr = new byte[2 * SymBytes]; - Sha3Digest Sha3Digest256 = new Sha3Digest(256); - - m_random.NextBytes(buf, 0, SymBytes); + m_random.NextBytes(randBytes, 0, SymBytes); - Sha3Digest256.BlockUpdate(buf, 0, SymBytes); - Sha3Digest256.DoFinal(buf, 0); + Symmetric.Hash_h(randBytes, randBytes, 0); + Array.Copy(randBytes, 0, buf, 0, SymBytes); - Sha3Digest256.BlockUpdate(pk, 0, PublicKeyBytes); - Sha3Digest256.DoFinal(buf, SymBytes); - - Sha3Digest Sha3Digest512 = new Sha3Digest(512); - Sha3Digest512.BlockUpdate(buf, 0, 2 * SymBytes); - Sha3Digest512.DoFinal(kr, 0); + Symmetric.Hash_h(buf, pk, SymBytes); + Symmetric.Hash_g(kr, buf); + m_indCpa.Encrypt(cipherText, Arrays.CopyOfRange(buf, 0, SymBytes), pk, Arrays.CopyOfRange(kr, SymBytes, 2 * SymBytes)); - Sha3Digest256.BlockUpdate(cipherText, 0, CipherTextBytes); - Sha3Digest256.DoFinal(kr, SymBytes); - ShakeDigest ShakeDigest128 = new ShakeDigest(256); - - ShakeDigest128.BlockUpdate(kr, 0, 2 * SymBytes); - ShakeDigest128.DoFinal(sharedSecret, 0, SymBytes); + Symmetric.Hash_h(kr, cipherText, SymBytes); + + Symmetric.Kdf(sharedSecret, kr); } internal void KemDecrypt(byte[] sharedSecret, byte[] cipherText, byte[] secretKey) { + int i; byte[] buf = new byte[2 * SymBytes], kr = new byte[2 * SymBytes], cmp = new byte[CipherTextBytes]; byte[] pk = Arrays.CopyOfRange(secretKey, IndCpaSecretKeyBytes, secretKey.Length); m_indCpa.Decrypt(buf, cipherText, secretKey); Array.Copy(secretKey, SecretKeyBytes - 2 * SymBytes, buf, SymBytes, SymBytes); - Sha3Digest Sha3Digest512 = new Sha3Digest(512); - Sha3Digest512.BlockUpdate(buf, 0, 2 * SymBytes); - Sha3Digest512.DoFinal(kr, 0); + Symmetric.Hash_g(kr, buf); + m_indCpa.Encrypt(cmp, Arrays.CopyOf(buf, SymBytes), pk, Arrays.CopyOfRange(kr, SymBytes, kr.Length)); bool fail = !Arrays.ConstantTimeAreEqual(cipherText, cmp); + + Symmetric.Hash_h(kr, cipherText, SymBytes); - Sha3Digest Sha3Digest256 = new Sha3Digest(256); - Sha3Digest256.BlockUpdate(cipherText, 0, CipherTextBytes); - Sha3Digest256.DoFinal(kr, SymBytes); CMov(kr, Arrays.CopyOfRange(secretKey, SecretKeyBytes - SymBytes, SecretKeyBytes), SymBytes, fail); - ShakeDigest ShakeDigest256 = new ShakeDigest(256); - ShakeDigest256.BlockUpdate(kr, 0, 2 * SymBytes); - ShakeDigest256.DoFinal(sharedSecret, 0, SymBytes); - } - - internal void RandomBytes(byte[] buf, int len) - { - m_random.NextBytes(buf, 0, len); + Symmetric.Kdf(sharedSecret, kr); } private void CMov(byte[] r, byte[] x, int len, bool b) { + int i; if (b) { Array.Copy(x, 0, r, 0, len); @@ -177,6 +171,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber Array.Copy(r, 0, r, 0, len); } } + + internal void RandomBytes(byte[] buf, int len) + { + m_random.NextBytes(buf,0,len); + } } } diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberIndCpa.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberIndCpa.cs index 1628ed90d..b3be4770d 100644 --- a/crypto/src/pqc/crypto/crystals/kyber/KyberIndCpa.cs +++ b/crypto/src/pqc/crypto/crystals/kyber/KyberIndCpa.cs @@ -1,6 +1,5 @@ using System; -using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber @@ -8,37 +7,35 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber internal class KyberIndCpa { private readonly KyberEngine m_engine; - - internal KyberIndCpa(KyberEngine engine) + private Symmetric m_symmetric; + internal KyberIndCpa(KyberEngine mEngine) { - m_engine = engine; + m_engine = mEngine; + m_symmetric = mEngine.Symmetric; } - - private int XofBlockBytes => Symmetric.Shake128Rate; - - private int GenerateMatrixNBlocks => ((12 * KyberEngine.N / 8 * (1 << 12) / KyberEngine.Q + XofBlockBytes) / XofBlockBytes); + + private int GenerateMatrixNBlocks => ((12 * KyberEngine.N / 8 * (1 << 12) / KyberEngine.Q + m_symmetric.XofBlockBytes) / m_symmetric.XofBlockBytes); private void GenerateMatrix(PolyVec[] a, byte[] seed, bool transposed) { int K = m_engine.K; - ShakeDigest shake128 = new ShakeDigest(128); - byte[] buf = new byte[GenerateMatrixNBlocks * XofBlockBytes + 2]; + byte[] buf = new byte[GenerateMatrixNBlocks * m_symmetric.XofBlockBytes + 2]; for (int i = 0; i < K; i++) { for (int j = 0; j < K; j++) { if (transposed) { - shake128 = Symmetric.Xof(seed, (byte) i, (byte) j); + m_symmetric.XofAbsorb(seed, (byte) i, (byte) j); } else { - shake128 = Symmetric.Xof(seed, (byte) j, (byte) i); + m_symmetric.XofAbsorb(seed, (byte) j, (byte) i); } - shake128.DoOutput(buf, 0, GenerateMatrixNBlocks * XofBlockBytes); - int buflen = GenerateMatrixNBlocks * XofBlockBytes; - int ctr = RejectionSampling(a[i].m_vec[j].Coeffs, 0, KyberEngine.N, buf, buflen); + m_symmetric.XofSqueezeBlocks(buf, 0, GenerateMatrixNBlocks * m_symmetric.XofBlockBytes); + int buflen = GenerateMatrixNBlocks * m_symmetric.XofBlockBytes; + int ctr = RejectionSampling(a[i].m_vec[j].m_coeffs, 0, KyberEngine.N, buf, buflen); while (ctr < KyberEngine.N) { int off = buflen % 3; @@ -46,13 +43,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber { buf[k] = buf[buflen - off + k]; } - shake128.DoOutput(buf, off, XofBlockBytes * 2); - buflen = off + XofBlockBytes; - ctr += RejectionSampling(a[i].m_vec[j].Coeffs, ctr, KyberEngine.N - ctr, buf, buflen); + m_symmetric.XofSqueezeBlocks(buf, off, m_symmetric.XofBlockBytes * 2); + buflen = off + m_symmetric.XofBlockBytes; + ctr += RejectionSampling(a[i].m_vec[j].m_coeffs, ctr, KyberEngine.N - ctr, buf, buflen); } } } + return; } private int RejectionSampling(short[] r, int off, int len, byte[] buf, int buflen) @@ -77,7 +75,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber return ctr; } - internal void GenerateKeyPair(byte[] pk, byte[] sk) + internal void GenerateKeyPair(out byte[] pk, out byte[] sk) { int K = m_engine.K; @@ -85,14 +83,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber byte nonce = 0; PolyVec[] Matrix = new PolyVec[K]; PolyVec e = new PolyVec(m_engine), pkpv = new PolyVec(m_engine), skpv = new PolyVec(m_engine); - Sha3Digest Sha3Digest512 = new Sha3Digest(512); - m_engine.RandomBytes(buf, KyberEngine.SymBytes); + byte[] d = new byte[32]; + m_engine.RandomBytes(d, 32); - Sha3Digest512.BlockUpdate(buf, 0, KyberEngine.SymBytes); - Sha3Digest512.DoFinal(buf, 0); + m_symmetric.Hash_g(buf, d); - //Console.WriteLine(string.Format("buf = {0}", Convert.ToHexString(buf))); byte[] PublicSeed = Arrays.CopyOfRange(buf, 0, KyberEngine.SymBytes); byte[] NoiseSeed = Arrays.CopyOfRange(buf, KyberEngine.SymBytes, 2 * KyberEngine.SymBytes); @@ -112,61 +108,26 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber { e.m_vec[i].GetNoiseEta1(NoiseSeed, nonce++); } - + skpv.Ntt(); e.Ntt(); - - //Console.WriteLine("skpv = "); - //for (int i = 0; i < K; i++) - //{ - // Console.Write(String.Format("{0} [", i)); - // foreach (short coeff in skpv.Vec[i].Coeffs) - // { - // Console.Write(String.Format("{0}, ", coeff)); - // } - // Console.Write("]\n"); - //} - - //for (int i = 0; i < K; i++) - //{ - // Console.Write("["); - // for (int j = 0; j < K; j++) - // { - // Console.Write("["); - // for (int k = 0; k < KyberEngine.N; k++) - // { - // Console.Write(String.Format("{0:G}, ", Matrix[i].Vec[j].Coeffs[k])); - // } - // Console.Write("], \n"); - // } - // Console.Write("] \n"); - //} - + for (int i = 0; i < K; i++) { PolyVec.PointwiseAccountMontgomery(pkpv.m_vec[i], Matrix[i], skpv, m_engine); pkpv.m_vec[i].ToMont(); } - - //Console.WriteLine("pkpv = "); - //for (int i = 0; i < K; i++) - //{ - // Console.Write(String.Format("{0} [", i)); - // foreach (short coeff in pkpv.Vec[i].Coeffs) - // { - // Console.Write(String.Format("{0}, ", coeff)); - // } - // Console.Write("]\n"); - //} + pkpv.Add(e); pkpv.Reduce(); - PackSecretKey(sk, skpv); - PackPublicKey(pk, pkpv, PublicSeed); + PackSecretKey(out sk, skpv); + PackPublicKey(out pk, pkpv, PublicSeed); } - private void PackSecretKey(byte[] sk, PolyVec skpv) + private void PackSecretKey(out byte[] sk, PolyVec skpv) { + sk = new byte[m_engine.PolyVecBytes]; skpv.ToBytes(sk); } @@ -175,26 +136,28 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber skpv.FromBytes(sk); } - private void PackPublicKey(byte[] pk, PolyVec pkpv, byte[] seed) + private void PackPublicKey(out byte[] pk, PolyVec pkpv, byte[] seed) { + int i; + pk = new byte[m_engine.IndCpaPublicKeyBytes]; pkpv.ToBytes(pk); Array.Copy(seed, 0, pk, m_engine.PolyVecBytes, KyberEngine.SymBytes); } private void UnpackPublicKey(PolyVec pkpv, byte[] seed, byte[] pk) { + int i; pkpv.FromBytes(pk); Array.Copy(pk, m_engine.PolyVecBytes, seed, 0, KyberEngine.SymBytes); } - internal void Encrypt(byte[] c, byte[] m, byte[] pk, byte[] coins) + public void Encrypt(byte[] c, byte[] m, byte[] pk, byte[] coins) { int K = m_engine.K; byte[] seed = new byte[KyberEngine.SymBytes]; byte nonce = 0; - PolyVec sp = new PolyVec(m_engine), pkpv = new PolyVec(m_engine), ep = new PolyVec(m_engine), - bp = new PolyVec(m_engine); + PolyVec sp = new PolyVec(m_engine), pkpv = new PolyVec(m_engine), ep = new PolyVec(m_engine), bp = new PolyVec(m_engine); PolyVec[] MatrixTransposed = new PolyVec[K]; Poly v = new Poly(m_engine), k = new Poly(m_engine), epp = new Poly(m_engine); diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberKEMExtractor.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberKEMExtractor.cs index a9f27c4ed..6dac60625 100644 --- a/crypto/src/pqc/crypto/crystals/kyber/KyberKEMExtractor.cs +++ b/crypto/src/pqc/crypto/crystals/kyber/KyberKEMExtractor.cs @@ -9,6 +9,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber private readonly KyberKeyParameters m_key; private readonly KyberEngine m_engine; + public KyberKemExtractor(KyberKeyParameters privParams) { m_key = privParams; @@ -17,13 +18,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber public byte[] ExtractSecret(byte[] encapsulation) { - byte[] sessionKey = new byte[m_engine.CryptoBytes]; - m_engine.KemDecrypt(sessionKey, encapsulation, ((KyberPrivateKeyParameters)m_key).m_privateKey); - byte[] rv = Arrays.CopyOfRange(sessionKey, 0, m_key.Parameters.DefaultKeySize / 8); - Arrays.Clear(sessionKey); - return rv; + byte[] sharedSecret = new byte[m_engine.CryptoBytes]; + m_engine.KemDecrypt(sharedSecret, encapsulation, ((KyberPrivateKeyParameters)m_key).GetEncoded()); + return sharedSecret; } public int EncapsulationLength => m_engine.CryptoCipherTextBytes; } -} +} \ No newline at end of file diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberKEMGenerator.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberKEMGenerator.cs index a0c070069..394890838 100644 --- a/crypto/src/pqc/crypto/crystals/kyber/KyberKEMGenerator.cs +++ b/crypto/src/pqc/crypto/crystals/kyber/KyberKEMGenerator.cs @@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber : IEncapsulatedSecretGenerator { // the source of randomness - private readonly SecureRandom m_random; + private SecureRandom m_random; public KyberKemGenerator(SecureRandom random) { @@ -19,15 +19,13 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber public ISecretWithEncapsulation GenerateEncapsulated(AsymmetricKeyParameter recipientKey) { - KyberPublicKeyParameters key = (KyberPublicKeyParameters)recipientKey; + KyberPublicKeyParameters key = (KyberPublicKeyParameters) recipientKey; KyberEngine engine = key.Parameters.Engine; engine.Init(m_random); byte[] cipherText = new byte[engine.CryptoCipherTextBytes]; byte[] sessionKey = new byte[engine.CryptoBytes]; - engine.KemEncrypt(cipherText, sessionKey, key.m_publicKey); - byte[] rv = Arrays.CopyOfRange(sessionKey, 0, key.Parameters.DefaultKeySize / 8); - Arrays.Clear(sessionKey); - return new SecretWithEncapsulationImpl(rv, cipherText); + engine.KemEncrypt(cipherText, sessionKey, key.GetEncoded()); + return new SecretWithEncapsulationImpl(sessionKey, cipherText); } private sealed class SecretWithEncapsulationImpl @@ -35,8 +33,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber { private volatile bool m_hasBeenDestroyed = false; - private readonly byte[] m_sessionKey; - private readonly byte[] m_cipherText; + private byte[] m_sessionKey; + private byte[] m_cipherText; internal SecretWithEncapsulationImpl(byte[] sessionKey, byte[] cipher_text) { @@ -68,13 +66,18 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber } } - internal bool IsDestroyed => m_hasBeenDestroyed; + internal bool IsDestroyed() + { + return m_hasBeenDestroyed; + } private void CheckDestroyed() { - if (IsDestroyed) + if (IsDestroyed()) + { throw new ArgumentException("data has been destroyed"); + } } } } -} +} \ No newline at end of file diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberKeyPairGenerator.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberKeyPairGenerator.cs index fde26f727..442944042 100644 --- a/crypto/src/pqc/crypto/crystals/kyber/KyberKeyPairGenerator.cs +++ b/crypto/src/pqc/crypto/crystals/kyber/KyberKeyPairGenerator.cs @@ -6,26 +6,37 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber public class KyberKeyPairGenerator : IAsymmetricCipherKeyPairGenerator { - private KyberKeyGenerationParameters m_kyberParams; - private SecureRandom m_random; + private KyberParameters KyberParams; + + private SecureRandom random; - public void Init(KeyGenerationParameters param) + private void Initialize( + KeyGenerationParameters param) { - m_kyberParams = (KyberKeyGenerationParameters)param; - m_random = param.Random; + this.KyberParams = ((KyberKeyGenerationParameters)param).Parameters;; + this.random = param.Random; } - public AsymmetricCipherKeyPair GenerateKeyPair() + private AsymmetricCipherKeyPair GenKeyPair() { - KyberEngine engine = m_kyberParams.Parameters.Engine; - engine.Init(m_random); - byte[] sk = new byte[engine.CryptoSecretKeyBytes]; - byte[] pk = new byte[engine.CryptoPublicKeyBytes]; - engine.GenerateKemKeyPair(pk, sk); + KyberEngine engine = KyberParams.Engine; + engine.Init(random); + byte[] s, hpk, nonce, t, rho; + engine.GenerateKemKeyPair(out t, out rho, out s, out hpk, out nonce); - KyberPublicKeyParameters pubKey = new KyberPublicKeyParameters(m_kyberParams.Parameters, pk); - KyberPrivateKeyParameters privKey = new KyberPrivateKeyParameters(m_kyberParams.Parameters, sk); + KyberPublicKeyParameters pubKey = new KyberPublicKeyParameters(KyberParams, t, rho); + KyberPrivateKeyParameters privKey = new KyberPrivateKeyParameters(KyberParams, s, hpk, nonce, t, rho); return new AsymmetricCipherKeyPair(pubKey, privKey); } + + public void Init(KeyGenerationParameters param) + { + this.Initialize(param); + } + + public AsymmetricCipherKeyPair GenerateKeyPair() + { + return GenKeyPair(); + } } } \ No newline at end of file diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberParameters.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberParameters.cs index ea9f90c98..f1a4ae921 100644 --- a/crypto/src/pqc/crypto/crystals/kyber/KyberParameters.cs +++ b/crypto/src/pqc/crypto/crystals/kyber/KyberParameters.cs @@ -1,31 +1,36 @@ using System; - using Org.BouncyCastle.Crypto; namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber { - public sealed class KyberParameters + public class KyberParameters : ICipherParameters { - public static KyberParameters kyber512 = new KyberParameters("kyber512", 2); - public static KyberParameters kyber768 = new KyberParameters("kyber768", 3); - public static KyberParameters kyber1024 = new KyberParameters("kyber1024", 4); - private string m_name; + public static KyberParameters kyber512 = new KyberParameters("kyber512", 2, 128, false); + public static KyberParameters kyber768 = new KyberParameters("kyber768", 3, 192, false); + public static KyberParameters kyber1024 = new KyberParameters("kyber1024", 4, 256, false); + public static KyberParameters kyber512_aes = new KyberParameters("kyber512-aes", 2, 128, true); + public static KyberParameters kyber768_aes = new KyberParameters("kyber768-aes", 3, 192, true); + public static KyberParameters kyber1024_aes = new KyberParameters("kyber1024-aes", 4, 256, true); + + + private String m_name; + private int m_sessionKeySize; private KyberEngine m_engine; - public KyberParameters(string name, int k) + public KyberParameters(String name, int k, int sessionKeySize, bool usingAes) { m_name = name; - m_engine = new KyberEngine(k); + this.m_sessionKeySize = sessionKeySize; + m_engine = new KyberEngine(k, usingAes); } - public string Name => m_name; + public String Name => m_name; public int K => m_engine.K; - - public int DefaultKeySize => 64 * m_engine.K; + public int SessionKeySize => m_sessionKeySize; internal KyberEngine Engine => m_engine; } -} +} \ No newline at end of file diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberPrivateKeyParameters.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberPrivateKeyParameters.cs index d58a59c40..ab355be54 100644 --- a/crypto/src/pqc/crypto/crystals/kyber/KyberPrivateKeyParameters.cs +++ b/crypto/src/pqc/crypto/crystals/kyber/KyberPrivateKeyParameters.cs @@ -2,20 +2,28 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber { - public sealed class KyberPrivateKeyParameters + public class KyberPrivateKeyParameters : KyberKeyParameters { - internal readonly byte[] m_privateKey; + private readonly byte[] m_s; + private readonly byte[] m_hpk; + private readonly byte[] m_nonce; + private readonly byte[] m_t; + private readonly byte[] m_rho; - public KyberPrivateKeyParameters(KyberParameters parameters, byte[] privateKey) + public KyberPrivateKeyParameters(KyberParameters parameters, byte[] s, byte[] hpk, byte[] nonce, byte[] t, byte[] rho) : base(true, parameters) { - m_privateKey = Arrays.Clone(privateKey); + m_s = Arrays.Clone(s); + m_hpk = Arrays.Clone(hpk); + m_nonce = Arrays.Clone(nonce); + m_t = Arrays.Clone(t); + m_rho = Arrays.Clone(rho); } public byte[] GetEncoded() { - return Arrays.Clone(m_privateKey); + return Arrays.ConcatenateAll(m_s, m_t, m_rho, m_hpk, m_nonce); } } -} +} \ No newline at end of file diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberPublicKeyParameters.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberPublicKeyParameters.cs index 02e467530..56d80f535 100644 --- a/crypto/src/pqc/crypto/crystals/kyber/KyberPublicKeyParameters.cs +++ b/crypto/src/pqc/crypto/crystals/kyber/KyberPublicKeyParameters.cs @@ -5,17 +5,27 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber public sealed class KyberPublicKeyParameters : KyberKeyParameters { - internal readonly byte[] m_publicKey; + private readonly byte[] m_t; + private readonly byte[] m_rho; - public KyberPublicKeyParameters(KyberParameters parameters, byte[] publicKey) + public byte[] GetEncoded() + { + return Arrays.Concatenate(m_t, m_rho); + } + + public KyberPublicKeyParameters(KyberParameters parameters, byte[] encoding) : base(false, parameters) { - m_publicKey = Arrays.Clone(publicKey); + m_t = Arrays.CopyOfRange(encoding, 0, encoding.Length - KyberEngine.SymBytes); + m_rho = Arrays.CopyOfRange(encoding, encoding.Length - KyberEngine.SymBytes, encoding.Length); } - public byte[] GetEncoded() + public KyberPublicKeyParameters(KyberParameters parameters, byte[] t, byte[] rho) + : base(false, parameters) { - return Arrays.Clone(m_publicKey); + m_t = Arrays.Clone(t); + m_rho = Arrays.Clone(rho); } } } + \ No newline at end of file diff --git a/crypto/src/pqc/crypto/crystals/kyber/Poly.cs b/crypto/src/pqc/crypto/crystals/kyber/Poly.cs index fc2f7ec70..db996f41a 100644 --- a/crypto/src/pqc/crypto/crystals/kyber/Poly.cs +++ b/crypto/src/pqc/crypto/crystals/kyber/Poly.cs @@ -1,31 +1,32 @@ -using System; + +using System; namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber { internal class Poly { - private short[] m_coeffs = new short[KyberEngine.N]; - private KyberEngine m_engine; - - internal Poly(KyberEngine engine) + public short[] m_coeffs = new short[KyberEngine.N]; + private Symmetric m_symmetric; + public Poly(KyberEngine mEngine) { - m_engine = engine; + m_engine = mEngine; + m_symmetric = mEngine.Symmetric; } - + internal short[] Coeffs => m_coeffs; internal void GetNoiseEta1(byte[] seed, byte nonce) { byte[] buf = new byte[m_engine.Eta1 * KyberEngine.N / 4]; - Symmetric.Prf(buf, buf.Length, seed, nonce); + m_symmetric.Prf(buf, seed, nonce); Cbd.Eta(this, buf, m_engine.Eta1); } internal void GetNoiseEta2(byte[] seed, byte nonce) { byte[] buf = new byte[KyberEngine.Eta2 * KyberEngine.N / 4]; - Symmetric.Prf(buf, buf.Length, seed, nonce); + m_symmetric.Prf(buf, seed, nonce); Cbd.Eta(this, buf, KyberEngine.Eta2); } @@ -76,7 +77,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber { for (int i = 0; i < KyberEngine.N; i++) { - Coeffs[i] = (short)(a.Coeffs[i] - Coeffs[i]); + Coeffs[i] = (short) (a.Coeffs[i] - Coeffs[i]); } } @@ -90,12 +91,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber internal void CompressPoly(byte[] r, int off) { -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - Span t = stackalloc byte[8]; -#else byte[] t = new byte[8]; -#endif - int count = 0; CondSubQ(); @@ -186,7 +182,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber throw new ArgumentException("PolyCompressedBytes is neither 128 or 160!"); } } - + internal void ToBytes(byte[] r, int off) { CondSubQ(); @@ -228,8 +224,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber internal void FromMsg(byte[] m) { if (m.Length != KyberEngine.N / 8) + { throw new ArgumentException("KYBER_INDCPA_MSGBYTES must be equal to KYBER_N/8 bytes!"); - + } for (int i = 0; i < KyberEngine.N / 8; i++) { for (int j = 0; j < 8; j++) diff --git a/crypto/src/pqc/crypto/crystals/kyber/PolyVec.cs b/crypto/src/pqc/crypto/crystals/kyber/PolyVec.cs index 5c92441b9..325b35e95 100644 --- a/crypto/src/pqc/crypto/crystals/kyber/PolyVec.cs +++ b/crypto/src/pqc/crypto/crystals/kyber/PolyVec.cs @@ -82,7 +82,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber t[k] = (short) ( ( - (((uint) m_vec[i].Coeffs[4 * j + k] << 10) + (((uint) m_vec[i].m_coeffs[4 * j + k] << 10) + (KyberEngine.Q / 2)) / KyberEngine.Q) & 0x3ff); @@ -113,7 +113,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber t[k] = (short) ( ( - (((uint) m_vec[i].Coeffs[8 * j + k] << 11) + (((uint) m_vec[i].m_coeffs[8 * j + k] << 11) + (KyberEngine.Q / 2)) / KyberEngine.Q) & 0x7ff); @@ -162,7 +162,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber count += 5; for (int k = 0; k < 4; k++) { - m_vec[i].Coeffs[4 * j + k] = (short)(((t[k] & 0x3FF) * KyberEngine.Q + 512) >> 10); + m_vec[i].m_coeffs[4 * j + k] = (short)(((t[k] & 0x3FF) * KyberEngine.Q + 512) >> 10); } } } @@ -190,7 +190,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber count += 11; for (int k = 0; k < 8; k++) { - m_vec[i].Coeffs[8 * j + k] = (short)(((t[k] & 0x7FF) * KyberEngine.Q + 1024) >> 11); + m_vec[i].m_coeffs[8 * j + k] = (short)(((t[k] & 0x7FF) * KyberEngine.Q + 1024) >> 11); } } } diff --git a/crypto/src/pqc/crypto/crystals/kyber/Symmetric.cs b/crypto/src/pqc/crypto/crystals/kyber/Symmetric.cs index d02990635..1ceb76b98 100644 --- a/crypto/src/pqc/crypto/crystals/kyber/Symmetric.cs +++ b/crypto/src/pqc/crypto/crystals/kyber/Symmetric.cs @@ -1,26 +1,166 @@ using Org.BouncyCastle.Crypto.Digests; +using System; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber { - internal static class Symmetric + public abstract class Symmetric { - internal const int Shake128Rate = 168; + internal readonly int XofBlockBytes; + + internal abstract void Hash_h(byte[] output, byte[] input, int outOffset); - internal static void Prf(byte[] outbuf, int outlen, byte[] key, byte nonce) + internal abstract void Hash_g(byte[] output, byte[] input); + + internal abstract void XofAbsorb(byte[] seed, byte x, byte y); + + internal abstract void XofSqueezeBlocks(byte[] output, int outOffset, int outLen); + + internal abstract void Prf(byte[] output, byte[] key, byte nonce); + + internal abstract void Kdf(byte[] output, byte[] input); + + Symmetric(int xofBlockBytes) + { + this.XofBlockBytes = xofBlockBytes; + } + + internal class ShakeSymmetric + : Symmetric { - ShakeDigest shake256 = new ShakeDigest(256); - shake256.BlockUpdate(key, 0, KyberEngine.SymBytes); - shake256.Update(nonce); - shake256.DoFinal(outbuf, 0, outlen); + private ShakeDigest xof; + private Sha3Digest sha3Digest512; + private Sha3Digest sha3Digest256; + private ShakeDigest shakeDigest; + + + internal ShakeSymmetric() + : base(164) + { + xof = new ShakeDigest(128); + shakeDigest = new ShakeDigest(256); + sha3Digest256 = new Sha3Digest(256); + sha3Digest512 = new Sha3Digest(512); + } + + internal override void Hash_h(byte[] output, byte[] input, int outOffset) + { + sha3Digest256.BlockUpdate(input, 0, input.Length); + sha3Digest256.DoFinal(output, outOffset); + } + + internal override void Hash_g(byte[] output, byte[] input) + { + sha3Digest512.BlockUpdate(input, 0, input.Length); + sha3Digest512.DoFinal(output, 0); + } + + internal override void XofAbsorb(byte[] seed, byte x, byte y) + { + xof.Reset(); + byte[] buf = new byte[seed.Length + 2]; + Array.Copy(seed, 0, buf, 0, seed.Length); + buf[seed.Length] = x; + buf[seed.Length + 1] = y; + xof.BlockUpdate(buf, 0, seed.Length + 2); + } + + internal override void XofSqueezeBlocks(byte[] output, int outOffset, int outLen) + { + xof.DoOutput(output, outOffset, outLen); + } + + internal override void Prf(byte[] output, byte[] seed, byte nonce) + { + byte[] extSeed = new byte[seed.Length + 1]; + Array.Copy(seed, 0, extSeed, 0, seed.Length); + extSeed[seed.Length] = nonce; + shakeDigest.BlockUpdate(extSeed, 0, extSeed.Length); + shakeDigest.DoFinal(output, 0, output.Length); + } + + internal override void Kdf(byte[] output, byte[] input) + { + shakeDigest.BlockUpdate(input, 0, input.Length); + shakeDigest.DoFinal(output, 0, output.Length); + } } - internal static ShakeDigest Xof(byte[] seed, byte a, byte b) + internal class AesSymmetric + : Symmetric { - ShakeDigest shake128 = new ShakeDigest(128); - shake128.BlockUpdate(seed, 0, seed.Length); - shake128.Update(a); - shake128.Update(b); - return shake128; + private Sha256Digest sha256Digest; + private Sha512Digest sha512Digest; + private SicBlockCipher cipher; + + internal AesSymmetric() + : base(64) + { + this.sha256Digest = new Sha256Digest(); + this.sha512Digest = new Sha512Digest(); + this.cipher = new SicBlockCipher(new AesEngine()); + } + private void DoDigest(IDigest digest, byte[] output, byte[] input, int outOffset) + { + digest.BlockUpdate(input, 0, input.Length); + digest.DoFinal(output, outOffset); + } + + private void Aes128(byte[] output, int offset, int size) + { + byte[] buf = new byte[size + offset]; // TODO: there might be a more efficient way of doing this... + for (int i = 0; i < size; i += 16) + { + cipher.ProcessBlock(buf, i + offset, output, i + offset); + } + } + + internal override void Hash_h(byte[] output, byte[] input, int outOffset) + { + DoDigest(sha256Digest, output, input, outOffset); + } + + internal override void Hash_g(byte[] output, byte[] input) + { + DoDigest(sha512Digest, output, input, 0); + } + + internal override void XofAbsorb(byte[] key, byte x, byte y) + { + byte[] expnonce = new byte[12]; + expnonce[0] = x; + expnonce[1] = y; + + ParametersWithIV kp = new ParametersWithIV(new KeyParameter(Arrays.CopyOfRange(key, 0, 32)), expnonce); + cipher.Init(true, kp); + } + + internal override void XofSqueezeBlocks(byte[] output, int outOffset, int outLen) + { + Aes128(output, outOffset, outLen); + } + + internal override void Prf(byte[] output, byte[] key, byte nonce) + { + byte[] expnonce = new byte[12]; + expnonce[0] = nonce; + + ParametersWithIV kp = new ParametersWithIV(new KeyParameter(Arrays.CopyOfRange(key, 0, 32)), expnonce); + cipher.Init(true, kp); + Aes128(output, 0, output.Length); + } + + internal override void Kdf(byte[] output, byte[] input) + { + byte[] buf = new byte[32]; + DoDigest(sha256Digest, buf, input, 0); + Array.Copy(buf, 0, output, 0, output.Length); + } } + } } -- cgit 1.4.1