summary refs log tree commit diff
path: root/crypto/src/crmf/PKMacBuilder.cs
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/PKMacBuilder.cs
parentMerge remote-tracking branch 'origin/master' (diff)
downloadBouncyCastle.NET-ed25519-6ca2f2f9b941289f42d0ef0d2ef8f0cfa1e4ac86.tar.xz
refactor of PKMacBuilder
Diffstat (limited to 'crypto/src/crmf/PKMacBuilder.cs')
-rw-r--r--crypto/src/crmf/PKMacBuilder.cs256
1 files changed, 256 insertions, 0 deletions
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);
+        }
+    }
+}