diff --git a/crypto/src/security/CipherUtilities.cs b/crypto/src/security/CipherUtilities.cs index 6a53c7a8e..152e6dd69 100644 --- a/crypto/src/security/CipherUtilities.cs +++ b/crypto/src/security/CipherUtilities.cs @@ -24,8 +24,21 @@ namespace Org.BouncyCastle.Security { + /// + /// Factory for instances, resolved from a textual algorithm name (with optional + /// mode/padding components) or from an ASN.1 algorithm OID. + /// /// - /// Cipher Utility class contains methods that can not be specifically grouped into other classes. + /// + /// Algorithm strings follow the JCA-style ALGORITHM[/MODE[/PADDING]] convention (for example + /// "AES/CBC/PKCS7Padding" or "DESEDE/ECB/NoPadding"). Aliases for common algorithm names and + /// many standard ASN.1 OIDs are recognised. When the input cannot be resolved, a + /// is thrown. + /// + /// + /// The returned is uninitialised; the caller must invoke + /// before processing data. + /// /// public static class CipherUtilities { @@ -295,11 +308,25 @@ static CipherUtilities() #endif } + /// + /// Returns the canonical algorithm name registered for the given ASN.1 OID, or null if the OID + /// is not mapped to a known cipher. + /// + /// An ASN.1 algorithm identifier. + /// The canonical algorithm name (suitable for passing to ), + /// or null. public static string GetAlgorithmName(DerObjectIdentifier oid) { return CollectionUtilities.GetValueOrNull(AlgorithmOidMap, oid); } + /// + /// Resolve and instantiate an for the given ASN.1 algorithm OID. + /// + /// The algorithm OID to look up. + /// A new, uninitialised . + /// If is null. + /// If the OID does not map to a known cipher. public static IBufferedCipher GetCipher(DerObjectIdentifier oid) { if (oid == null) @@ -315,6 +342,16 @@ public static IBufferedCipher GetCipher(DerObjectIdentifier oid) throw new SecurityUtilityException("Cipher OID not recognised."); } + /// + /// Resolve and instantiate an for the given algorithm specification. + /// + /// A JCA-style cipher name of the form ALGORITHM[/MODE[/PADDING]] + /// (e.g. "AES/CBC/PKCS7Padding"). Aliases such as "DESede" or "3DES" are + /// also accepted. + /// A new, uninitialised . + /// If is null. + /// If the algorithm, mode, or padding component is not + /// recognised. public static IBufferedCipher GetCipher(string algorithm) { if (algorithm == null) diff --git a/crypto/src/security/DigestUtilities.cs b/crypto/src/security/DigestUtilities.cs index 68131a54d..d0bfc408d 100644 --- a/crypto/src/security/DigestUtilities.cs +++ b/crypto/src/security/DigestUtilities.cs @@ -18,8 +18,12 @@ namespace Org.BouncyCastle.Security { + /// + /// Factory for instances and convenience helpers for one-shot hash computation. + /// /// - /// Utility class for creating IDigest objects from their names/Oids + /// Digests can be looked up by canonical name (e.g. "SHA-256", "SHA3-512") or by ASN.1 OID. + /// Names are matched case-insensitively and a number of common aliases are recognised. /// public static class DigestUtilities { @@ -202,18 +206,24 @@ static DigestUtilities() #endif } + /// One-shot digest of using the algorithm identified by + /// . // TODO[api] Change parameter name to 'oid' public static byte[] CalculateDigest(DerObjectIdentifier id, byte[] input) { return CalculateDigest(id.Id, input); } + /// One-shot digest of using the named algorithm. + /// If is not recognised. public static byte[] CalculateDigest(string algorithm, byte[] input) { IDigest digest = GetDigest(algorithm); return DoFinal(digest, input); } + /// One-shot digest of bytes from starting at + /// offset . public static byte[] CalculateDigest(string algorithm, byte[] buf, int off, int len) { IDigest digest = GetDigest(algorithm); @@ -221,9 +231,12 @@ public static byte[] CalculateDigest(string algorithm, byte[] buf, int off, int } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + /// One-shot digest of using the algorithm identified by + /// . public static byte[] CalculateDigest(DerObjectIdentifier oid, ReadOnlySpan buffer) => CalculateDigest(oid.GetID(), buffer); + /// One-shot digest of using the named algorithm. public static byte[] CalculateDigest(string algorithm, ReadOnlySpan buffer) { IDigest digest = GetDigest(algorithm); @@ -231,6 +244,7 @@ public static byte[] CalculateDigest(string algorithm, ReadOnlySpan buffer } #endif + /// Finalises and returns the resulting hash as a fresh array. public static byte[] DoFinal(IDigest digest) { byte[] b = new byte[digest.GetDigestSize()]; @@ -238,12 +252,16 @@ public static byte[] DoFinal(IDigest digest) return b; } + /// Feeds into , then finalises and returns the + /// hash. public static byte[] DoFinal(IDigest digest, byte[] input) { digest.BlockUpdate(input, 0, input.Length); return DoFinal(digest); } + /// Feeds bytes from at offset + /// into , then finalises and returns the hash. public static byte[] DoFinal(IDigest digest, byte[] buf, int off, int len) { digest.BlockUpdate(buf, off, len); @@ -251,6 +269,8 @@ public static byte[] DoFinal(IDigest digest, byte[] buf, int off, int len) } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + /// Feeds into , then finalises and returns + /// the hash. public static byte[] DoFinal(IDigest digest, ReadOnlySpan buffer) { digest.BlockUpdate(buffer); @@ -258,11 +278,20 @@ public static byte[] DoFinal(IDigest digest, ReadOnlySpan buffer) } #endif + /// + /// Returns the canonical algorithm name registered for the given ASN.1 OID, or null if the OID + /// is not mapped to a known digest. + /// public static string GetAlgorithmName(DerObjectIdentifier oid) { return CollectionUtilities.GetValueOrNull(AlgorithmOidMap, oid); } + /// + /// Resolve and instantiate an for the given ASN.1 algorithm OID. + /// + /// If is null. + /// If the OID does not map to a known digest. // TODO[api] Change parameter name to 'oid' public static IDigest GetDigest(DerObjectIdentifier id) { @@ -279,6 +308,13 @@ public static IDigest GetDigest(DerObjectIdentifier id) throw new SecurityUtilityException("Digest OID not recognised."); } + /// + /// Resolve and instantiate an by name (or alias). + /// + /// A digest name (e.g. "SHA-256", "SHA3-512", + /// "BLAKE2B-512"). + /// If is null. + /// If the digest name is not recognised. public static IDigest GetDigest(string algorithm) { if (algorithm == null) @@ -364,10 +400,11 @@ private static string GetMechanism(string algorithm) } /// - /// Returns an ObjectIdentifier for a given digest mechanism. + /// Returns the ASN.1 OID associated with the named digest mechanism, or null when none is + /// registered. /// - /// A string representation of the digest meanism. - /// A DerObjectIdentifier, null if the Oid is not available. + /// A digest name or alias (e.g. "SHA-256"). + /// If is null. public static DerObjectIdentifier GetObjectIdentifier(string mechanism) { if (mechanism == null) diff --git a/crypto/src/security/GeneratorUtilities.cs b/crypto/src/security/GeneratorUtilities.cs index a0606a82f..5dea4230d 100644 --- a/crypto/src/security/GeneratorUtilities.cs +++ b/crypto/src/security/GeneratorUtilities.cs @@ -22,6 +22,16 @@ namespace Org.BouncyCastle.Security { + /// + /// Factory for symmetric key generators () and asymmetric key pair + /// generators (), resolved by algorithm name or ASN.1 OID. + /// + /// + /// Names are matched case-insensitively. Symmetric generators are pre-configured with the algorithm's + /// default key size; asymmetric generators are returned uninitialised — the caller must invoke + /// with appropriate + /// before generating a key pair. + /// public static class GeneratorUtilities { private static readonly IDictionary KgAlgorithms = @@ -352,11 +362,18 @@ internal static string GetCanonicalKeyPairGeneratorAlgorithm(string algorithm) return CollectionUtilities.GetValueOrNull(KpgAlgorithms, algorithm); } + /// Resolve a for the given symmetric algorithm OID. public static CipherKeyGenerator GetKeyGenerator(DerObjectIdentifier oid) { return GetKeyGenerator(oid.Id); } + /// + /// Resolve a for the named symmetric algorithm (e.g. "AES", + /// "DESede", "ChaCha20"), pre-configured with the algorithm's default key size. + /// + /// If the algorithm is not recognised or has no default + /// key size. public static CipherKeyGenerator GetKeyGenerator(string algorithm) { string canonicalName = GetCanonicalKeyGeneratorAlgorithm(algorithm); @@ -378,11 +395,17 @@ public static CipherKeyGenerator GetKeyGenerator(string algorithm) return new CipherKeyGenerator(defaultKeySize); } + /// Resolve an for the given algorithm OID. public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator(DerObjectIdentifier oid) { return GetKeyPairGenerator(oid.Id); } + /// + /// Resolve an for the named asymmetric algorithm + /// (e.g. "RSA", "ECDSA", "Ed25519", "DH"). + /// + /// If the algorithm is not recognised. public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator(string algorithm) { string canonicalName = GetCanonicalKeyPairGeneratorAlgorithm(algorithm); diff --git a/crypto/src/security/MacUtilities.cs b/crypto/src/security/MacUtilities.cs index 444e0fb42..6c10b41fa 100644 --- a/crypto/src/security/MacUtilities.cs +++ b/crypto/src/security/MacUtilities.cs @@ -17,8 +17,14 @@ namespace Org.BouncyCastle.Security { + /// + /// Factory for instances (HMAC, CMAC, GMAC, Poly1305, etc.) and convenience helpers for + /// one-shot MAC computation. + /// /// - /// Utility class for creating HMac object from their names/Oids + /// MACs can be looked up by canonical name (e.g. "HMAC-SHA256", "AESCMAC") or by ASN.1 OID; + /// names are matched case-insensitively. The returned is uninitialised — the caller + /// must invoke with a key before processing data. /// public static class MacUtilities { @@ -111,6 +117,12 @@ static MacUtilities() #endif } + /// + /// One-shot MAC of using the named algorithm and the supplied key parameters. + /// + /// A MAC name or alias (e.g. "HMAC-SHA256"). + /// Key (and any other) parameters required to initialise the MAC. + /// The data to authenticate. public static byte[] CalculateMac(string algorithm, ICipherParameters cp, byte[] input) { IMac mac = GetMac(algorithm); @@ -119,6 +131,7 @@ public static byte[] CalculateMac(string algorithm, ICipherParameters cp, byte[] return DoFinal(mac); } + /// Finalises and returns the resulting tag as a fresh array. public static byte[] DoFinal(IMac mac) { byte[] b = new byte[mac.GetMacSize()]; @@ -126,17 +139,26 @@ public static byte[] DoFinal(IMac mac) return b; } + /// Feeds into , then finalises and returns the + /// tag. public static byte[] DoFinal(IMac mac, byte[] input) { mac.BlockUpdate(input, 0, input.Length); return DoFinal(mac); } + /// + /// Returns the canonical algorithm name registered for the given ASN.1 OID, or null if the OID + /// is not mapped to a known MAC. + /// public static string GetAlgorithmName(DerObjectIdentifier oid) { return CollectionUtilities.GetValueOrNull(AlgorithmOidMap, oid); } + /// Resolve and instantiate an for the given ASN.1 algorithm OID. + /// If is null. + /// If the OID does not map to a known MAC. // TODO[api] Change parameter name to 'oid' public static IMac GetMac(DerObjectIdentifier id) { @@ -153,6 +175,11 @@ public static IMac GetMac(DerObjectIdentifier id) throw new SecurityUtilityException("Mac OID not recognised."); } + /// Resolve and instantiate an by name (or alias). + /// A MAC name (e.g. "HMAC-SHA512", "AESCMAC", + /// "POLY1305"). + /// If is null. + /// If the MAC name is not recognised. public static IMac GetMac(string algorithm) { if (algorithm == null) diff --git a/crypto/src/security/ParameterUtilities.cs b/crypto/src/security/ParameterUtilities.cs index 7dd76b0d1..d47e918d6 100644 --- a/crypto/src/security/ParameterUtilities.cs +++ b/crypto/src/security/ParameterUtilities.cs @@ -17,6 +17,17 @@ namespace Org.BouncyCastle.Security { + /// + /// Helpers for building values: creating algorithm-appropriate + /// instances, decoding ASN.1 algorithm parameters into IV-bearing + /// , generating random IV/parameter blocks, and wrapping/unwrapping + /// / envelopes. + /// + /// + /// Algorithm names are resolved through and matched + /// case-insensitively. DES, DES-EDE and RC2 receive their dedicated parameter subclasses with parity + /// enforcement; other algorithms get a plain . + /// public static class ParameterUtilities { private static readonly IDictionary Algorithms = @@ -195,21 +206,30 @@ private static void AddBasicIVSizeEntries(int size, params string[] algorithms) } } + /// + /// Returns the canonical algorithm name for the given alias or OID string, or null if the + /// algorithm is not recognised. + /// public static string GetCanonicalAlgorithmName(string algorithm) { return CollectionUtilities.GetValueOrNull(Algorithms, algorithm); } + /// + /// Build a for the algorithm identified by . + /// public static KeyParameter CreateKeyParameter(DerObjectIdentifier algOid, byte[] keyBytes) { return CreateKeyParameter(algOid.Id, keyBytes, 0, keyBytes.Length); } + /// Build a for the named algorithm. public static KeyParameter CreateKeyParameter(string algorithm, byte[] keyBytes) { return CreateKeyParameter(algorithm, keyBytes, 0, keyBytes.Length); } + /// Build a from a slice of . public static KeyParameter CreateKeyParameter( DerObjectIdentifier algOid, byte[] keyBytes, @@ -219,6 +239,13 @@ public static KeyParameter CreateKeyParameter( return CreateKeyParameter(algOid.Id, keyBytes, offset, length); } + /// + /// Build a from a slice of . DES / DES-EDE / RC2 + /// keys are returned as their dedicated parameter subclasses; all other algorithms get a plain + /// . + /// + /// If is null. + /// If the algorithm is not recognised. public static KeyParameter CreateKeyParameter( string algorithm, byte[] keyBytes, @@ -245,6 +272,11 @@ public static KeyParameter CreateKeyParameter( return new KeyParameter(keyBytes, offset, length); } + /// + /// Combine a key with ASN.1-encoded algorithm parameters, returning the appropriate + /// envelope (e.g. or + /// for AES-GCM/CCM). + /// public static ICipherParameters GetCipherParameters( DerObjectIdentifier algOid, ICipherParameters key, @@ -253,6 +285,13 @@ public static ICipherParameters GetCipherParameters( return GetCipherParameters(algOid.Id, key, asn1Params); } + /// + /// Combine a key with ASN.1-encoded algorithm parameters for the named algorithm. See the OID + /// overload. + /// + /// If cannot supply the data required by + /// an AEAD mode, or the parameters block cannot be parsed. + /// If the algorithm is not recognised. public static ICipherParameters GetCipherParameters( string algorithm, ICipherParameters key, @@ -330,6 +369,10 @@ public static ICipherParameters GetCipherParameters( throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised."); } + /// + /// Generate a fresh ASN.1-encoded algorithm parameters block (typically a random IV) for the + /// algorithm identified by . + /// public static Asn1Encodable GenerateParameters( DerObjectIdentifier algID, SecureRandom random) @@ -337,6 +380,14 @@ public static Asn1Encodable GenerateParameters( return GenerateParameters(algID.Id, random); } + /// + /// Generate a fresh ASN.1-encoded algorithm parameters block for the named algorithm. CAST5, IDEA and + /// RC2 receive their dedicated parameter structures; other IV-based algorithms get a plain + /// containing the IV. + /// + /// If is null. + /// If the algorithm is not recognised or has no + /// parameter generator. public static Asn1Encodable GenerateParameters( string algorithm, SecureRandom random) @@ -369,6 +420,17 @@ public static Asn1Encodable GenerateParameters( throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised."); } + /// + /// Unwrap a envelope, returning the inner parameters and copying the + /// context bytes out via . If the envelope is absent, + /// is set to null and the input is returned unchanged. + /// + /// Parameters to inspect. + /// Minimum permitted context length, inclusive. + /// Maximum permitted context length, inclusive. + /// Receives the context bytes, or null if no envelope is present. + /// If the context length falls outside + /// [, ]. public static ICipherParameters GetContext(ICipherParameters cipherParameters, int minLen, int maxLen, out byte[] context) { @@ -389,6 +451,11 @@ public static ICipherParameters GetContext(ICipherParameters cipherParameters, i return cipherParameters; } + /// + /// Unwrap a envelope, returning the inner parameters and exposing the + /// attached via . If the envelope is absent, + /// is set to null and the input is returned unchanged. + /// public static ICipherParameters GetRandom(ICipherParameters cipherParameters, out SecureRandom random) { if (cipherParameters is ParametersWithRandom withRandom) @@ -401,6 +468,10 @@ public static ICipherParameters GetRandom(ICipherParameters cipherParameters, ou return cipherParameters; } + /// + /// Strip any envelope and return the inner parameters; otherwise return + /// the input unchanged. + /// public static ICipherParameters IgnoreRandom(ICipherParameters cipherParameters) { if (cipherParameters is ParametersWithRandom withRandom) @@ -409,6 +480,10 @@ public static ICipherParameters IgnoreRandom(ICipherParameters cipherParameters) return cipherParameters; } + /// + /// Wrap in a envelope when + /// is non-null; otherwise return unchanged. + /// public static ICipherParameters WithContext(ICipherParameters cp, byte[] context) { if (context != null) @@ -418,6 +493,10 @@ public static ICipherParameters WithContext(ICipherParameters cp, byte[] context return cp; } + /// + /// Wrap in a envelope when + /// is non-null; otherwise return unchanged. + /// public static ICipherParameters WithRandom(ICipherParameters cp, SecureRandom random) { if (random != null) diff --git a/crypto/src/security/SignerUtilities.cs b/crypto/src/security/SignerUtilities.cs index f3bdb5c58..9af85ee74 100644 --- a/crypto/src/security/SignerUtilities.cs +++ b/crypto/src/security/SignerUtilities.cs @@ -26,8 +26,21 @@ namespace Org.BouncyCastle.Security { /// - /// Signer Utility class contains methods that can not be specifically grouped into other classes. + /// Factory for instances and helpers for resolving signature algorithm metadata + /// (X.509 algorithm parameters, OID lookup) from algorithm names or OIDs. /// + /// + /// + /// Algorithm names follow the JCA-style DIGESTwithCIPHER convention (for example + /// "SHA256withRSA", "SHA1withECDSA", "SHA256withRSAandMGF1") and a number of common + /// aliases are recognised; matching is case-insensitive. + /// + /// + /// The returned is uninitialised — the caller must invoke + /// before processing data, or use the higher-level + /// overloads. + /// + /// public static class SignerUtilities { private static readonly Dictionary AlgorithmMap = @@ -613,8 +626,14 @@ private static void AddAlgorithm(string name, DerObjectIdentifier oid, bool isNo } } + /// The set of canonical signature algorithm names recognised by this factory. public static ICollection Algorithms => CollectionUtilities.ReadOnly(Oids.Keys); + /// + /// Returns the default X.509 AlgorithmIdentifier parameters block for the given signature + /// algorithm OID. For RSASSA-PSS variants this constructs a populated RSASSA-PSS-params + /// structure; for most other algorithms is returned. + /// // TODO[api] Change parameter name to 'oid' public static Asn1Encodable GetDefaultX509Parameters(DerObjectIdentifier id) { @@ -627,6 +646,10 @@ public static Asn1Encodable GetDefaultX509Parameters(DerObjectIdentifier id) return GetDefaultX509ParametersForMechanism(mechanism); } + /// + /// Returns the default X.509 AlgorithmIdentifier parameters block for the named signature + /// algorithm. See the OID overload for behaviour. + /// public static Asn1Encodable GetDefaultX509Parameters(string algorithm) { if (algorithm == null) @@ -655,6 +678,10 @@ private static Asn1Encodable GetDefaultX509ParametersForMechanism(string mechani return DerNull.Instance; } + /// + /// Returns the canonical signature algorithm name registered for the given ASN.1 OID, or null + /// if the OID is not mapped. + /// public static string GetEncodingName(DerObjectIdentifier oid) { return CollectionUtilities.GetValueOrNull(AlgorithmOidMap, oid); @@ -704,6 +731,11 @@ private static Asn1Encodable GetPssX509Parameters( DerInteger.ValueOf(saltLen), RsassaPssParameters.DefaultTrailerField); } + /// + /// Resolve and instantiate an for the given ASN.1 algorithm OID. + /// + /// If is null. + /// If the OID does not map to a known signer. // TODO[api] Change parameter name to 'oid' public static ISigner GetSigner(DerObjectIdentifier id) { @@ -720,6 +752,12 @@ public static ISigner GetSigner(DerObjectIdentifier id) throw new SecurityUtilityException("Signer OID not recognised."); } + /// + /// Resolve and instantiate an by name (e.g. "SHA256withRSA", + /// "SHA1withECDSA", "Ed25519"). + /// + /// If is null. + /// If the algorithm name is not recognised. public static ISigner GetSigner(string algorithm) { if (algorithm == null) @@ -903,6 +941,17 @@ private static ISigner GetSignerForMechanism(string mechanism) return null; } + /// + /// Resolve a signer for the given OID and initialise it for signing or verification. + /// + /// The signature algorithm OID. + /// true to initialise for signing (private key required); + /// false for verification (public key). + /// The signing or verification key. + /// Source of randomness, used by signers that require it; ignored + /// otherwise. + /// If is null. + /// If the OID is not recognised. // TODO[api] Rename 'privateKey' to 'key' public static ISigner InitSigner(DerObjectIdentifier algorithmOid, bool forSigning, AsymmetricKeyParameter privateKey, SecureRandom random) @@ -916,6 +965,10 @@ public static ISigner InitSigner(DerObjectIdentifier algorithmOid, bool forSigni return InitSignerForMechanism(mechanism, forSigning, privateKey, random); } + /// + /// Resolve a signer by name and initialise it for signing or verification. See the OID overload for + /// parameter semantics. + /// // TODO[api] Rename 'privateKey' to 'key' public static ISigner InitSigner(string algorithm, bool forSigning, AsymmetricKeyParameter privateKey, SecureRandom random)