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/PKMacBuilder.cs | |
parent | Merge remote-tracking branch 'origin/master' (diff) | |
download | BouncyCastle.NET-ed25519-6ca2f2f9b941289f42d0ef0d2ef8f0cfa1e4ac86.tar.xz |
refactor of PKMacBuilder
Diffstat (limited to 'crypto/src/crmf/PKMacBuilder.cs')
-rw-r--r-- | crypto/src/crmf/PKMacBuilder.cs | 256 |
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); + } + } +} |