summary refs log tree commit diff
path: root/crypto/src/crmf
diff options
context:
space:
mode:
authorDavid Hook <dgh@bouncycastle.org>2019-01-15 08:05:41 +1100
committerDavid Hook <dgh@bouncycastle.org>2019-01-15 08:05:41 +1100
commit6ca2f2f9b941289f42d0ef0d2ef8f0cfa1e4ac86 (patch)
tree3c1d88a79669f1cf55de9a5731d63066f442de5c /crypto/src/crmf
parentMerge remote-tracking branch 'origin/master' (diff)
downloadBouncyCastle.NET-ed25519-6ca2f2f9b941289f42d0ef0d2ef8f0cfa1e4ac86.tar.xz
refactor of PKMacBuilder
Diffstat (limited to 'crypto/src/crmf')
-rw-r--r--crypto/src/crmf/CertificateRequestMessageBuilder.cs4
-rw-r--r--crypto/src/crmf/DefaultPKMacPrimitivesProvider.cs23
-rw-r--r--crypto/src/crmf/IPKMacPrimitivesProvider.cs28
-rw-r--r--crypto/src/crmf/PKMacBuilder.cs256
-rw-r--r--crypto/src/crmf/ProofOfPossessionSigningKeyBuilder.cs90
5 files changed, 399 insertions, 2 deletions
diff --git a/crypto/src/crmf/CertificateRequestMessageBuilder.cs b/crypto/src/crmf/CertificateRequestMessageBuilder.cs
index 10a575abe..384f6a965 100644
--- a/crypto/src/crmf/CertificateRequestMessageBuilder.cs
+++ b/crypto/src/crmf/CertificateRequestMessageBuilder.cs
@@ -19,7 +19,7 @@ namespace Org.BouncyCastle.Crmf
         private CertTemplateBuilder _templateBuilder;
         private ArrayList _controls= new ArrayList();
         private ISignatureFactory _popSigner;
-        private PkMacFactory _pkMacBuilder;
+        private PKMacBuilder _pkMacBuilder;
         private char[] _password;
         private GeneralName _sender;
         private int _popoType = ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
@@ -161,7 +161,7 @@ namespace Org.BouncyCastle.Crmf
             return this;
         }
 
-        public CertificateRequestMessageBuilder SetAuthInfoPKMAC(PkMacFactory pkmacFactory, char[] password)
+        public CertificateRequestMessageBuilder SetAuthInfoPKMAC(PKMacBuilder pkmacFactory, char[] password)
         {
             this._pkMacBuilder = pkmacFactory;
             this._password = password;
diff --git a/crypto/src/crmf/DefaultPKMacPrimitivesProvider.cs b/crypto/src/crmf/DefaultPKMacPrimitivesProvider.cs
new file mode 100644
index 000000000..1757d6a92
--- /dev/null
+++ b/crypto/src/crmf/DefaultPKMacPrimitivesProvider.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crmf
+{
+    public class DefaultPKMacPrimitivesProvider : IPKMacPrimitivesProvider
+    {
+        public IDigest CreateDigest(AlgorithmIdentifier digestAlg)
+        {
+            return DigestUtilities.GetDigest(digestAlg.Algorithm);
+        }
+
+        public IMac CreateMac(AlgorithmIdentifier macAlg)
+        {
+            return MacUtilities.GetMac(macAlg.Algorithm);
+        }
+    }
+}
diff --git a/crypto/src/crmf/IPKMacPrimitivesProvider.cs b/crypto/src/crmf/IPKMacPrimitivesProvider.cs
new file mode 100644
index 000000000..8b90be515
--- /dev/null
+++ b/crypto/src/crmf/IPKMacPrimitivesProvider.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Iana;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crmf
+{
+    public interface IPKMacPrimitivesProvider   
+    {
+	    IDigest CreateDigest(AlgorithmIdentifier digestAlg);
+
+        IMac CreateMac(AlgorithmIdentifier macAlg);
+    }
+}
diff --git a/crypto/src/crmf/PKMacBuilder.cs b/crypto/src/crmf/PKMacBuilder.cs
new file mode 100644
index 000000000..5e3a5844d
--- /dev/null
+++ b/crypto/src/crmf/PKMacBuilder.cs
@@ -0,0 +1,256 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Iana;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+
+namespace Org.BouncyCastle.Crmf
+{
+
+    class PKMacStreamCalculator : IStreamCalculator
+    {
+        private readonly MacSink _stream;
+        
+        public PKMacStreamCalculator(IMac mac)
+        {
+            _stream = new MacSink(mac);
+        }
+
+        public Stream Stream
+        {
+            get { return _stream; }
+        }
+
+        public object GetResult()
+        {
+            return new DefaultPKMacResult(_stream.Mac);
+        }
+    }
+
+    class PKMacFactory : IMacFactory
+    {
+        protected readonly PbmParameter parameters;
+        private byte[] key;
+        
+   
+        public PKMacFactory(byte[] key, PbmParameter parameters)
+        {
+            this.key = Arrays.Clone(key);
+
+            this.parameters = parameters;  
+        }
+
+        public virtual object AlgorithmDetails
+        {
+            get { return new AlgorithmIdentifier(CmpObjectIdentifiers.passwordBasedMac, parameters); }
+        }
+
+        public virtual IStreamCalculator CreateCalculator()
+        {
+            IMac mac = MacUtilities.GetMac(parameters.Mac.Algorithm);
+
+            mac.Init(new KeyParameter(key));
+
+            return new PKMacStreamCalculator(mac);
+        }
+    }
+
+    class DefaultPKMacResult: IBlockResult
+    {
+        private readonly IMac mac;
+
+        public DefaultPKMacResult(IMac mac)
+        {
+            this.mac = mac;
+        }
+
+        public byte[] Collect()
+        {
+            byte[] res = new byte[mac.GetMacSize()];
+
+            mac.DoFinal(res, 0);
+
+            return res;
+        }
+
+        public int Collect(byte[] sig, int sigOff)
+        {
+            byte[] signature = Collect();
+            signature.CopyTo(sig, sigOff);
+            return signature.Length;
+        }
+    }
+
+    public class PKMacBuilder
+    {
+        private AlgorithmIdentifier owf;
+        private AlgorithmIdentifier mac;
+        private IPKMacPrimitivesProvider provider;
+        private SecureRandom random;
+        private PbmParameter parameters;
+        private int iterationCount;
+        private int saltLength;
+        private byte[] salt;
+        private int maxIterations;
+
+        public PKMacBuilder() :
+            this(new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1), 1000, new AlgorithmIdentifier(IanaObjectIdentifiers.HmacSha1, DerNull.Instance), new DefaultPKMacPrimitivesProvider())
+        {
+        }
+
+        public PKMacBuilder(IPKMacPrimitivesProvider provider) :
+            this(new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1), 1000, new AlgorithmIdentifier(IanaObjectIdentifiers.HmacSha1, DerNull.Instance), provider)
+        {       
+        }
+
+        public PKMacBuilder(IPKMacPrimitivesProvider provider, int maxIterations)
+        {
+            this.provider = provider;
+            this.maxIterations = maxIterations;
+        }
+
+        private PKMacBuilder(AlgorithmIdentifier digestAlgorithmIdentifier, int iterationCount, AlgorithmIdentifier macAlgorithmIdentifier, IPKMacPrimitivesProvider provider)
+        {
+            this.iterationCount = iterationCount;
+            this.mac = macAlgorithmIdentifier;
+            this.owf = digestAlgorithmIdentifier;
+            this.provider = provider;
+        }
+
+        /**
+         * Set the salt length in octets.
+         *
+         * @param saltLength length in octets of the salt to be generated.
+         * @return the generator
+         */
+        public PKMacBuilder SetSaltLength(int saltLength)
+        {
+            if (saltLength < 8)
+            {
+                throw new ArgumentException("salt length must be at least 8 bytes");
+            }
+
+            this.saltLength = saltLength;
+
+            return this;
+        }
+
+        public PKMacBuilder SetIterationCount(int iterationCount)
+        {
+            if (iterationCount < 100)
+            {
+                throw new ArgumentException("iteration count must be at least 100");
+            }
+            checkIterationCountCeiling(iterationCount);
+
+            this.iterationCount = iterationCount;
+
+            return this;
+        }
+
+        public PKMacBuilder SetParameters(PbmParameter parameters)
+        {
+            checkIterationCountCeiling(parameters.IterationCount.Value.IntValue);
+
+            this.parameters = parameters;
+
+            return this;
+        }
+
+        public PKMacBuilder SetSecureRandom(SecureRandom random)
+        {
+            this.random = random;
+
+            return this;          
+        }
+
+        public IMacFactory Build(char[] password)
+        {
+            if (parameters != null)
+            {
+                return genCalculator(parameters, password);
+            }
+            else
+            {
+                byte[] salt = new byte[saltLength];
+
+                if (random == null)
+                {
+                    this.random = new SecureRandom();
+                }
+
+                random.NextBytes(salt);
+
+                return genCalculator(new PbmParameter(salt, owf, iterationCount, mac), password);
+            }
+        }
+
+        private void checkIterationCountCeiling(int iterationCount)
+        {
+            if (maxIterations > 0 && iterationCount > maxIterations)
+            {
+                throw new ArgumentException("iteration count exceeds limit (" + iterationCount + " > " + maxIterations + ")");
+            }
+        }
+
+        private IMacFactory genCalculator(PbmParameter parameters, char[] password)
+        {
+            // From RFC 4211
+            //
+            //   1.  Generate a random salt value S
+            //
+            //   2.  Append the salt to the pw.  K = pw || salt.
+            //
+            //   3.  Hash the value of K.  K = HASH(K)
+            //
+            //   4.  Iter = Iter - 1.  If Iter is greater than zero.  Goto step 3.
+            //
+            //   5.  Compute an HMAC as documented in [HMAC].
+            //
+            //       MAC = HASH( K XOR opad, HASH( K XOR ipad, data) )
+            //
+            //       Where opad and ipad are defined in [HMAC].
+            byte[] pw = Strings.ToUtf8ByteArray(password);
+            byte[] salt = parameters.Salt.GetOctets();
+            byte[] K = new byte[pw.Length + salt.Length];
+
+            System.Array.Copy(pw, 0, K, 0, pw.Length);
+            System.Array.Copy(salt, 0, K, pw.Length, salt.Length);
+
+            IDigest digest = provider.CreateDigest(parameters.Owf);
+
+            int iter = parameters.IterationCount.Value.IntValue;
+
+            digest.BlockUpdate(K, 0, K.Length);
+
+            K = new byte[digest.GetDigestSize()];
+
+            digest.DoFinal(K, 0);
+
+            while (--iter > 0)
+            {
+                digest.BlockUpdate(K, 0, K.Length);
+
+                digest.DoFinal(K, 0);
+            }
+
+            byte[] key = K;
+
+            return new PKMacFactory(key, parameters);
+        }
+    }
+}
diff --git a/crypto/src/crmf/ProofOfPossessionSigningKeyBuilder.cs b/crypto/src/crmf/ProofOfPossessionSigningKeyBuilder.cs
new file mode 100644
index 000000000..8457585ff
--- /dev/null
+++ b/crypto/src/crmf/ProofOfPossessionSigningKeyBuilder.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Operators;
+using Org.BouncyCastle.Crypto.Paddings;
+
+namespace Org.BouncyCastle.Crmf
+{
+    public class ProofOfPossessionSigningKeyBuilder
+    {
+        private CertRequest _certRequest;
+        private SubjectPublicKeyInfo _pubKeyInfo;
+        private GeneralName _name;
+        private PKMacValue _publicKeyMAC;
+
+        public ProofOfPossessionSigningKeyBuilder(CertRequest certRequest)
+        {
+            this._certRequest = certRequest;
+        }
+
+        public ProofOfPossessionSigningKeyBuilder(SubjectPublicKeyInfo pubKeyInfo)
+        {
+            this._pubKeyInfo = pubKeyInfo;
+        }
+
+        public ProofOfPossessionSigningKeyBuilder setSender(GeneralName name)
+        {
+            this._name = name;
+
+            return this;
+        }
+
+        public ProofOfPossessionSigningKeyBuilder setPublicKeyMac(PKMacBuilder generator, char[] password)
+        {
+            IMacFactory fact = generator.Build(password);
+
+            IStreamCalculator calc = fact.CreateCalculator();
+            byte[] d = _pubKeyInfo.GetDerEncoded();
+            calc.Stream.Write(d, 0, d.Length);
+            calc.Stream.Flush();
+            calc.Stream.Close();
+
+            this._publicKeyMAC = new PKMacValue(
+                (AlgorithmIdentifier)fact.AlgorithmDetails,
+                new DerBitString(((IBlockResult)calc.GetResult()).Collect()));
+
+            return this;
+        }
+
+        public PopoSigningKey build(ISignatureFactory signer)
+        {
+            if (_name != null && _publicKeyMAC != null)
+            {
+                throw new InvalidOperationException("name and publicKeyMAC cannot both be set.");
+            }
+
+            PopoSigningKeyInput popo;
+            byte[] b;
+            IStreamCalculator calc = signer.CreateCalculator();
+            if (_certRequest != null)
+            {
+                popo = null;
+                b = _certRequest.GetDerEncoded();
+                calc.Stream.Write(b, 0, b.Length);
+
+            }
+            else if (_name != null)
+            {
+                popo = new PopoSigningKeyInput(_name, _pubKeyInfo);
+                b = popo.GetDerEncoded();
+                calc.Stream.Write(b, 0, b.Length);
+            }
+            else
+            {
+                popo = new PopoSigningKeyInput(_publicKeyMAC, _pubKeyInfo);
+                b = popo.GetDerEncoded();
+                calc.Stream.Write(b, 0, b.Length);
+            }
+
+            calc.Stream.Flush();
+            calc.Stream.Close();
+            DefaultSignatureResult res = (DefaultSignatureResult)calc.GetResult();
+            return new PopoSigningKey(popo, (AlgorithmIdentifier)signer.AlgorithmDetails, new DerBitString(res.Collect()));
+        }
+    }
+}