summary refs log tree commit diff
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
parentMerge remote-tracking branch 'origin/master' (diff)
downloadBouncyCastle.NET-ed25519-6ca2f2f9b941289f42d0ef0d2ef8f0cfa1e4ac86.tar.xz
refactor of PKMacBuilder
-rw-r--r--crypto/src/cmp/GeneralPkiMessage.cs (renamed from crypto/src/asn1/cmp/GeneralPKIMessage.cs)0
-rw-r--r--crypto/src/cmp/ProtectedPkiMessage.cs (renamed from crypto/src/asn1/cmp/ProtectedPkiMessage.cs)35
-rw-r--r--crypto/src/cmp/ProtectedPkiMessageBuilder.cs9
-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
-rw-r--r--crypto/src/crypto/operators/Asn1Mac.cs410
9 files changed, 423 insertions, 432 deletions
diff --git a/crypto/src/asn1/cmp/GeneralPKIMessage.cs b/crypto/src/cmp/GeneralPkiMessage.cs
index d91b8ef7e..d91b8ef7e 100644
--- a/crypto/src/asn1/cmp/GeneralPKIMessage.cs
+++ b/crypto/src/cmp/GeneralPkiMessage.cs
diff --git a/crypto/src/asn1/cmp/ProtectedPkiMessage.cs b/crypto/src/cmp/ProtectedPkiMessage.cs
index c39f06ad0..159f08722 100644
--- a/crypto/src/asn1/cmp/ProtectedPkiMessage.cs
+++ b/crypto/src/cmp/ProtectedPkiMessage.cs
@@ -3,6 +3,8 @@ using Org.BouncyCastle.X509;
 using System;
 using System.Collections.Generic;
 using System.Text;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
 using Org.BouncyCastle.Asn1.Crmf;
 using Org.BouncyCastle.Asn1.Pkcs;
 using Org.BouncyCastle.Crypto;
@@ -10,8 +12,9 @@ using Org.BouncyCastle.Crypto.Operators;
 using Org.BouncyCastle.Crypto.Paddings;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Crmf;
 
-namespace Org.BouncyCastle.Asn1.Cmp
+namespace Org.BouncyCastle.Cmp
 {
    
     public class ProtectedPkiMessage
@@ -64,29 +67,31 @@ namespace Org.BouncyCastle.Asn1.Cmp
 
             return res;
         }
-        
 
-        
+        public bool Verify(IVerifierFactory verifierFactory)
+        {
+            IStreamCalculator streamCalculator = verifierFactory.CreateCalculator();
+
+            IVerifier result = (IVerifier)Process(streamCalculator);
+
+            return result.IsVerified(pkiMessage.Protection.GetBytes());
+        }
 
-        public bool Verify(IVerifierFactory verifier)
+        private Object Process(IStreamCalculator streamCalculator)
         {
            Asn1EncodableVector avec = new Asn1EncodableVector();
            avec.Add(pkiMessage.Header);
            avec.Add(pkiMessage.Body);
            byte[] enc =   new DerSequence(avec).GetDerEncoded();
 
-           IStreamCalculator streamCalculator = verifier.CreateCalculator();
-
            streamCalculator.Stream.Write(enc,0,enc.Length);
            streamCalculator.Stream.Flush();
            streamCalculator.Stream.Close();
           
-           IVerifier result = (IVerifier) streamCalculator.GetResult();     
-           return result.IsVerified(pkiMessage.Protection.GetBytes());          
+           return streamCalculator.GetResult();          
         }
 
-
-        public bool Verify(Asn1MacFactoryProvider asn1Factory, byte[] password)
+        public bool Verify(PKMacBuilder pkMacBuilder, char[] password)
         {
             if (!CmpObjectIdentifiers.passwordBasedMac.Equals(pkiMessage.Header.ProtectionAlg.Algorithm))
             {
@@ -95,13 +100,11 @@ namespace Org.BouncyCastle.Asn1.Cmp
 
             PbmParameter parameter = PbmParameter.GetInstance(pkiMessage.Header.ProtectionAlg.Parameters);
 
-            PkMacFactory macFactory = (PkMacFactory)asn1Factory.CreateMacFactory(parameter);
-                            
-            macFactory.Password = password;
-            MacVerifierFactory macVerifierFactory = new MacVerifierFactory(macFactory);
+            pkMacBuilder.SetParameters(parameter);
 
-            return Verify(macVerifierFactory);       
-        }
+            IBlockResult result = (IBlockResult)Process(pkMacBuilder.Build(password).CreateCalculator());
 
+            return Arrays.ConstantTimeAreEqual(result.Collect(), this.pkiMessage.Protection.GetBytes());
+        }
     }
 }
diff --git a/crypto/src/cmp/ProtectedPkiMessageBuilder.cs b/crypto/src/cmp/ProtectedPkiMessageBuilder.cs
index 22a004669..e660f844a 100644
--- a/crypto/src/cmp/ProtectedPkiMessageBuilder.cs
+++ b/crypto/src/cmp/ProtectedPkiMessageBuilder.cs
@@ -1,11 +1,13 @@
 using System;
 using System.Collections;
+using Org.BouncyCastle.Asn1.Crmf;
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.Cmp;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Operators;
 using Org.BouncyCastle.X509;
+using Org.BouncyCastle.Crmf;
 
 namespace Org.BouncyCastle.Cmp
 {
@@ -153,14 +155,13 @@ namespace Org.BouncyCastle.Cmp
             signer.Stream.Write(encoded, 0, encoded.Length);
             Object result = signer.GetResult();
 
-
             if (result is DefaultSignatureResult)
             {
-                return ((DefaultSignatureResult) result).Collect();
+                return ((DefaultSignatureResult)result).Collect();
             }
-            else if (result is DefaultMacAndDigestResult)
+            else if (result is IBlockResult)
             {
-                return ((DefaultMacAndDigestResult) result).MacResult;
+                return ((IBlockResult)result).Collect();
             }
             else if (result is byte[])
             {
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()));
+        }
+    }
+}
diff --git a/crypto/src/crypto/operators/Asn1Mac.cs b/crypto/src/crypto/operators/Asn1Mac.cs
deleted file mode 100644
index ff70e5849..000000000
--- a/crypto/src/crypto/operators/Asn1Mac.cs
+++ /dev/null
@@ -1,410 +0,0 @@
-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;
-
-namespace Org.BouncyCastle.Crypto.Operators
-{
-
-    public class DefaultMacStreamCalculator : IStreamCalculator
-    {
-        private readonly MacSink _stream;
-
-        public DefaultMacStreamCalculator(IMac mac)
-        {
-            _stream = new MacSink(mac);
-        }
-
-        public void Init(KeyParameter key)
-        {
-            _stream.Mac.Init(key);
-        }
-
-        public Stream Stream
-        {
-            get { return _stream; }
-        }
-        public object GetResult()
-        {
-            byte[] res = new byte[_stream.Mac.GetMacSize()];
-            _stream.Mac.DoFinal(res, 0);
-            return res;
-        }
-    }
-
-
-    public class DefaultMacAndDigestStreamCalculator : IStreamCalculator
-    {
-
-        private readonly MacSink macSink;
-        private readonly DigestSink digestSink;
-        private readonly Stream _stream;
-
-
-        public DefaultMacAndDigestStreamCalculator(IMac imac, IDigest idigest)
-        {
-            this.macSink = new MacSink(imac);
-            this.digestSink = new DigestSink(idigest);
-            _stream = new MergedStream(macSink,digestSink);
-        }
-
-
-        public void Init(KeyParameter macKey)
-        {
-            this.macSink.Mac.Init(macKey);
-        }
-
-        public void Init(PbmParameter parameter, byte[] password)
-        {
-
-            byte[] pw = password;
-            byte[] salt = parameter.Salt.GetOctets();
-            byte[] K = new byte[pw.Length + salt.Length];
-
-            System.Array.Copy(pw,K,pw.Length);
-            System.Array.Copy(salt,0,K,pw.Length,salt.Length);
-            int iter = parameter.IterationCount.Value.IntValue;
-            this.digestSink.Digest.Reset();
-
-            IDigest dig = DigestUtilities.GetDigest(digestSink.Digest.AlgorithmName);
-
-           
-        
-            dig.BlockUpdate(K,0,K.Length);
-            K = new byte[dig.GetDigestSize()];
-            dig.DoFinal(K, 0);
-            iter--;
-
-            do
-            {
-                dig.BlockUpdate(K,0,K.Length);
-                dig.DoFinal(K, 0);
-            } while (--iter > 0);
-        
-           macSink.Mac.Init(new KeyParameter(K));
-        }
-
-
-
-        public Stream Stream
-        {
-            get { return _stream; }
-        }
-
-
-        public object GetResult()
-        {
-            byte[] macResult = new byte[macSink.Mac.GetMacSize()];
-            macSink.Mac.DoFinal(macResult, 0);
-            byte[] digestResult = new byte[digestSink.Digest.GetByteLength()];
-            digestSink.Digest.DoFinal(digestResult, 0);
-            return new DefaultMacAndDigestResult(digestResult, macResult);
-        }
-
-        private class MergedStream : Stream
-        {
-
-            private Stream aStream;
-            private Stream bStream;
-
-            public MergedStream(Stream aStream, Stream bStream)
-            {
-                this.aStream = aStream;
-                this.bStream = bStream;
-            }
-
-            public override void Flush()
-            {
-                aStream.Flush();
-                bStream.Flush();
-            }
-
-            public override long Seek(long offset, SeekOrigin origin)
-            {
-                aStream.Seek(offset, origin);
-                return bStream.Seek(offset, origin);
-            }
-
-            public override void SetLength(long value)
-            {
-                aStream.SetLength(value);
-                bStream.SetLength(value);
-            }
-
-            public override int Read(byte[] buffer, int offset, int count)
-            {
-                aStream.Read(buffer, offset, count);
-                return bStream.Read(buffer, offset, count);
-            }
-
-            public override void Write(byte[] buffer, int offset, int count)
-            {
-                aStream.Write(buffer, offset, count);
-                bStream.Write(buffer, offset, count);
-            }
-
-            public override bool CanRead
-            {
-                get { return bStream.CanRead && aStream.CanRead; }
-            }
-            public override bool CanSeek
-            {
-                get { return bStream.CanSeek && aStream.CanSeek; }
-
-            }
-            public override bool CanWrite {
-                get { return bStream.CanWrite && aStream.CanWrite; }
-                
-            }
-            public override long Length {
-                get
-                {
-                    return aStream.Length;              
-                }
-            }
-            public override long Position
-            {
-                get { return aStream.Position; }
-
-                set { aStream.Position = value; }
-            }
-        }
-    }
-
-    public struct DefaultMacAndDigestResult
-    {
-        public DefaultMacAndDigestResult(byte[] digestResult, byte[] macResult)
-        {
-            DigestResult = digestResult;
-            MacResult = macResult;
-        }
-
-        public byte[] DigestResult { get; }
-
-        public byte[] MacResult { get; }
-    }
-
-    public class Asn1MacFactory : IMacFactory
-    {
-        protected readonly AlgorithmIdentifier MacAlgorithmIdentifier;
-
-        
-   
-        public Asn1MacFactory(AlgorithmIdentifier macAlgorithmIdentifier)
-        {
-            MacAlgorithmIdentifier = macAlgorithmIdentifier;  
-        }
-
-       
-
-        public virtual object AlgorithmDetails
-        {
-            get { return MacAlgorithmIdentifier; }
-        }
-
-        public virtual IStreamCalculator CreateCalculator()
-        {
-           IMac mac = MacUtilities.GetMac(MacAlgorithmIdentifier.Algorithm);
-           return new DefaultMacStreamCalculator(mac);
-        }
-    }
-
-
-    public interface IMacFactoryProvider
-    {
-        IMacFactory CreateMacFactory(AlgorithmIdentifier algorithmIdentifier);
-    }
-
-    public class Asn1MacFactoryProvider : IMacFactoryProvider
-    {
-        public IMacFactory CreateMacFactory(AlgorithmIdentifier algorithmIdentifier)
-        {
-            return new Asn1MacFactory(algorithmIdentifier);
-        }
-
-        public IMacFactory CreateMacFactory(AlgorithmIdentifier digestAlgorithmIdentifier, AlgorithmIdentifier macAlgorithmIdentifier)
-        {
-            return new PkMacFactory(digestAlgorithmIdentifier,macAlgorithmIdentifier);
-        }
-
-        public IMacFactory CreateMacFactory(PbmParameter parameter)
-        {
-            return new PkMacFactory(parameter);
-        }
-
-    }
-
-
-
-    public class PkMacFactory:Asn1MacFactory
-    {
-        private readonly AlgorithmIdentifier _digestAlgorithmIdentifier;
-        private byte[] password;
-        private int iterationCount;
-        private byte[] salt;
-
-
-     
-        public PkMacFactory(SecureRandom random) : base(new AlgorithmIdentifier(IanaObjectIdentifiers.HmacSha1))
-        {
-            this._digestAlgorithmIdentifier = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
-            this.iterationCount = 1000;
-            this.salt = new byte[20];
-            random.NextBytes(salt);        
-        }
-
-        public PkMacFactory(AlgorithmIdentifier digestAlgorithmIdentifier, AlgorithmIdentifier macAlgorithmIdentifier) : base(macAlgorithmIdentifier)
-        {
-            this._digestAlgorithmIdentifier = digestAlgorithmIdentifier;
-        }
-
-        public PkMacFactory(PbmParameter parameter):base(parameter.Mac)
-        {
-            this._digestAlgorithmIdentifier = parameter.Owf;         
-            this.salt = parameter.Salt.GetOctets();
-            this.iterationCount = parameter.IterationCount.Value.IntValue;           
-        }
-
-        public override object AlgorithmDetails
-        {
-            get
-            {
-                return new AlgorithmIdentifier(CmpObjectIdentifiers.passwordBasedMac,
-                    new PbmParameter(salt, _digestAlgorithmIdentifier, iterationCount, MacAlgorithmIdentifier));
-            }
-        }
-
-
-        public int IterationCount
-        {
-            set { this.iterationCount = value; }
-        }
-        public byte[] Salt
-        {
-            set { this.salt = value;}
-        }
-        public byte[] Password {
-            set { this.password = value; }
-        }
-       
-
-        public override IStreamCalculator CreateCalculator()
-        {
-           
-            DefaultMacAndDigestStreamCalculator calc = new DefaultMacAndDigestStreamCalculator(
-                MacUtilities.GetMac(this.MacAlgorithmIdentifier.Algorithm), 
-                DigestUtilities.GetDigest(_digestAlgorithmIdentifier.Algorithm));
-       
-            PbmParameter parameter = new PbmParameter(salt, _digestAlgorithmIdentifier,iterationCount,MacAlgorithmIdentifier);                 
-            calc.Init(parameter, password);
-            
-          
-            return calc;
-        }
-
-    }
-
-
-    public class MacVerifierFactory : IVerifierFactory
-    {
-        private readonly IMacFactory _macFactory;
-
-
-        public MacVerifierFactory(IMacFactory macFactory)
-        {
-            this._macFactory = macFactory;
-        }
-
-        public object AlgorithmDetails
-        {
-            get { return _macFactory.AlgorithmDetails; }
-        }
-        public IStreamCalculator CreateCalculator()
-        {
-            return new MacVerifier(_macFactory.CreateCalculator());
-        }
-
-        private class MacVerifier : IStreamCalculator
-        {
-            public IStreamCalculator _calculator;
-
-            public MacVerifier(IStreamCalculator calculator)
-            {
-                _calculator = calculator;
-            }
-
-            public Stream Stream
-            {
-                get { return _calculator.Stream; }
-            }
-
-            public object GetResult()
-            {
-                object result = _calculator.GetResult();
-                if (result is byte[])
-                {
-                    return new DefaultMacVerifierResult((byte[])result);
-                } else if (result is DefaultMacAndDigestResult)
-                {
-                    return new DefaultMacVerifierResult(((DefaultMacAndDigestResult)result).MacResult);
-
-                }
-
-                throw new InvalidOperationException("calculator did not return byte[] or DefaultMacVerifierResult");
-            }
-        }
-
-    }
-
-
-    public class DefaultMacVerifierResult:IVerifier
-    {
-        private readonly byte[] _calculatedResult;
-
-        public DefaultMacVerifierResult(byte[] calculatedResult)
-        {
-            this._calculatedResult = calculatedResult;
-        }
-
-
-        public bool IsVerified(byte[] data)
-        {
-            return Arrays.ConstantTimeAreEqual(_calculatedResult, data);
-        }
-
-        public bool IsVerified(byte[] source, int off, int length)
-        {
-            if (_calculatedResult.Length != length)
-            {
-                return false;
-            }
-
-            //
-            // Must be constant time.
-            //
-            int j = 0;        
-            int nonEqual = 0;        
-            for (int i = off; i < off + length; i++)
-            {
-                nonEqual |= (_calculatedResult[j++] ^ source[i]);
-            }
-
-            return nonEqual == 0;
-        }
-    }
-
-
-}