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;