/// <summary> /// Creates a new instance of <see cref="BlockDigestAlgorithm"/> which wraps this <see cref="BlockDigestAlgorithm"/>, and adds HMAC support. /// </summary> /// <param name="algorithm">This <see cref="BlockDigestAlgorithm"/>.</param> /// <param name="key">The key to use in HMAC.</param> /// <param name="skipDisposeAlgorithm">Whether to skip disposing this <see cref="BlockDigestAlgorithm"/> when returned HMAC <see cref="BlockDigestAlgorithm"/> is disposed.</param> /// <param name="skipZeroingOutKey">Whether to skip zeroing out the key array when the returned HMAC <see cref="BlockDigestAlgorithm"/> is disposed.</param> /// <returns>A new instance of <see cref="BlockDigestAlgorithm"/> with HMAC support.</returns> /// <exception cref="NullReferenceException">If this <see cref="BlockDigestAlgorithm"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">If <paramref name="key"/> is <c>null</c>.</exception> /// <remarks> /// The returned <see cref="BlockDigestAlgorithm"/> will assume the given <paramref name="key"/> as its own, and will write to it. If that is undesirable, please pass a copy of an array as <paramref name="key"/>. /// </remarks> public static BlockDigestAlgorithm CreateHMAC( this BlockDigestAlgorithm algorithm, Byte[] key, Boolean skipDisposeAlgorithm = false, Boolean skipZeroingOutKey = false ) => algorithm.CreateHMAC(key, 0, key?.Length ?? 0, skipDisposeAlgorithm: skipDisposeAlgorithm, skipZeroingOutKey: skipZeroingOutKey);
/// <summary> /// Creates a new instance of <see cref="SASLMechanism"/> that implements server-side SCRAM mechanism with this <see cref="BlockDigestAlgorithm"/>. /// </summary> /// <param name="algorithm">This <see cref="BlockDigestAlgorithm"/>, that will be used by SCRAM mechanism as its digest provider.</param> /// <param name="getCredentials">The callback to get <see cref="SASLCredentialsSCRAMForServer"/> for given username.</param> /// <param name="nonceGenerator">The optional custom callback to provide nonce. Please read remarks if supplying value.</param> /// <returns>A new <see cref="SASLMechanism"/> which will behave as server-side when authenticating with SCRAM.</returns> /// <remarks> /// <para> /// The returned <see cref="SASLMechanism"/> will expect the <see cref="SASLChallengeArguments.Credentials"/> field to always be non-null and of type <see cref="SASLCredentialsHolder"/>. /// </para> /// <para> /// The <paramref name="nonceGenerator"/>, if supplied, *must* return valid nonce (e.g. not containing any commas, printable ASCII characters, etc). /// The returned nonce will be directly written to the message - it is not base64-encoded! /// </para> /// </remarks> /// <exception cref="NullReferenceException">If this <see cref="BlockDigestAlgorithm"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">If <paramref name="getCredentials"/> is <c>null</c>.</exception> /// <seealso cref="SASLCredentialsSCRAMForClient"/> /// <seealso cref="SCRAMCommon"/> public static SASLMechanism CreateSASLServerSCRAM( this BlockDigestAlgorithm algorithm, Func <String, ValueTask <SASLCredentialsSCRAMForServer> > getCredentials, Func <Byte[]> nonceGenerator = null ) { return(new SASLMechanismSCRAMForServer(ArgumentValidator.ValidateNotNullReference(algorithm), getCredentials, nonceGenerator)); }
internal static Byte[] UseNonceGenerator(BlockDigestAlgorithm algorithm, Func <Byte[]> nonceGenerator) { var retVal = nonceGenerator?.Invoke(); return(retVal.IsNullOrEmpty() ? GenerateNonce(algorithm, 24, 32) : retVal); // Let's not check it after all - but document that nonce returned by factory is not checked! }
private readonly ResizableArray <Byte> _clientMessage; // Temporary storage for data to be preserved between Challenge invocations public SASLMechanismSCRAMForClient( BlockDigestAlgorithm algorithm, Func <Byte[]> clientNonceGenerator ) { this._algorithm = ArgumentValidator.ValidateNotNull(nameof(algorithm), algorithm); this._nonceGenerator = clientNonceGenerator; this._clientMessage = new ResizableArray <Byte>(exponentialResize: false); }
public HMACBlockDigestAlgorithm( BlockDigestAlgorithm actual, Byte[] key, Int32 keyOffset, Int32 keyLength, Boolean skipDisposeAlgorithm, Boolean skipZeroingKeyOnDispose ) { this._actual = ArgumentValidator.ValidateNotNull(nameof(actual), actual); ArgumentValidator.ValidateNotNull(nameof(key), key); // Check if the key is too long var blockSize = actual.BlockSize; this._skipDisposeAlgorithm = skipDisposeAlgorithm; this._skipZeroingKeyOnDispose = skipZeroingKeyOnDispose; if (keyLength > blockSize) { // Compute hash of the key actual.ProcessBlock(key); actual.WriteDigest(key, keyOffset); // Explicitly set trailing zeroes key.Clear(keyOffset + actual.DigestByteCount, keyLength - actual.DigestByteCount); } else if (keyLength < blockSize) { if (key.Length < keyOffset + blockSize) { var newKey = new Byte[blockSize]; key.CopyTo(newKey); keyOffset = 0; key = newKey; // There will be trailing zeroes, as a new array was allocated this._skipZeroingKeyOnDispose = false; // Always zero out, since we created the array here. } else { // Explicitly set trailing zeroes key.Clear(keyOffset + keyLength, blockSize - keyLength); } } this._key = key; this._keyOffset = keyOffset; }
/// <summary> /// This is convenience method to create new <see cref="DigestBasedRandomGenerator"/> and seed it with default, secure logic. /// </summary> /// <param name="algorithm">The algorithm that returned <see cref="DigestBasedRandomGenerator"/> should use.</param> /// <param name="seedCycleCount">How often to re-seed the state of returned <see cref="DigestBasedRandomGenerator"/>.</param> /// <param name="skipDisposeAlgorithm">Optional parameter controlling whether the <see cref="DigestBasedRandomGenerator"/> will, when disposed, dispose also the given <paramref name="algorithm"/>.</param> /// <returns>A new instance of <see cref="DigestBasedRandomGenerator"/> with given parameters.</returns> /// <exception cref="ArgumentNullException">If <paramref name="algorithm"/> is <c>null</c>.</exception> public static DigestBasedRandomGenerator CreateAndSeedWithDefaultLogic( BlockDigestAlgorithm algorithm, Int32 seedCycleCount = DEFAULT_SEED_CYCLE_COUNT, Boolean skipDisposeAlgorithm = false ) { var retVal = new DigestBasedRandomGenerator(algorithm, seedCycleCount, skipDisposeAlgorithm); // Use Guid as random source (should be version 4) retVal.AddSeedMaterial(Guid.NewGuid().ToByteArray()); // Use current ticks retVal.AddSeedMaterial(DateTime.Now.Ticks); // Use Guid again retVal.AddSeedMaterial(Guid.NewGuid().ToByteArray()); return(retVal); }
/// <summary> /// Creates a new instance of <see cref="BlockDigestAlgorithm"/> which wraps this <see cref="BlockDigestAlgorithm"/>, and adds HMAC support. /// </summary> /// <param name="algorithm">This <see cref="BlockDigestAlgorithm"/>.</param> /// <param name="key">The key to use in HMAC.</param> /// <param name="offset">The offset in <paramref name="key"/> array where the key content starts.</param> /// <param name="count">The amount of bytes in <paramref name="key"/> which are key bytes.</param> /// <param name="skipDisposeAlgorithm">Whether to skip disposing this <see cref="BlockDigestAlgorithm"/> when returned HMAC <see cref="BlockDigestAlgorithm"/> is disposed.</param> /// <param name="skipZeroingOutKey">Whether to skip zeroing out the key array when the returned HMAC <see cref="BlockDigestAlgorithm"/> is disposed.</param> /// <returns>A new instance of <see cref="BlockDigestAlgorithm"/> with HMAC support.</returns> /// <exception cref="NullReferenceException">If this <see cref="BlockDigestAlgorithm"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">If <paramref name="key"/> is <c>null</c>.</exception> /// <remarks> /// The returned <see cref="BlockDigestAlgorithm"/> will assume the given <paramref name="key"/> as its own, and will write to it. If that is undesirable, please pass a copy of an array as <paramref name="key"/>. /// </remarks> public static BlockDigestAlgorithm CreateHMAC( this BlockDigestAlgorithm algorithm, Byte[] key, Int32 offset, Int32 count, Boolean skipDisposeAlgorithm = false, Boolean skipZeroingOutKey = false ) { return(new HMACBlockDigestAlgorithm( ArgumentValidator.ValidateNotNullReference(algorithm), key, offset, count, skipDisposeAlgorithm, skipZeroingOutKey )); }
//private static void CheckCustomNonce( BlockDigestAlgorithm algorithm, Byte[] nonce ) //{ // using ( var randomLazy = new LazyDisposable<SecureRandom>( () => new SecureRandom( DigestBasedRandomGenerator.CreateAndSeedWithDefaultLogic( algorithm, skipDisposeAlgorithm: true ) ) ) ) // { // for ( var i = 0; i < nonce.Length; ++i ) // { // var b = nonce[i]; // if (b < ) // } // } //} internal static Byte[] GenerateNonce(BlockDigestAlgorithm algorithm, Int32 minSize, Int32 maxValue) { using (var random = new SecureRandom(DigestBasedRandomGenerator.CreateAndSeedWithDefaultLogic(algorithm, skipDisposeAlgorithm: true))) { var retVal = new Byte[random.Next(minSize, maxValue)]; // Actual legal values are 0x21-0x7E for (var i = 0; i < retVal.Length; ++i) { Byte nextVal; do { nextVal = (Byte)random.Next(0x21, 0x7F); retVal[i] = nextVal; } while (nextVal == COMMA); // ... except commas not allowed } return(retVal); } }