diff --git a/JoinFS.Tests/ProgramCode.cs b/JoinFS.Tests/ProgramCode.cs index f09fdeb9..c5122f56 100644 --- a/JoinFS.Tests/ProgramCode.cs +++ b/JoinFS.Tests/ProgramCode.cs @@ -1,5 +1,6 @@ using System; using System.Text; +using System.Security.Cryptography; namespace JoinFS.Tests { @@ -9,6 +10,39 @@ namespace JoinFS.Tests /// public static class ProgramCode { + /// + /// Cryptographically secure random number generator seeded with a key + /// + private class SeededCryptoRandom + { + private readonly byte[] seed; + private int counter; + + public SeededCryptoRandom(int key) + { + seed = BitConverter.GetBytes(key); + counter = 0; + } + + /// + /// Generate a deterministic but cryptographically derived random number in range [0, maxValue) + /// + public int Next(int maxValue) + { + if (maxValue <= 0) + throw new ArgumentOutOfRangeException(nameof(maxValue)); + + // Use HMACSHA256 to derive random value from seed and counter + using (var hmac = new HMACSHA256(seed)) + { + byte[] counterBytes = BitConverter.GetBytes(counter++); + byte[] hash = hmac.ComputeHash(counterBytes); + uint randomValue = BitConverter.ToUInt32(hash, 0); + return (int)(randomValue % (uint)maxValue); + } + } + } + public static string? Code(string? s, bool bToCode, int nKey) { if (s == null) @@ -70,7 +104,7 @@ public static class ProgramCode int nInc = 0; int k; const int nPasses = 11; - Random rnd = new Random(nKey); + SeededCryptoRandom rnd = new SeededCryptoRandom(nKey); for (int j = 0; j < nPasses; ++j) { k = (bToCode) ? j : nPasses - j - 1; diff --git a/JoinFS/Program.cs b/JoinFS/Program.cs index 8bfdc276..bf099134 100644 --- a/JoinFS/Program.cs +++ b/JoinFS/Program.cs @@ -12,6 +12,7 @@ using System.Configuration; using System.Globalization; using System.Reflection; +using System.Security.Cryptography; using JoinFS.Properties; namespace JoinFS @@ -1935,6 +1936,39 @@ public void MonitorAircraftDetails() static class Program { + /// + /// Cryptographically secure random number generator seeded with a key + /// + private class SeededCryptoRandom + { + private readonly byte[] seed; + private int counter; + + public SeededCryptoRandom(int key) + { + seed = BitConverter.GetBytes(key); + counter = 0; + } + + /// + /// Generate a deterministic but cryptographically derived random number in range [0, maxValue) + /// + public int Next(int maxValue) + { + if (maxValue <= 0) + throw new ArgumentOutOfRangeException(nameof(maxValue)); + + // Use HMACSHA256 to derive random value from seed and counter + using (var hmac = new HMACSHA256(seed)) + { + byte[] counterBytes = BitConverter.GetBytes(counter++); + byte[] hash = hmac.ComputeHash(counterBytes); + uint randomValue = BitConverter.ToUInt32(hash, 0); + return (int)(randomValue % (uint)maxValue); + } + } + } + public static string Code(string s, bool bToCode, int nKey) { if (s == null) @@ -1996,7 +2030,7 @@ public static string Code(string s, bool bToCode, int nKey) int nInc = 0; int k; const int nPasses = 11; - Random rnd = new Random(nKey); + SeededCryptoRandom rnd = new SeededCryptoRandom(nKey); for (int j = 0; j < nPasses; ++j) { k = (bToCode) ? j : nPasses - j - 1;