| | | 1 | | // Licensed to the .NET Foundation under one or more agreements. |
| | | 2 | | // The .NET Foundation licenses this file to you under the MIT license. |
| | | 3 | | |
| | | 4 | | using System; |
| | | 5 | | using System.Security.Cryptography; |
| | | 6 | | using CoreWCF.Runtime; |
| | | 7 | | |
| | | 8 | | namespace CoreWCF.IdentityModel |
| | | 9 | | { |
| | | 10 | | internal sealed class Psha1DerivedKeyGenerator |
| | | 11 | | { |
| | | 12 | | private readonly byte[] _key; |
| | | 13 | | |
| | 10 | 14 | | public Psha1DerivedKeyGenerator(byte[] key) |
| | | 15 | | { |
| | 10 | 16 | | _key = key ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(key)); |
| | 10 | 17 | | } |
| | | 18 | | |
| | | 19 | | public byte[] GenerateDerivedKey(byte[] label, byte[] nonce, int derivedKeySize, int position) |
| | | 20 | | { |
| | 10 | 21 | | if (label == null) |
| | | 22 | | { |
| | 0 | 23 | | throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(label)); |
| | | 24 | | } |
| | 10 | 25 | | if (nonce == null) |
| | | 26 | | { |
| | 0 | 27 | | throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(nonce)); |
| | | 28 | | } |
| | 10 | 29 | | ManagedPsha1 dkcp = new ManagedPsha1(_key, label, nonce); |
| | 10 | 30 | | return dkcp.GetDerivedKey(derivedKeySize, position); |
| | | 31 | | } |
| | | 32 | | |
| | | 33 | | // private class to do the real work |
| | | 34 | | // Note: Though named ManagedPsha1, this works for both fips and non-fips compliance |
| | | 35 | | private sealed class ManagedPsha1 |
| | | 36 | | { |
| | | 37 | | private byte[] _aValue; |
| | | 38 | | private readonly byte[] _buffer; |
| | | 39 | | private byte[] _chunk; |
| | | 40 | | private readonly KeyedHashAlgorithm _hmac; |
| | | 41 | | private int _index; |
| | | 42 | | private int _position; |
| | | 43 | | private readonly byte[] _secret; |
| | | 44 | | private readonly byte[] _seed; |
| | | 45 | | |
| | | 46 | | // assume arguments are already validated |
| | 10 | 47 | | public ManagedPsha1(byte[] secret, byte[] label, byte[] seed) |
| | | 48 | | { |
| | 10 | 49 | | _secret = secret; |
| | 10 | 50 | | _seed = Fx.AllocateByteArray(checked(label.Length + seed.Length)); |
| | 10 | 51 | | label.CopyTo(_seed, 0); |
| | 10 | 52 | | seed.CopyTo(_seed, label.Length); |
| | | 53 | | |
| | 10 | 54 | | _aValue = _seed; |
| | 10 | 55 | | _chunk = Array.Empty<byte>(); |
| | 10 | 56 | | _index = 0; |
| | 10 | 57 | | _position = 0; |
| | 10 | 58 | | _hmac = CryptoHelper.NewHmacSha1KeyedHashAlgorithm(secret); |
| | | 59 | | |
| | 10 | 60 | | _buffer = Fx.AllocateByteArray(checked(_hmac.HashSize / 8 + _seed.Length)); |
| | 10 | 61 | | } |
| | | 62 | | |
| | | 63 | | public byte[] GetDerivedKey(int derivedKeySize, int position) |
| | | 64 | | { |
| | 10 | 65 | | if (derivedKeySize < 0) |
| | | 66 | | { |
| | 0 | 67 | | throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(der |
| | | 68 | | } |
| | 10 | 69 | | if (_position > position) |
| | | 70 | | { |
| | 0 | 71 | | throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(pos |
| | | 72 | | } |
| | | 73 | | |
| | | 74 | | // Seek to the desired position in the pseudo-random stream. |
| | 10 | 75 | | while (_position < position) |
| | | 76 | | { |
| | 0 | 77 | | GetByte(); |
| | | 78 | | } |
| | 10 | 79 | | int sizeInBytes = derivedKeySize / 8; |
| | 10 | 80 | | byte[] derivedKey = new byte[sizeInBytes]; |
| | 660 | 81 | | for (int i = 0; i < sizeInBytes; i++) |
| | | 82 | | { |
| | 320 | 83 | | derivedKey[i] = GetByte(); |
| | | 84 | | } |
| | 10 | 85 | | return derivedKey; |
| | | 86 | | } |
| | | 87 | | |
| | | 88 | | private byte GetByte() |
| | | 89 | | { |
| | 320 | 90 | | if (_index >= _chunk.Length) |
| | | 91 | | { |
| | | 92 | | // Calculate A(i) = HMAC_SHA1(secret, A(i-1)). |
| | 20 | 93 | | _hmac.Initialize(); |
| | 20 | 94 | | _aValue = _hmac.ComputeHash(_aValue); |
| | | 95 | | // Calculate P_SHA1(secret, seed)[j] = HMAC_SHA1(secret, A(j+1) || seed). |
| | 20 | 96 | | _aValue.CopyTo(_buffer, 0); |
| | 20 | 97 | | _seed.CopyTo(_buffer, _aValue.Length); |
| | 20 | 98 | | _hmac.Initialize(); |
| | 20 | 99 | | _chunk = _hmac.ComputeHash(_buffer); |
| | 20 | 100 | | _index = 0; |
| | | 101 | | } |
| | 320 | 102 | | _position++; |
| | 320 | 103 | | return _chunk[_index++]; |
| | | 104 | | } |
| | | 105 | | } |
| | | 106 | | } |
| | | 107 | | } |