summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Hook <dgh@cryptoworkshop.com>2020-04-25 16:53:47 +1000
committerDavid Hook <dgh@cryptoworkshop.com>2020-04-25 16:53:47 +1000
commit99467b8431c1a871792ecb34fd5eeb962353b1d2 (patch)
tree043b017ad8dd740c71e8f0661a170109672b6bb6
parentgithub #237 - gost 2012 parsing (diff)
downloadBouncyCastle.NET-ed25519-99467b8431c1a871792ecb34fd5eeb962353b1d2.tar.xz
first cut at PKCS#5 Scheme 2 in PKCS#12
-rw-r--r--crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs38
-rw-r--r--crypto/src/pkcs/PKCS12StoreBuilder.cs11
-rw-r--r--crypto/src/pkcs/Pkcs12Store.cs34
-rw-r--r--crypto/src/security/PbeUtilities.cs30
4 files changed, 108 insertions, 5 deletions
diff --git a/crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs b/crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs
index b6b7bac65..000eb7ae5 100644
--- a/crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs
+++ b/crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs
@@ -60,5 +60,43 @@ namespace Org.BouncyCastle.Pkcs
             AlgorithmIdentifier algID = new AlgorithmIdentifier(oid, pbeParameters);
             return new EncryptedPrivateKeyInfo(algID, encoding);
         }
+
+        public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo(
+            DerObjectIdentifier cipherAlgorithm,
+            DerObjectIdentifier prfAlgorithm,
+            char[] passPhrase,
+            byte[] salt,
+            int iterationCount,
+            SecureRandom random,
+            AsymmetricKeyParameter key)
+        {
+            return CreateEncryptedPrivateKeyInfo(
+                cipherAlgorithm, prfAlgorithm, passPhrase, salt, iterationCount, random,
+                PrivateKeyInfoFactory.CreatePrivateKeyInfo(key));
+        }
+
+        public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo(
+            DerObjectIdentifier cipherAlgorithm,
+            DerObjectIdentifier prfAlgorithm,
+            char[] passPhrase,
+            byte[] salt,
+            int iterationCount,
+            SecureRandom random,
+            PrivateKeyInfo keyInfo)
+        {
+            IBufferedCipher cipher = CipherUtilities.GetCipher(cipherAlgorithm) as IBufferedCipher;
+            if (cipher == null)
+                throw new Exception("Unknown encryption algorithm: " + cipherAlgorithm);
+
+            Asn1Encodable pbeParameters = PbeUtilities.GenerateAlgorithmParameters(
+                cipherAlgorithm, prfAlgorithm, salt, iterationCount, random);
+            ICipherParameters cipherParameters = PbeUtilities.GenerateCipherParameters(
+                PkcsObjectIdentifiers.IdPbeS2, passPhrase, pbeParameters);
+            cipher.Init(true, cipherParameters);
+            byte[] encoding = cipher.DoFinal(keyInfo.GetEncoded());
+
+            AlgorithmIdentifier algID = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPbeS2, pbeParameters);
+            return new EncryptedPrivateKeyInfo(algID, encoding);
+        }
     }
 }
diff --git a/crypto/src/pkcs/PKCS12StoreBuilder.cs b/crypto/src/pkcs/PKCS12StoreBuilder.cs
index c8fa0f603..b61a9ea63 100644
--- a/crypto/src/pkcs/PKCS12StoreBuilder.cs
+++ b/crypto/src/pkcs/PKCS12StoreBuilder.cs
@@ -9,6 +9,8 @@ namespace Org.BouncyCastle.Pkcs
 	{
 		private DerObjectIdentifier	keyAlgorithm = PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc;
 		private DerObjectIdentifier	certAlgorithm = PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc;
+		private DerObjectIdentifier keyPrfAlgorithm = null;
+		private DerObjectIdentifier certPrfAlgorithm = null;
 		private bool useDerEncoding = false;
 
 		public Pkcs12StoreBuilder()
@@ -17,7 +19,7 @@ namespace Org.BouncyCastle.Pkcs
 
 		public Pkcs12Store Build()
 		{
-			return new Pkcs12Store(keyAlgorithm, certAlgorithm, useDerEncoding);
+			return new Pkcs12Store(keyAlgorithm, keyPrfAlgorithm, certAlgorithm, certPrfAlgorithm, useDerEncoding);
 		}
 
 		public Pkcs12StoreBuilder SetCertAlgorithm(DerObjectIdentifier certAlgorithm)
@@ -32,6 +34,13 @@ namespace Org.BouncyCastle.Pkcs
 			return this;
 		}
 
+		// Specify a PKCS#5 Scheme 2 encryption for keys
+		public Pkcs12StoreBuilder SetKeyAlgorithm(DerObjectIdentifier keyAlgorithm, DerObjectIdentifier keyPrfAlgorithm)
+		{
+			this.keyAlgorithm = keyAlgorithm;
+			this.keyPrfAlgorithm = keyPrfAlgorithm;
+			return this;
+		}
 		public Pkcs12StoreBuilder SetUseDerEncoding(bool useDerEncoding)
 		{
 			this.useDerEncoding = useDerEncoding;
diff --git a/crypto/src/pkcs/Pkcs12Store.cs b/crypto/src/pkcs/Pkcs12Store.cs
index 50db14d61..0eff8eb92 100644
--- a/crypto/src/pkcs/Pkcs12Store.cs
+++ b/crypto/src/pkcs/Pkcs12Store.cs
@@ -27,7 +27,9 @@ namespace Org.BouncyCastle.Pkcs
         private readonly IDictionary            chainCerts = Platform.CreateHashtable();
         private readonly IDictionary            keyCerts = Platform.CreateHashtable();
         private readonly DerObjectIdentifier	keyAlgorithm;
+        private readonly DerObjectIdentifier    keyPrfAlgorithm;
         private readonly DerObjectIdentifier	certAlgorithm;
+        private readonly DerObjectIdentifier    certPrfAlgorithm;
         private readonly bool					useDerEncoding;
 
         private AsymmetricKeyEntry unmarkedKeyEntry = null;
@@ -89,12 +91,28 @@ namespace Org.BouncyCastle.Pkcs
             bool				useDerEncoding)
         {
             this.keyAlgorithm = keyAlgorithm;
+            this.keyPrfAlgorithm = null;
             this.certAlgorithm = certAlgorithm;
+            this.certPrfAlgorithm = null;
+            this.useDerEncoding = useDerEncoding;
+        }
+
+        internal Pkcs12Store(
+            DerObjectIdentifier keyAlgorithm,
+            DerObjectIdentifier keyPrfAlgorithm,
+            DerObjectIdentifier certAlgorithm,
+            DerObjectIdentifier certPrfAlgorithm,
+            bool useDerEncoding)
+        {
+            this.keyAlgorithm = keyAlgorithm;
+            this.keyPrfAlgorithm = keyPrfAlgorithm;
+            this.certAlgorithm = certAlgorithm;
+            this.certPrfAlgorithm = certPrfAlgorithm;
             this.useDerEncoding = useDerEncoding;
         }
 
         // TODO Consider making obsolete
-//		[Obsolete("Use 'Pkcs12StoreBuilder' instead")]
+        //		[Obsolete("Use 'Pkcs12StoreBuilder' instead")]
         public Pkcs12Store()
             : this(PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc,
                 PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc, false)
@@ -748,8 +766,16 @@ namespace Org.BouncyCastle.Pkcs
                 else
                 {
                     bagOid = PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag;
-                    bagData = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
-                        keyAlgorithm, password, kSalt, MinIterations, privKey.Key);
+                    if (keyPrfAlgorithm != null)
+                    {
+                        bagData = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+                                        keyAlgorithm, keyPrfAlgorithm, password, kSalt, MinIterations, random, privKey.Key);
+                    }
+                    else
+                    {
+                        bagData = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+                                            keyAlgorithm, password, kSalt, MinIterations, privKey.Key);
+                    }
                 }
 
                 Asn1EncodableVector kName = new Asn1EncodableVector();
@@ -952,7 +978,7 @@ namespace Org.BouncyCastle.Pkcs
             byte[] certBagsEncoding = new DerSequence(certBags).GetDerEncoded();
 
             ContentInfo certsInfo;
-            if (password == null)
+            if (password == null || certAlgorithm == null)
             {
                 certsInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(certBagsEncoding));
             }
diff --git a/crypto/src/security/PbeUtilities.cs b/crypto/src/security/PbeUtilities.cs
index ce47e38e5..622c6dd43 100644
--- a/crypto/src/security/PbeUtilities.cs
+++ b/crypto/src/security/PbeUtilities.cs
@@ -42,6 +42,7 @@ namespace Org.BouncyCastle.Security
         {
             algorithms["PKCS5SCHEME1"] = "Pkcs5scheme1";
             algorithms["PKCS5SCHEME2"] = "Pkcs5scheme2";
+            algorithms["PBKDF2"] = "Pkcs5scheme2";
             algorithms[PkcsObjectIdentifiers.IdPbeS2.Id] = "Pkcs5scheme2";
 //			algorithms[PkcsObjectIdentifiers.IdPbkdf2.Id] = "Pkcs5scheme2";
 
@@ -324,6 +325,35 @@ namespace Org.BouncyCastle.Security
             }
         }
 
+        public static Asn1Encodable GenerateAlgorithmParameters( 
+            DerObjectIdentifier cipherAlgorithm,
+            DerObjectIdentifier hashAlgorithm,
+            byte[] salt,
+            int iterationCount,
+            SecureRandom secureRandom)
+        {
+            EncryptionScheme encScheme;
+            if (NistObjectIdentifiers.IdAes128Cbc.Equals(cipherAlgorithm)
+                || NistObjectIdentifiers.IdAes192Cbc.Equals(cipherAlgorithm)
+                || NistObjectIdentifiers.IdAes256Cbc.Equals(cipherAlgorithm)
+                || NistObjectIdentifiers.IdAes128Cfb.Equals(cipherAlgorithm)
+                || NistObjectIdentifiers.IdAes192Cfb.Equals(cipherAlgorithm)
+                || NistObjectIdentifiers.IdAes256Cfb.Equals(cipherAlgorithm))
+            {
+                byte[] iv = new byte[16];
+                secureRandom.NextBytes(iv);
+                encScheme = new EncryptionScheme(cipherAlgorithm, new DerOctetString(iv));
+            }
+            else
+            {
+                throw new ArgumentException("unknown cipher: " + cipherAlgorithm);
+            }
+
+            KeyDerivationFunc func = new KeyDerivationFunc(PkcsObjectIdentifiers.IdPbkdf2, new Pbkdf2Params(salt, iterationCount, new AlgorithmIdentifier(hashAlgorithm, DerNull.Instance)));
+
+            return new PbeS2Parameters(func, encScheme);
+        }
+
         public static ICipherParameters GenerateCipherParameters(
             DerObjectIdentifier algorithmOid,
             char[]              password,