summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-05-01 00:24:51 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-05-01 00:24:51 +0700
commitf0e8e9ce4dac3fc7fdbc18ea8e27a33001974a99 (patch)
treefb5a6ed66e3dd848dc4024e2d527bd4b6e6057ef
parentUse Longs.NumberOfTrailingZeros (diff)
downloadBouncyCastle.NET-ed25519-f0e8e9ce4dac3fc7fdbc18ea8e27a33001974a99.tar.xz
Frodo: add support to PQC factories
- refactoring
-rw-r--r--crypto/src/asn1/bc/BCObjectIdentifiers.cs14
-rw-r--r--crypto/src/pqc/crypto/frodo/FrodoEngine.cs16
-rw-r--r--crypto/src/pqc/crypto/frodo/FrodoKEMExtractor.cs27
-rw-r--r--crypto/src/pqc/crypto/frodo/FrodoKEMGenerator.cs11
-rw-r--r--crypto/src/pqc/crypto/frodo/FrodoKeyGenerationParameters.cs13
-rw-r--r--crypto/src/pqc/crypto/frodo/FrodoKeyPairGenerator.cs48
-rw-r--r--crypto/src/pqc/crypto/frodo/FrodoKeyParameters.cs2
-rw-r--r--crypto/src/pqc/crypto/frodo/FrodoParameters.cs87
-rw-r--r--crypto/src/pqc/crypto/frodo/FrodoPrivateKeyParameters.cs2
-rw-r--r--crypto/src/pqc/crypto/utils/PqcPrivateKeyFactory.cs8
-rw-r--r--crypto/src/pqc/crypto/utils/PqcPrivateKeyInfoFactory.cs14
-rw-r--r--crypto/src/pqc/crypto/utils/PqcPublicKeyFactory.cs23
-rw-r--r--crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs10
-rw-r--r--crypto/src/pqc/crypto/utils/PqcUtilities.cs82
-rw-r--r--crypto/test/src/pqc/crypto/test/FrodoVectorTest.cs32
15 files changed, 245 insertions, 144 deletions
diff --git a/crypto/src/asn1/bc/BCObjectIdentifiers.cs b/crypto/src/asn1/bc/BCObjectIdentifiers.cs
index d526980e5..face6f8d3 100644
--- a/crypto/src/asn1/bc/BCObjectIdentifiers.cs
+++ b/crypto/src/asn1/bc/BCObjectIdentifiers.cs
@@ -178,7 +178,19 @@ namespace Org.BouncyCastle.Asn1.BC
         public static readonly DerObjectIdentifier mceliece6960119f_r3 = pqc_kem_mceliece.Branch("8");
         public static readonly DerObjectIdentifier mceliece8192128_r3 = pqc_kem_mceliece.Branch("9");
         public static readonly DerObjectIdentifier mceliece8192128f_r3 = pqc_kem_mceliece.Branch("10");
-        
+
+        /**
+         * Frodo
+         */
+        public static readonly DerObjectIdentifier pqc_kem_frodo = bc_kem.Branch("2");
+
+        public static readonly DerObjectIdentifier frodokem640aes = pqc_kem_frodo.Branch("1");
+        public static readonly DerObjectIdentifier frodokem640shake = pqc_kem_frodo.Branch("2");
+        public static readonly DerObjectIdentifier frodokem976aes = pqc_kem_frodo.Branch("3");
+        public static readonly DerObjectIdentifier frodokem976shake = pqc_kem_frodo.Branch("4");
+        public static readonly DerObjectIdentifier frodokem1344aes = pqc_kem_frodo.Branch("5");
+        public static readonly DerObjectIdentifier frodokem1344shake = pqc_kem_frodo.Branch("6");
+
         /**
          * SABER
          */
diff --git a/crypto/src/pqc/crypto/frodo/FrodoEngine.cs b/crypto/src/pqc/crypto/frodo/FrodoEngine.cs
index 6aa3c8d89..905274cc3 100644
--- a/crypto/src/pqc/crypto/frodo/FrodoEngine.cs
+++ b/crypto/src/pqc/crypto/frodo/FrodoEngine.cs
@@ -59,6 +59,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Frodo
         public int PrivateKeySize => len_sk_bytes;
         public int PublicKeySize => len_pk_bytes;
 
+        // TODO[api] IDigest should be IXof?
         public FrodoEngine(int n, int D, int B, short[] cdf_table, IDigest digest, FrodoMatrixGenerator mGen)
         {
             this.n = n;
@@ -380,18 +381,17 @@ namespace Org.BouncyCastle.Pqc.Crypto.Frodo
             ((IXof) digest).OutputFinal(pkh, 0, len_pkh_bytes);
 
             // 3. seedSE || k = SHAKE(pkh || mu, len_seedSE + len_k) (length in bits)
-            byte[] seedSE_k = new byte[len_seedSE + len_k];
+            byte[] x96_seedSE_k = new byte[len_seedSE + len_k];
+            x96_seedSE_k[0] = 0x96;
+
             digest.BlockUpdate(pkh, 0, len_pkh_bytes);
             digest.BlockUpdate(mu, 0, len_mu_bytes);
-            ((IXof) digest).OutputFinal(seedSE_k, 0, len_seedSE_bytes + len_k_bytes);
-
-            byte[] seedSE = Arrays.CopyOfRange(seedSE_k, 0, len_seedSE_bytes);
-            byte[] k = Arrays.CopyOfRange(seedSE_k, len_seedSE_bytes, len_seedSE_bytes + len_k_bytes);
+            ((IXof) digest).OutputFinal(x96_seedSE_k, 1, len_seedSE_bytes + len_k_bytes);
 
             // 4. r = SHAKE(0x96 || seedSE, 2*mbar*n + mbar*nbar*len_chi) (length in bits)
             byte[] rbytes = new byte[(2 * mbar * n + mbar * nbar) * len_chi_bytes];
-            digest.Update((byte) 0x96);
-            digest.BlockUpdate(seedSE, 0, seedSE.Length);
+
+            digest.BlockUpdate(x96_seedSE_k, 0, 1 + len_seedSE_bytes);
             ((IXof) digest).OutputFinal(rbytes, 0, rbytes.Length);
 
             short[] r = new short[rbytes.Length / 2];
@@ -435,7 +435,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Frodo
             Array.Copy(Arrays.Concatenate(c1, c2), 0, ct, 0, len_ct_bytes);
             digest.BlockUpdate(c1, 0, c1.Length);
             digest.BlockUpdate(c2, 0, c2.Length);
-            digest.BlockUpdate(k, 0, len_k_bytes);
+            digest.BlockUpdate(x96_seedSE_k, 1 + len_seedSE_bytes, len_k_bytes);
             ((IXof) digest).OutputFinal(ss, 0, len_s_bytes);
         }
 
diff --git a/crypto/src/pqc/crypto/frodo/FrodoKEMExtractor.cs b/crypto/src/pqc/crypto/frodo/FrodoKEMExtractor.cs
index 8a26e90a4..a3805e39d 100644
--- a/crypto/src/pqc/crypto/frodo/FrodoKEMExtractor.cs
+++ b/crypto/src/pqc/crypto/frodo/FrodoKEMExtractor.cs
@@ -1,34 +1,29 @@
-
 using Org.BouncyCastle.Crypto;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Frodo
 {
-    
+    // TODO[api] FrodoKemExtractor
     public class FrodoKEMExtractor
             : IEncapsulatedSecretExtractor
     {
-        private FrodoEngine engine;
-
-        private FrodoKeyParameters key;
+        private readonly FrodoKeyParameters m_key;
+        private readonly FrodoEngine m_engine;
 
         public FrodoKEMExtractor(FrodoKeyParameters privParams)
         {
-            this.key = privParams;
-            InitCipher(key.Parameters);
-        }
-
-        private void InitCipher(FrodoParameters param)
-        {
-            engine = param.Engine;
+            m_key = privParams;
+#pragma warning disable CS0618 // Type or member is obsolete
+            m_engine = privParams.Parameters.Engine;
+#pragma warning restore CS0618 // Type or member is obsolete
         }
 
         public byte[] ExtractSecret(byte[] encapsulation)
         {
-            byte[] session_key = new byte[engine.SessionKeySize];
-            engine.kem_dec(session_key, encapsulation, ((FrodoPrivateKeyParameters)key).privateKey);
+            byte[] session_key = new byte[m_engine.SessionKeySize];
+            m_engine.kem_dec(session_key, encapsulation, ((FrodoPrivateKeyParameters)m_key).privateKey);
             return session_key;
         }
 
-        public int EncapsulationLength => (int)engine.CipherTextSize;
+        public int EncapsulationLength => m_engine.CipherTextSize;
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/frodo/FrodoKEMGenerator.cs b/crypto/src/pqc/crypto/frodo/FrodoKEMGenerator.cs
index 4cfde03fb..cf764ef25 100644
--- a/crypto/src/pqc/crypto/frodo/FrodoKEMGenerator.cs
+++ b/crypto/src/pqc/crypto/frodo/FrodoKEMGenerator.cs
@@ -4,24 +4,27 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Frodo
 {
+    // TODO[api] FrodoKemGenerator
     public class FrodoKEMGenerator
         : IEncapsulatedSecretGenerator
     {
         // the source of randomness
-        private readonly SecureRandom sr;
+        private readonly SecureRandom m_random;
 
         public FrodoKEMGenerator(SecureRandom random)
         {
-            this.sr = random;
+            m_random = random;
         }
 
         public ISecretWithEncapsulation GenerateEncapsulated(AsymmetricKeyParameter recipientKey)
         {
-            FrodoPublicKeyParameters key = (FrodoPublicKeyParameters) recipientKey;
+            FrodoPublicKeyParameters key = (FrodoPublicKeyParameters)recipientKey;
+#pragma warning disable CS0618 // Type or member is obsolete
             FrodoEngine engine = key.Parameters.Engine;
+#pragma warning restore CS0618 // Type or member is obsolete
             byte[] cipher_text = new byte[engine.CipherTextSize];
             byte[] sessionKey = new byte[engine.SessionKeySize];
-            engine.kem_enc(cipher_text, sessionKey, key.m_publicKey, sr);
+            engine.kem_enc(cipher_text, sessionKey, key.m_publicKey, m_random);
             return new SecretWithEncapsulationImpl(sessionKey, cipher_text);
         }
     }
diff --git a/crypto/src/pqc/crypto/frodo/FrodoKeyGenerationParameters.cs b/crypto/src/pqc/crypto/frodo/FrodoKeyGenerationParameters.cs
index 062441b8f..e10ee6395 100644
--- a/crypto/src/pqc/crypto/frodo/FrodoKeyGenerationParameters.cs
+++ b/crypto/src/pqc/crypto/frodo/FrodoKeyGenerationParameters.cs
@@ -1,4 +1,3 @@
-
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Security;
 
@@ -7,16 +6,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Frodo
     public class FrodoKeyGenerationParameters
         : KeyGenerationParameters
     {
-        private FrodoParameters parameters;
+        private readonly FrodoParameters m_parameters;
 
-        public FrodoKeyGenerationParameters(
-            SecureRandom random,
-            FrodoParameters frodoParameters)
+        public FrodoKeyGenerationParameters(SecureRandom random, FrodoParameters frodoParameters)
             : base(random, 256)
         {
-            this.parameters = frodoParameters;
+            m_parameters = frodoParameters;
         }
 
-        public FrodoParameters Parameters => parameters;
+        public FrodoParameters Parameters => m_parameters;
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/frodo/FrodoKeyPairGenerator.cs b/crypto/src/pqc/crypto/frodo/FrodoKeyPairGenerator.cs
index 464161444..c10087ea2 100644
--- a/crypto/src/pqc/crypto/frodo/FrodoKeyPairGenerator.cs
+++ b/crypto/src/pqc/crypto/frodo/FrodoKeyPairGenerator.cs
@@ -1,4 +1,3 @@
-
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Security;
 
@@ -7,46 +6,29 @@ namespace Org.BouncyCastle.Pqc.Crypto.Frodo
     public class FrodoKeyPairGenerator
         : IAsymmetricCipherKeyPairGenerator
     {
-        private FrodoKeyGenerationParameters frodoParams;
-
-        private int n;
-        private int D;
-        private int B;
+        private FrodoParameters m_parameters;
+        private SecureRandom m_random;
 
-        private SecureRandom random;
-
-        private void Initialize(
-            KeyGenerationParameters param)
+        public void Init(KeyGenerationParameters param)
         {
-            frodoParams = (FrodoKeyGenerationParameters) param;
-            random = param.Random;
+            FrodoKeyGenerationParameters frodoParams = (FrodoKeyGenerationParameters)param;
 
-            n = frodoParams.Parameters.N;
-            D = frodoParams.Parameters.D;
-            B = frodoParams.Parameters.B;
+            m_parameters = frodoParams.Parameters;
+            m_random = frodoParams.Random;
         }
 
-        private AsymmetricCipherKeyPair GenKeyPair()
+        public AsymmetricCipherKeyPair GenerateKeyPair()
         {
-            FrodoEngine engine = frodoParams.Parameters.Engine;
+#pragma warning disable CS0618 // Type or member is obsolete
+            FrodoEngine engine = m_parameters.Engine;
+#pragma warning restore CS0618 // Type or member is obsolete
             byte[] sk = new byte[engine.PrivateKeySize];
             byte[] pk = new byte[engine.PublicKeySize];
-            engine.kem_keypair(pk, sk, random);
-
-            FrodoPublicKeyParameters pubKey = new FrodoPublicKeyParameters(frodoParams.Parameters, pk);
-            FrodoPrivateKeyParameters privKey = new FrodoPrivateKeyParameters(frodoParams.Parameters, sk);
-            return new AsymmetricCipherKeyPair(pubKey, privKey);
-        }
+            engine.kem_keypair(pk, sk, m_random);
 
-        public void Init(KeyGenerationParameters param)
-        {
-            this.Initialize(param);
+            return new AsymmetricCipherKeyPair(
+                new FrodoPublicKeyParameters(m_parameters, pk),
+                new FrodoPrivateKeyParameters(m_parameters, sk));
         }
-
-        public AsymmetricCipherKeyPair GenerateKeyPair()
-        {
-            return GenKeyPair();
-        }
-
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/frodo/FrodoKeyParameters.cs b/crypto/src/pqc/crypto/frodo/FrodoKeyParameters.cs
index d195eba2b..4b9e4f1d9 100644
--- a/crypto/src/pqc/crypto/frodo/FrodoKeyParameters.cs
+++ b/crypto/src/pqc/crypto/frodo/FrodoKeyParameters.cs
@@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Frodo
         internal FrodoKeyParameters(bool isPrivate, FrodoParameters parameters)
             : base(isPrivate)
         {
-            this.m_parameters = parameters;
+            m_parameters = parameters;
         }
 
         public FrodoParameters Parameters => m_parameters;
diff --git a/crypto/src/pqc/crypto/frodo/FrodoParameters.cs b/crypto/src/pqc/crypto/frodo/FrodoParameters.cs
index 3f8fe254d..6f84f1b0c 100644
--- a/crypto/src/pqc/crypto/frodo/FrodoParameters.cs
+++ b/crypto/src/pqc/crypto/frodo/FrodoParameters.cs
@@ -1,35 +1,53 @@
+using System;
+
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Frodo
 {
     public sealed class FrodoParameters
         : ICipherParameters
     {
-        private static short[] cdf_table640  = {4643, 13363, 20579, 25843, 29227, 31145, 32103, 32525, 32689, 32745, 32762, 32766, 32767};
-        private static short[] cdf_table976  = {5638, 15915, 23689, 28571, 31116, 32217, 32613, 32731, 32760, 32766, 32767};
-        private static short[] cdf_table1344 = {9142, 23462, 30338, 32361, 32725, 32765, 32767};
-
-        public static FrodoParameters frodokem19888r3 = new FrodoParameters("frodokem19888", 640, 15, 2, cdf_table640, new ShakeDigest(128), new FrodoMatrixGenerator.Aes128MatrixGenerator(640, (1<<15)));
-        public static FrodoParameters frodokem19888shaker3 = new FrodoParameters("frodokem19888shake", 640, 15, 2, cdf_table640, new ShakeDigest(128), new FrodoMatrixGenerator.Shake128MatrixGenerator(640, (1<<15)));
-
-        public static FrodoParameters frodokem31296r3 = new FrodoParameters("frodokem31296", 976, 16, 3, cdf_table976, new ShakeDigest(256), new FrodoMatrixGenerator.Aes128MatrixGenerator(976, (1<<16)));
-        public static FrodoParameters frodokem31296shaker3 = new FrodoParameters("frodokem31296shake", 976, 16, 3, cdf_table976, new ShakeDigest(256), new FrodoMatrixGenerator.Shake128MatrixGenerator(976, (1<<16)));
-
-        public static FrodoParameters frodokem43088r3 = new FrodoParameters("frodokem43088", 1344, 16, 4, cdf_table1344, new ShakeDigest(256), new FrodoMatrixGenerator.Aes128MatrixGenerator(1344, (1<<16)));
-        public static FrodoParameters frodokem43088shaker3 = new FrodoParameters("frodokem43088shake", 1344, 16, 4, cdf_table1344, new ShakeDigest(256), new FrodoMatrixGenerator.Shake128MatrixGenerator(1344, (1<<16)));
-
-        private string name;
-        private int n;
-        private int d;
-        private int b;
-        private short[] cdf_table;
-        private IDigest digest;
-        private FrodoMatrixGenerator mGen;
-        private int defaultKeySize;
-        private FrodoEngine engine;
-
-        private FrodoParameters(string name, int n, int d, int b, short[] cdf_table, IDigest digest,
+        private static readonly short[] cdf_table640  = {4643, 13363, 20579, 25843, 29227, 31145, 32103, 32525, 32689, 32745, 32762, 32766, 32767};
+        private static readonly short[] cdf_table976  = {5638, 15915, 23689, 28571, 31116, 32217, 32613, 32731, 32760, 32766, 32767};
+        private static readonly short[] cdf_table1344 = {9142, 23462, 30338, 32361, 32725, 32765, 32767};
+
+        public static readonly FrodoParameters frodokem640aes = new FrodoParameters("frodokem19888", 640, 15, 2, cdf_table640, new ShakeDigest(128), new FrodoMatrixGenerator.Aes128MatrixGenerator(640, (1 << 15)));
+        public static readonly FrodoParameters frodokem640shake = new FrodoParameters("frodokem19888shake", 640, 15, 2, cdf_table640, new ShakeDigest(128), new FrodoMatrixGenerator.Shake128MatrixGenerator(640, (1 << 15)));
+
+        public static readonly FrodoParameters frodokem976aes = new FrodoParameters("frodokem31296", 976, 16, 3, cdf_table976, new ShakeDigest(256), new FrodoMatrixGenerator.Aes128MatrixGenerator(976, (1 << 16)));
+        public static readonly FrodoParameters frodokem976shake = new FrodoParameters("frodokem31296shake", 976, 16, 3, cdf_table976, new ShakeDigest(256), new FrodoMatrixGenerator.Shake128MatrixGenerator(976, (1 << 16)));
+
+        public static readonly FrodoParameters frodokem1344aes = new FrodoParameters("frodokem43088", 1344, 16, 4, cdf_table1344, new ShakeDigest(256), new FrodoMatrixGenerator.Aes128MatrixGenerator(1344, (1 << 16)));
+        public static readonly FrodoParameters frodokem1344shake = new FrodoParameters("frodokem43088shake", 1344, 16, 4, cdf_table1344, new ShakeDigest(256), new FrodoMatrixGenerator.Shake128MatrixGenerator(1344, (1 << 16)));
+
+        [Obsolete("Use 'frodokem640aes' instead")]
+        public static FrodoParameters frodokem19888r3 = frodokem640aes;
+        [Obsolete("Use 'frodokem640shake' instead")]
+        public static FrodoParameters frodokem19888shaker3 = frodokem640shake;
+
+        [Obsolete("Use 'frodokem976aes' instead")]
+        public static FrodoParameters frodokem31296r3 = frodokem976aes;
+        [Obsolete("Use 'frodokem976shake' instead")]
+        public static FrodoParameters frodokem31296shaker3 = frodokem976shake;
+
+        [Obsolete("Use 'frodokem1344aes' instead")]
+        public static FrodoParameters frodokem43088r3 = frodokem1344aes;
+        [Obsolete("Use 'frodokem1344shake' instead")]
+        public static FrodoParameters frodokem43088shaker3 = frodokem1344shake;
+
+        private readonly string name;
+        private readonly int n;
+        private readonly int d;
+        private readonly int b;
+        private readonly short[] cdf_table;
+        private readonly ShakeDigest digest;
+        private readonly FrodoMatrixGenerator mGen;
+        private readonly int defaultKeySize;
+        private readonly FrodoEngine engine;
+
+        private FrodoParameters(string name, int n, int d, int b, short[] cdf_table, ShakeDigest digest,
             FrodoMatrixGenerator mGen)
         {
             this.name = name;
@@ -39,26 +57,33 @@ namespace Org.BouncyCastle.Pqc.Crypto.Frodo
             this.cdf_table = cdf_table;
             this.digest = digest;
             this.mGen = mGen;
-            this.defaultKeySize = B * FrodoEngine.nbar * FrodoEngine.nbar;
+            this.defaultKeySize = b * FrodoEngine.nbar * FrodoEngine.nbar;
             this.engine = new FrodoEngine(n, d, b, cdf_table, digest, mGen);
         }
 
+        public string Name => name;
+
+        public int DefaultKeySize => defaultKeySize;
+
+        [Obsolete("Will be removed")]
         public FrodoEngine Engine => engine;
 
+        [Obsolete("Will be removed")]
         public int N => n;
 
-        public string Name => name;
-
+        [Obsolete("Will be removed")]
         public int D => d;
 
+        [Obsolete("Will be removed")]
         public int B => b;
 
-        public short[] CdfTable => cdf_table;
+        [Obsolete("Will be removed")]
+        public short[] CdfTable => Arrays.Clone(cdf_table);
 
-        public IDigest Digest => digest;
-
-        public int DefaultKeySize => defaultKeySize;
+        [Obsolete("Will be removed")]
+        public IDigest Digest => new ShakeDigest(digest);
 
+        [Obsolete("Will be removed")]
         public FrodoMatrixGenerator MGen => mGen;
     }
 } 
diff --git a/crypto/src/pqc/crypto/frodo/FrodoPrivateKeyParameters.cs b/crypto/src/pqc/crypto/frodo/FrodoPrivateKeyParameters.cs
index cfbf1c3ea..cc3d1e182 100644
--- a/crypto/src/pqc/crypto/frodo/FrodoPrivateKeyParameters.cs
+++ b/crypto/src/pqc/crypto/frodo/FrodoPrivateKeyParameters.cs
@@ -5,7 +5,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Frodo
     public sealed class FrodoPrivateKeyParameters
         : FrodoKeyParameters
     {
-        internal byte[] privateKey;
+        internal readonly byte[] privateKey;
 
         public FrodoPrivateKeyParameters(FrodoParameters parameters, byte[] privateKey)
             : base(true, parameters)
diff --git a/crypto/src/pqc/crypto/utils/PqcPrivateKeyFactory.cs b/crypto/src/pqc/crypto/utils/PqcPrivateKeyFactory.cs
index f01988169..01566c8b0 100644
--- a/crypto/src/pqc/crypto/utils/PqcPrivateKeyFactory.cs
+++ b/crypto/src/pqc/crypto/utils/PqcPrivateKeyFactory.cs
@@ -14,6 +14,7 @@ using Org.BouncyCastle.Pqc.Crypto.Cmce;
 using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium;
 using Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber;
 using Org.BouncyCastle.Pqc.Crypto.Falcon;
+using Org.BouncyCastle.Pqc.Crypto.Frodo;
 using Org.BouncyCastle.Pqc.Crypto.Hqc;
 using Org.BouncyCastle.Pqc.Crypto.Lms;
 using Org.BouncyCastle.Pqc.Crypto.Picnic;
@@ -78,6 +79,13 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
 
                 return new CmcePrivateKeyParameters(spParams, cmceKey.Delta, cmceKey.C, cmceKey.G, cmceKey.Alpha, cmceKey.S);
             }
+            if (algOID.On(BCObjectIdentifiers.pqc_kem_frodo))
+            {
+                byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets();
+                FrodoParameters spParams = PqcUtilities.FrodoParamsLookup(keyInfo.PrivateKeyAlgorithm.Algorithm);
+
+                return new FrodoPrivateKeyParameters(spParams, keyEnc);
+            }
             if (algOID.On(BCObjectIdentifiers.sphincsPlus))
             {
                 byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets();
diff --git a/crypto/src/pqc/crypto/utils/PqcPrivateKeyInfoFactory.cs b/crypto/src/pqc/crypto/utils/PqcPrivateKeyInfoFactory.cs
index 3d1b1b679..6f7bed2ca 100644
--- a/crypto/src/pqc/crypto/utils/PqcPrivateKeyInfoFactory.cs
+++ b/crypto/src/pqc/crypto/utils/PqcPrivateKeyInfoFactory.cs
@@ -10,6 +10,7 @@ using Org.BouncyCastle.Pqc.Crypto.Cmce;
 using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium;
 using Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber;
 using Org.BouncyCastle.Pqc.Crypto.Falcon;
+using Org.BouncyCastle.Pqc.Crypto.Frodo;
 using Org.BouncyCastle.Pqc.Crypto.Hqc;
 using Org.BouncyCastle.Pqc.Crypto.Lms;
 using Org.BouncyCastle.Pqc.Crypto.Picnic;
@@ -67,8 +68,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             if (privateKey is CmcePrivateKeyParameters cmcePrivateKeyParameters)
             {
                 byte[] encoding = cmcePrivateKeyParameters.GetEncoded();
-                AlgorithmIdentifier algorithmIdentifier =
-                    new AlgorithmIdentifier(PqcUtilities.McElieceOidLookup(cmcePrivateKeyParameters.Parameters));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.McElieceOidLookup(cmcePrivateKeyParameters.Parameters));
 
                 CmcePublicKey CmcePub = new CmcePublicKey(cmcePrivateKeyParameters.ReconstructPublicKey());
                 CmcePrivateKey CmcePriv = new CmcePrivateKey(0, cmcePrivateKeyParameters.Delta,
@@ -76,6 +77,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
                     cmcePrivateKeyParameters.S, CmcePub);
                 return new PrivateKeyInfo(algorithmIdentifier, CmcePriv, attributes);
             }
+            if (privateKey is FrodoPrivateKeyParameters frodoPrivateKeyParameters)
+            {
+                byte[] encoding = frodoPrivateKeyParameters.GetEncoded();
+
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.FrodoOidLookup(frodoPrivateKeyParameters.Parameters));
+
+                return new PrivateKeyInfo(algorithmIdentifier, new DerOctetString(encoding), attributes);
+            }
             if (privateKey is SaberPrivateKeyParameters saberPrivateKeyParameters)
             {
                 byte[] encoding = saberPrivateKeyParameters.GetEncoded();
diff --git a/crypto/src/pqc/crypto/utils/PqcPublicKeyFactory.cs b/crypto/src/pqc/crypto/utils/PqcPublicKeyFactory.cs
index 909b93577..899ebc28e 100644
--- a/crypto/src/pqc/crypto/utils/PqcPublicKeyFactory.cs
+++ b/crypto/src/pqc/crypto/utils/PqcPublicKeyFactory.cs
@@ -14,6 +14,7 @@ using Org.BouncyCastle.Pqc.Crypto.Cmce;
 using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium;
 using Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber;
 using Org.BouncyCastle.Pqc.Crypto.Falcon;
+using Org.BouncyCastle.Pqc.Crypto.Frodo;
 using Org.BouncyCastle.Pqc.Crypto.Hqc;
 using Org.BouncyCastle.Pqc.Crypto.Lms;
 using Org.BouncyCastle.Pqc.Crypto.Picnic;
@@ -49,7 +50,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             Converters[BCObjectIdentifiers.mceliece6960119f_r3] = new CmceConverter();
             Converters[BCObjectIdentifiers.mceliece8192128_r3] = new CmceConverter();
             Converters[BCObjectIdentifiers.mceliece8192128f_r3] = new CmceConverter();
-           
+
+            Converters[BCObjectIdentifiers.frodokem640aes] = new FrodoConverter();
+            Converters[BCObjectIdentifiers.frodokem640shake] = new FrodoConverter();
+            Converters[BCObjectIdentifiers.frodokem976aes] = new FrodoConverter();
+            Converters[BCObjectIdentifiers.frodokem976shake] = new FrodoConverter();
+            Converters[BCObjectIdentifiers.frodokem1344aes] = new FrodoConverter();
+            Converters[BCObjectIdentifiers.frodokem1344shake] = new FrodoConverter();
+
             Converters[BCObjectIdentifiers.lightsaberkem128r3] = new SaberConverter();
             Converters[BCObjectIdentifiers.saberkem128r3] = new SaberConverter();
             Converters[BCObjectIdentifiers.firesaberkem128r3] = new SaberConverter();
@@ -217,6 +225,19 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             }
         }
 
+        private class FrodoConverter
+            : SubjectPublicKeyInfoConverter
+        {
+            internal override AsymmetricKeyParameter GetPublicKeyParameters(SubjectPublicKeyInfo keyInfo, object defaultParams)
+            {
+                byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets();
+
+                FrodoParameters fParams = PqcUtilities.FrodoParamsLookup(keyInfo.AlgorithmID.Algorithm);
+
+                return new FrodoPublicKeyParameters(fParams, keyEnc);
+            }
+        }
+
         private class SaberConverter
             : SubjectPublicKeyInfoConverter
         {
diff --git a/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs b/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs
index c13255c68..1bdf031f6 100644
--- a/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs
+++ b/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs
@@ -10,6 +10,7 @@ using Org.BouncyCastle.Pqc.Crypto.Cmce;
 using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium;
 using Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber;
 using Org.BouncyCastle.Pqc.Crypto.Falcon;
+using Org.BouncyCastle.Pqc.Crypto.Frodo;
 using Org.BouncyCastle.Pqc.Crypto.Hqc;
 using Org.BouncyCastle.Pqc.Crypto.Lms;
 using Org.BouncyCastle.Pqc.Crypto.Picnic;
@@ -71,6 +72,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
                 // https://datatracker.ietf.org/doc/draft-uni-qsckeys/
                 return new SubjectPublicKeyInfo(algorithmIdentifier, new CmcePublicKey(encoding));
             }
+            else if (publicKey is FrodoPublicKeyParameters frodoPublicKeyParameters)
+            {
+                byte[] encoding = frodoPublicKeyParameters.GetEncoded();
+
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.FrodoOidLookup(frodoPublicKeyParameters.Parameters));
+
+                return new SubjectPublicKeyInfo(algorithmIdentifier, new DerOctetString(encoding));
+            }
             if (publicKey is SaberPublicKeyParameters saberPublicKeyParameters)
             {
                 byte[] encoding = saberPublicKeyParameters.GetEncoded();
diff --git a/crypto/src/pqc/crypto/utils/PqcUtilities.cs b/crypto/src/pqc/crypto/utils/PqcUtilities.cs
index 67e58fd28..101e3c846 100644
--- a/crypto/src/pqc/crypto/utils/PqcUtilities.cs
+++ b/crypto/src/pqc/crypto/utils/PqcUtilities.cs
@@ -7,11 +7,13 @@ using Org.BouncyCastle.Pqc.Crypto.Cmce;
 using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium;
 using Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber;
 using Org.BouncyCastle.Pqc.Crypto.Falcon;
+using Org.BouncyCastle.Pqc.Crypto.Frodo;
 using Org.BouncyCastle.Pqc.Crypto.Hqc;
 using Org.BouncyCastle.Pqc.Crypto.Picnic;
 using Org.BouncyCastle.Pqc.Crypto.Saber;
 using Org.BouncyCastle.Pqc.Crypto.Sike;
 using Org.BouncyCastle.Pqc.Crypto.SphincsPlus;
+using Org.BouncyCastle.Utilities.Collections;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Utilities
 {
@@ -19,7 +21,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
     {
         private readonly static Dictionary<CmceParameters, DerObjectIdentifier> mcElieceOids = new Dictionary<CmceParameters, DerObjectIdentifier>();
         private readonly static Dictionary<DerObjectIdentifier, CmceParameters> mcElieceParams = new Dictionary<DerObjectIdentifier, CmceParameters>();
-        
+
+        private readonly static Dictionary<FrodoParameters, DerObjectIdentifier> frodoOids = new Dictionary<FrodoParameters, DerObjectIdentifier>();
+        private readonly static Dictionary<DerObjectIdentifier, FrodoParameters> frodoParams = new Dictionary<DerObjectIdentifier, FrodoParameters>();
+
         private readonly static Dictionary<SaberParameters, DerObjectIdentifier> saberOids = new Dictionary<SaberParameters, DerObjectIdentifier>();
         private readonly static Dictionary<DerObjectIdentifier, SaberParameters> saberParams = new Dictionary<DerObjectIdentifier, SaberParameters>();
 
@@ -70,7 +75,21 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             mcElieceParams[BCObjectIdentifiers.mceliece6960119f_r3] = CmceParameters.mceliece6960119fr3;
             mcElieceParams[BCObjectIdentifiers.mceliece8192128_r3] = CmceParameters.mceliece8192128r3;
             mcElieceParams[BCObjectIdentifiers.mceliece8192128f_r3] = CmceParameters.mceliece8192128fr3;
-            
+
+            frodoOids[FrodoParameters.frodokem640aes] = BCObjectIdentifiers.frodokem640aes;
+            frodoOids[FrodoParameters.frodokem640shake] = BCObjectIdentifiers.frodokem640shake;
+            frodoOids[FrodoParameters.frodokem976aes] = BCObjectIdentifiers.frodokem976aes;
+            frodoOids[FrodoParameters.frodokem976shake] = BCObjectIdentifiers.frodokem976shake;
+            frodoOids[FrodoParameters.frodokem1344aes] = BCObjectIdentifiers.frodokem1344aes;
+            frodoOids[FrodoParameters.frodokem1344shake] = BCObjectIdentifiers.frodokem1344shake;
+
+            frodoParams[BCObjectIdentifiers.frodokem640aes] = FrodoParameters.frodokem640aes;
+            frodoParams[BCObjectIdentifiers.frodokem640shake] = FrodoParameters.frodokem640shake;
+            frodoParams[BCObjectIdentifiers.frodokem976aes] = FrodoParameters.frodokem976aes;
+            frodoParams[BCObjectIdentifiers.frodokem976shake] = FrodoParameters.frodokem976shake;
+            frodoParams[BCObjectIdentifiers.frodokem1344aes] = FrodoParameters.frodokem1344aes;
+            frodoParams[BCObjectIdentifiers.frodokem1344shake] = FrodoParameters.frodokem1344shake;
+
             saberOids[SaberParameters.lightsaberkem128r3] = BCObjectIdentifiers.lightsaberkem128r3;
             saberOids[SaberParameters.saberkem128r3] = BCObjectIdentifiers.saberkem128r3;
             saberOids[SaberParameters.firesaberkem128r3] = BCObjectIdentifiers.firesaberkem128r3;
@@ -209,45 +228,62 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
 
         internal static DerObjectIdentifier McElieceOidLookup(CmceParameters parameters)
         {
-            return mcElieceOids[parameters];
+            return CollectionUtilities.GetValueOrNull(mcElieceOids, parameters);
         }
 
         internal static CmceParameters McElieceParamsLookup(DerObjectIdentifier oid)
         {
-            return mcElieceParams[oid];
+            return CollectionUtilities.GetValueOrNull(mcElieceParams, oid);
+        }
+
+        internal static DerObjectIdentifier FrodoOidLookup(FrodoParameters parameters)
+        {
+            return CollectionUtilities.GetValueOrNull(frodoOids, parameters);
+        }
+
+        internal static FrodoParameters FrodoParamsLookup(DerObjectIdentifier oid)
+        {
+            return CollectionUtilities.GetValueOrNull(frodoParams, oid);
         }
-        
+
         internal static DerObjectIdentifier SaberOidLookup(SaberParameters parameters)
         {
-            return saberOids[parameters];
+            return CollectionUtilities.GetValueOrNull(saberOids, parameters);
         }
+
         internal static SaberParameters SaberParamsLookup(DerObjectIdentifier oid)
         {
-            return saberParams[oid];
+            return CollectionUtilities.GetValueOrNull(saberParams, oid);
         }
+
         internal static KyberParameters KyberParamsLookup(DerObjectIdentifier oid)
         {
-            return kyberParams[oid];
-        }       
+            return CollectionUtilities.GetValueOrNull(kyberParams, oid);
+        }
+
         internal static DerObjectIdentifier KyberOidLookup(KyberParameters parameters)
         {
-            return kyberOids[parameters];
+            return CollectionUtilities.GetValueOrNull(kyberOids, parameters);
         }
+
         internal static FalconParameters FalconParamsLookup(DerObjectIdentifier oid)
         {
-            return falconParams[oid];
+            return CollectionUtilities.GetValueOrNull(falconParams, oid);
         }       
+
         internal static DerObjectIdentifier FalconOidLookup(FalconParameters parameters)
         {
-            return falconOids[parameters];
+            return CollectionUtilities.GetValueOrNull(falconOids, parameters);
         }
+
         internal static DilithiumParameters DilithiumParamsLookup(DerObjectIdentifier oid)
         {
-            return dilithiumParams[oid];
-        }       
+            return CollectionUtilities.GetValueOrNull(dilithiumParams, oid);
+        }
+
         internal static DerObjectIdentifier DilithiumOidLookup(DilithiumParameters parameters)
         {
-            return dilithiumOids[parameters];
+            return CollectionUtilities.GetValueOrNull(dilithiumOids, parameters);
         }
 
         internal static DerObjectIdentifier SphincsPlusOidLookup(SphincsPlusParameters parameters)
@@ -265,44 +301,44 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
 
         internal static DerObjectIdentifier PicnicOidLookup(PicnicParameters parameters)
         {
-            return picnicOids[parameters];
+            return CollectionUtilities.GetValueOrNull(picnicOids, parameters);
         }
 
         internal static PicnicParameters PicnicParamsLookup(DerObjectIdentifier oid)
         {
-            return picnicParams[oid];
+            return CollectionUtilities.GetValueOrNull(picnicParams, oid);
         }
 
 #pragma warning disable CS0618 // Type or member is obsolete
         internal static DerObjectIdentifier SikeOidLookup(SikeParameters parameters)
         {
-            return sikeOids[parameters];
+            return CollectionUtilities.GetValueOrNull(sikeOids, parameters);
         }
 
         internal static SikeParameters SikeParamsLookup(DerObjectIdentifier oid)
         {
-            return sikeParams[oid];
+            return CollectionUtilities.GetValueOrNull(sikeParams, oid);
         }
 #pragma warning restore CS0618 // Type or member is obsolete
 
         internal static DerObjectIdentifier BikeOidLookup(BikeParameters parameters)
         {
-            return bikeOids[parameters];
+            return CollectionUtilities.GetValueOrNull(bikeOids, parameters);
         }
 
         internal static BikeParameters BikeParamsLookup(DerObjectIdentifier oid)
         {
-            return bikeParams[oid];
+            return CollectionUtilities.GetValueOrNull(bikeParams, oid);
         }
 
         internal static DerObjectIdentifier HqcOidLookup(HqcParameters parameters)
         {
-            return hqcOids[parameters];
+            return CollectionUtilities.GetValueOrNull(hqcOids, parameters);
         }
 
         internal static HqcParameters HqcParamsLookup(DerObjectIdentifier oid)
         {
-            return hqcParams[oid];
+            return CollectionUtilities.GetValueOrNull(hqcParams, oid);
         }
     }
 }
diff --git a/crypto/test/src/pqc/crypto/test/FrodoVectorTest.cs b/crypto/test/src/pqc/crypto/test/FrodoVectorTest.cs
index a8133e524..a67424887 100644
--- a/crypto/test/src/pqc/crypto/test/FrodoVectorTest.cs
+++ b/crypto/test/src/pqc/crypto/test/FrodoVectorTest.cs
@@ -1,4 +1,3 @@
-using System;
 using System.Collections.Generic;
 using System.IO;
 
@@ -6,6 +5,7 @@ using NUnit.Framework;
 
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Pqc.Crypto.Frodo;
+using Org.BouncyCastle.Pqc.Crypto.Utilities;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Encoders;
 using Org.BouncyCastle.Utilities.Test;
@@ -17,12 +17,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Tests
     {
         private static readonly Dictionary<string, FrodoParameters> Parameters = new Dictionary<string, FrodoParameters>()
         {
-            { "PQCkemKAT_19888.rsp", FrodoParameters.frodokem19888r3 },
-            { "PQCkemKAT_31296.rsp", FrodoParameters.frodokem31296r3 },
-            { "PQCkemKAT_43088.rsp", FrodoParameters.frodokem43088r3 },
-            { "PQCkemKAT_19888_shake.rsp", FrodoParameters.frodokem19888shaker3 },
-            { "PQCkemKAT_31296_shake.rsp", FrodoParameters.frodokem31296shaker3 },
-            { "PQCkemKAT_43088_shake.rsp", FrodoParameters.frodokem43088shaker3 },
+            { "PQCkemKAT_19888.rsp", FrodoParameters.frodokem640aes },
+            { "PQCkemKAT_31296.rsp", FrodoParameters.frodokem976aes },
+            { "PQCkemKAT_43088.rsp", FrodoParameters.frodokem1344aes },
+            { "PQCkemKAT_19888_shake.rsp", FrodoParameters.frodokem640shake },
+            { "PQCkemKAT_31296_shake.rsp", FrodoParameters.frodokem976shake },
+            { "PQCkemKAT_43088_shake.rsp", FrodoParameters.frodokem1344shake },
         };
 
         private static readonly string[] TestVectorFilesAes =
@@ -42,12 +42,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Tests
         [Test]
         public void TestParameters()
         {
-            Assert.AreEqual(128, FrodoParameters.frodokem19888r3.DefaultKeySize);
-            Assert.AreEqual(128, FrodoParameters.frodokem19888shaker3.DefaultKeySize);
-            Assert.AreEqual(192, FrodoParameters.frodokem31296r3.DefaultKeySize);
-            Assert.AreEqual(192, FrodoParameters.frodokem31296shaker3.DefaultKeySize);
-            Assert.AreEqual(256, FrodoParameters.frodokem43088r3.DefaultKeySize);
-            Assert.AreEqual(256, FrodoParameters.frodokem43088shaker3.DefaultKeySize);
+            Assert.AreEqual(128, FrodoParameters.frodokem640aes.DefaultKeySize);
+            Assert.AreEqual(128, FrodoParameters.frodokem640shake.DefaultKeySize);
+            Assert.AreEqual(192, FrodoParameters.frodokem976aes.DefaultKeySize);
+            Assert.AreEqual(192, FrodoParameters.frodokem976shake.DefaultKeySize);
+            Assert.AreEqual(256, FrodoParameters.frodokem1344aes.DefaultKeySize);
+            Assert.AreEqual(256, FrodoParameters.frodokem1344shake.DefaultKeySize);
         }
 
         [TestCaseSource(nameof(TestVectorFilesAes))]
@@ -84,8 +84,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Tests
             kpGen.Init(genParams);
             AsymmetricCipherKeyPair kp = kpGen.GenerateKeyPair();
 
-            FrodoPublicKeyParameters pubParams = (FrodoPublicKeyParameters)kp.Public;
-            FrodoPrivateKeyParameters privParams = (FrodoPrivateKeyParameters)kp.Private;
+            FrodoPublicKeyParameters pubParams = (FrodoPublicKeyParameters)PqcPublicKeyFactory.CreateKey(
+                PqcSubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo((FrodoPublicKeyParameters)kp.Public));
+            FrodoPrivateKeyParameters privParams = (FrodoPrivateKeyParameters)PqcPrivateKeyFactory.CreateKey(
+                PqcPrivateKeyInfoFactory.CreatePrivateKeyInfo((FrodoPrivateKeyParameters)kp.Private));
 
             Assert.True(Arrays.AreEqual(pk, pubParams.GetPublicKey()), $"{name} {count} : public key");
             Assert.True(Arrays.AreEqual(sk, privParams.GetPrivateKey()), $"{name} {count} : secret key");