diff options
author | David Hook <dgh@bouncycastle.org> | 2019-01-15 08:05:41 +1100 |
---|---|---|
committer | David Hook <dgh@bouncycastle.org> | 2019-01-15 08:05:41 +1100 |
commit | 6ca2f2f9b941289f42d0ef0d2ef8f0cfa1e4ac86 (patch) | |
tree | 3c1d88a79669f1cf55de9a5731d63066f442de5c /crypto/src/crmf | |
parent | Merge remote-tracking branch 'origin/master' (diff) | |
download | BouncyCastle.NET-ed25519-6ca2f2f9b941289f42d0ef0d2ef8f0cfa1e4ac86.tar.xz |
refactor of PKMacBuilder
Diffstat (limited to 'crypto/src/crmf')
-rw-r--r-- | crypto/src/crmf/CertificateRequestMessageBuilder.cs | 4 | ||||
-rw-r--r-- | crypto/src/crmf/DefaultPKMacPrimitivesProvider.cs | 23 | ||||
-rw-r--r-- | crypto/src/crmf/IPKMacPrimitivesProvider.cs | 28 | ||||
-rw-r--r-- | crypto/src/crmf/PKMacBuilder.cs | 256 | ||||
-rw-r--r-- | crypto/src/crmf/ProofOfPossessionSigningKeyBuilder.cs | 90 |
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())); + } + } +} |