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()));
+ }
+ }
+}
|