| | | 1 | | using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Utilities; |
| | | 2 | | |
| | | 3 | | namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto.Prng |
| | | 4 | | { |
| | | 5 | | internal class DigestRandomGenerator |
| | | 6 | | : IRandomGenerator |
| | | 7 | | { |
| | | 8 | | private const long CYCLE_COUNT = 10; |
| | | 9 | | |
| | | 10 | | private long stateCounter; |
| | | 11 | | private long seedCounter; |
| | | 12 | | private IDigest digest; |
| | | 13 | | private byte[] state; |
| | | 14 | | private byte[] seed; |
| | | 15 | | |
| | 10 | 16 | | public DigestRandomGenerator( |
| | 10 | 17 | | IDigest digest) |
| | 10 | 18 | | { |
| | 10 | 19 | | this.digest = digest; |
| | | 20 | | |
| | 10 | 21 | | this.seed = new byte[digest.GetDigestSize()]; |
| | 10 | 22 | | this.seedCounter = 1; |
| | | 23 | | |
| | 10 | 24 | | this.state = new byte[digest.GetDigestSize()]; |
| | 10 | 25 | | this.stateCounter = 1; |
| | 10 | 26 | | } |
| | | 27 | | |
| | | 28 | | public void AddSeedMaterial( |
| | | 29 | | byte[] inSeed) |
| | 10 | 30 | | { |
| | 10 | 31 | | lock (this) |
| | 10 | 32 | | { |
| | 10 | 33 | | DigestUpdate(inSeed); |
| | 10 | 34 | | DigestUpdate(seed); |
| | 10 | 35 | | DigestDoFinal(seed); |
| | 10 | 36 | | } |
| | 10 | 37 | | } |
| | | 38 | | |
| | | 39 | | public void AddSeedMaterial( |
| | | 40 | | long rSeed) |
| | 10 | 41 | | { |
| | 10 | 42 | | lock (this) |
| | 10 | 43 | | { |
| | 10 | 44 | | DigestAddCounter(rSeed); |
| | 10 | 45 | | DigestUpdate(seed); |
| | 10 | 46 | | DigestDoFinal(seed); |
| | 10 | 47 | | } |
| | 10 | 48 | | } |
| | | 49 | | |
| | | 50 | | public void NextBytes( |
| | | 51 | | byte[] bytes) |
| | 9 | 52 | | { |
| | 9 | 53 | | NextBytes(bytes, 0, bytes.Length); |
| | 9 | 54 | | } |
| | | 55 | | |
| | | 56 | | public void NextBytes( |
| | | 57 | | byte[] bytes, |
| | | 58 | | int start, |
| | | 59 | | int len) |
| | 9 | 60 | | { |
| | 9 | 61 | | lock (this) |
| | 9 | 62 | | { |
| | 9 | 63 | | int stateOff = 0; |
| | | 64 | | |
| | 9 | 65 | | GenerateState(); |
| | | 66 | | |
| | 9 | 67 | | int end = start + len; |
| | 894 | 68 | | for (int i = start; i < end; ++i) |
| | 438 | 69 | | { |
| | 438 | 70 | | if (stateOff == state.Length) |
| | 9 | 71 | | { |
| | 9 | 72 | | GenerateState(); |
| | 9 | 73 | | stateOff = 0; |
| | 9 | 74 | | } |
| | 438 | 75 | | bytes[i] = state[stateOff++]; |
| | 438 | 76 | | } |
| | 9 | 77 | | } |
| | 9 | 78 | | } |
| | | 79 | | |
| | | 80 | | private void CycleSeed() |
| | 0 | 81 | | { |
| | 0 | 82 | | DigestUpdate(seed); |
| | 0 | 83 | | DigestAddCounter(seedCounter++); |
| | 0 | 84 | | DigestDoFinal(seed); |
| | 0 | 85 | | } |
| | | 86 | | |
| | | 87 | | private void GenerateState() |
| | 18 | 88 | | { |
| | 18 | 89 | | DigestAddCounter(stateCounter++); |
| | 18 | 90 | | DigestUpdate(state); |
| | 18 | 91 | | DigestUpdate(seed); |
| | 18 | 92 | | DigestDoFinal(state); |
| | | 93 | | |
| | 18 | 94 | | if ((stateCounter % CYCLE_COUNT) == 0) |
| | 0 | 95 | | { |
| | 0 | 96 | | CycleSeed(); |
| | 0 | 97 | | } |
| | 18 | 98 | | } |
| | | 99 | | |
| | | 100 | | private void DigestAddCounter(long seedVal) |
| | 28 | 101 | | { |
| | 28 | 102 | | byte[] bytes = new byte[8]; |
| | 28 | 103 | | Pack.UInt64_To_LE((ulong)seedVal, bytes); |
| | 28 | 104 | | digest.BlockUpdate(bytes, 0, bytes.Length); |
| | 28 | 105 | | } |
| | | 106 | | |
| | | 107 | | private void DigestUpdate(byte[] inSeed) |
| | 66 | 108 | | { |
| | 66 | 109 | | digest.BlockUpdate(inSeed, 0, inSeed.Length); |
| | 66 | 110 | | } |
| | | 111 | | |
| | | 112 | | private void DigestDoFinal(byte[] result) |
| | 38 | 113 | | { |
| | 38 | 114 | | digest.DoFinal(result, 0); |
| | 38 | 115 | | } |
| | | 116 | | } |
| | | 117 | | } |