From f7306bc440ebf000b31d302868fbd1997b2ae69f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 4 Dec 2025 21:20:20 +0000
Subject: [PATCH 1/4] Initial plan
From aacaeb28adb882ff6a70ab321752a8a76219136e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 4 Dec 2025 21:24:55 +0000
Subject: [PATCH 2/4] Replace System.Random with cryptographically secure
HMACSHA256-based PRNG
Co-authored-by: tuduce <73273884+tuduce@users.noreply.github.com>
---
JoinFS.Tests/ProgramCode.cs | 48 ++++++++++++++++++++++++++++++++++++-
JoinFS/Program.cs | 48 ++++++++++++++++++++++++++++++++++++-
2 files changed, 94 insertions(+), 2 deletions(-)
diff --git a/JoinFS.Tests/ProgramCode.cs b/JoinFS.Tests/ProgramCode.cs
index f09fdeb9..5f8e0f50 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,51 @@ namespace JoinFS.Tests
///
public static class ProgramCode
{
+ ///
+ /// Cryptographically secure random number generator seeded with a key
+ ///
+ private class SeededCryptoRandom
+ {
+ private readonly byte[] keyState;
+ private int counter;
+
+ public SeededCryptoRandom(int key)
+ {
+ // Create deterministic initial state from key using SHA256
+ byte[] keyBytes = BitConverter.GetBytes(key);
+ using (var sha256 = System.Security.Cryptography.SHA256.Create())
+ {
+ keyState = sha256.ComputeHash(keyBytes);
+ }
+ 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));
+
+ // Derive random bytes deterministically from key state and counter
+ byte[] input = new byte[keyState.Length + 4];
+ Buffer.BlockCopy(keyState, 0, input, 0, keyState.Length);
+ Buffer.BlockCopy(BitConverter.GetBytes(counter++), 0, input, keyState.Length, 4);
+
+ // Use HMACSHA256 for cryptographically strong deterministic generation
+ byte[] output;
+ using (var hmac = new System.Security.Cryptography.HMACSHA256(keyState))
+ {
+ output = hmac.ComputeHash(input);
+ }
+
+ // Convert first 4 bytes to int and ensure it's in the desired range
+ uint randomValue = BitConverter.ToUInt32(output, 0);
+ return (int)(randomValue % (uint)maxValue);
+ }
+ }
+
public static string? Code(string? s, bool bToCode, int nKey)
{
if (s == null)
@@ -70,7 +116,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..3bb02288 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,51 @@ public void MonitorAircraftDetails()
static class Program
{
+ ///
+ /// Cryptographically secure random number generator seeded with a key
+ ///
+ private class SeededCryptoRandom
+ {
+ private readonly byte[] keyState;
+ private int counter;
+
+ public SeededCryptoRandom(int key)
+ {
+ // Create deterministic initial state from key using SHA256
+ byte[] keyBytes = BitConverter.GetBytes(key);
+ using (var sha256 = System.Security.Cryptography.SHA256.Create())
+ {
+ keyState = sha256.ComputeHash(keyBytes);
+ }
+ 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));
+
+ // Derive random bytes deterministically from key state and counter
+ byte[] input = new byte[keyState.Length + 4];
+ Buffer.BlockCopy(keyState, 0, input, 0, keyState.Length);
+ Buffer.BlockCopy(BitConverter.GetBytes(counter++), 0, input, keyState.Length, 4);
+
+ // Use HMACSHA256 for cryptographically strong deterministic generation
+ byte[] output;
+ using (var hmac = new System.Security.Cryptography.HMACSHA256(keyState))
+ {
+ output = hmac.ComputeHash(input);
+ }
+
+ // Convert first 4 bytes to int and ensure it's in the desired range
+ uint randomValue = BitConverter.ToUInt32(output, 0);
+ return (int)(randomValue % (uint)maxValue);
+ }
+ }
+
public static string Code(string s, bool bToCode, int nKey)
{
if (s == null)
@@ -1996,7 +2042,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;
From 99c3d02d872a11503bad2894aeb2d27b7c0d3700 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 4 Dec 2025 21:26:37 +0000
Subject: [PATCH 3/4] Address code review: Simplify using statements and add
modulo bias note
Co-authored-by: tuduce <73273884+tuduce@users.noreply.github.com>
---
JoinFS.Tests/ProgramCode.cs | 6 ++++--
JoinFS/Program.cs | 6 ++++--
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/JoinFS.Tests/ProgramCode.cs b/JoinFS.Tests/ProgramCode.cs
index 5f8e0f50..c09d3518 100644
--- a/JoinFS.Tests/ProgramCode.cs
+++ b/JoinFS.Tests/ProgramCode.cs
@@ -22,7 +22,7 @@ public SeededCryptoRandom(int key)
{
// Create deterministic initial state from key using SHA256
byte[] keyBytes = BitConverter.GetBytes(key);
- using (var sha256 = System.Security.Cryptography.SHA256.Create())
+ using (var sha256 = SHA256.Create())
{
keyState = sha256.ComputeHash(keyBytes);
}
@@ -44,12 +44,14 @@ public int Next(int maxValue)
// Use HMACSHA256 for cryptographically strong deterministic generation
byte[] output;
- using (var hmac = new System.Security.Cryptography.HMACSHA256(keyState))
+ using (var hmac = new HMACSHA256(keyState))
{
output = hmac.ComputeHash(input);
}
// Convert first 4 bytes to int and ensure it's in the desired range
+ // Note: Using modulo introduces slight bias, but we maintain this approach
+ // for backward compatibility with the original implementation
uint randomValue = BitConverter.ToUInt32(output, 0);
return (int)(randomValue % (uint)maxValue);
}
diff --git a/JoinFS/Program.cs b/JoinFS/Program.cs
index 3bb02288..1b5ebbc6 100644
--- a/JoinFS/Program.cs
+++ b/JoinFS/Program.cs
@@ -1948,7 +1948,7 @@ public SeededCryptoRandom(int key)
{
// Create deterministic initial state from key using SHA256
byte[] keyBytes = BitConverter.GetBytes(key);
- using (var sha256 = System.Security.Cryptography.SHA256.Create())
+ using (var sha256 = SHA256.Create())
{
keyState = sha256.ComputeHash(keyBytes);
}
@@ -1970,12 +1970,14 @@ public int Next(int maxValue)
// Use HMACSHA256 for cryptographically strong deterministic generation
byte[] output;
- using (var hmac = new System.Security.Cryptography.HMACSHA256(keyState))
+ using (var hmac = new HMACSHA256(keyState))
{
output = hmac.ComputeHash(input);
}
// Convert first 4 bytes to int and ensure it's in the desired range
+ // Note: Using modulo introduces slight bias, but we maintain this approach
+ // for backward compatibility with the original implementation
uint randomValue = BitConverter.ToUInt32(output, 0);
return (int)(randomValue % (uint)maxValue);
}
From 9fb5f9cd4af58895e22c578e277e5675f6484919 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 4 Dec 2025 21:38:29 +0000
Subject: [PATCH 4/4] Simplify SeededCryptoRandom: Remove SHA256 layer, use
HMACSHA256 directly
Co-authored-by: tuduce <73273884+tuduce@users.noreply.github.com>
---
JoinFS.Tests/ProgramCode.cs | 30 ++++++++----------------------
JoinFS/Program.cs | 30 ++++++++----------------------
2 files changed, 16 insertions(+), 44 deletions(-)
diff --git a/JoinFS.Tests/ProgramCode.cs b/JoinFS.Tests/ProgramCode.cs
index c09d3518..c5122f56 100644
--- a/JoinFS.Tests/ProgramCode.cs
+++ b/JoinFS.Tests/ProgramCode.cs
@@ -15,17 +15,12 @@ public static class ProgramCode
///
private class SeededCryptoRandom
{
- private readonly byte[] keyState;
+ private readonly byte[] seed;
private int counter;
public SeededCryptoRandom(int key)
{
- // Create deterministic initial state from key using SHA256
- byte[] keyBytes = BitConverter.GetBytes(key);
- using (var sha256 = SHA256.Create())
- {
- keyState = sha256.ComputeHash(keyBytes);
- }
+ seed = BitConverter.GetBytes(key);
counter = 0;
}
@@ -37,23 +32,14 @@ public int Next(int maxValue)
if (maxValue <= 0)
throw new ArgumentOutOfRangeException(nameof(maxValue));
- // Derive random bytes deterministically from key state and counter
- byte[] input = new byte[keyState.Length + 4];
- Buffer.BlockCopy(keyState, 0, input, 0, keyState.Length);
- Buffer.BlockCopy(BitConverter.GetBytes(counter++), 0, input, keyState.Length, 4);
-
- // Use HMACSHA256 for cryptographically strong deterministic generation
- byte[] output;
- using (var hmac = new HMACSHA256(keyState))
+ // Use HMACSHA256 to derive random value from seed and counter
+ using (var hmac = new HMACSHA256(seed))
{
- output = hmac.ComputeHash(input);
+ byte[] counterBytes = BitConverter.GetBytes(counter++);
+ byte[] hash = hmac.ComputeHash(counterBytes);
+ uint randomValue = BitConverter.ToUInt32(hash, 0);
+ return (int)(randomValue % (uint)maxValue);
}
-
- // Convert first 4 bytes to int and ensure it's in the desired range
- // Note: Using modulo introduces slight bias, but we maintain this approach
- // for backward compatibility with the original implementation
- uint randomValue = BitConverter.ToUInt32(output, 0);
- return (int)(randomValue % (uint)maxValue);
}
}
diff --git a/JoinFS/Program.cs b/JoinFS/Program.cs
index 1b5ebbc6..bf099134 100644
--- a/JoinFS/Program.cs
+++ b/JoinFS/Program.cs
@@ -1941,17 +1941,12 @@ static class Program
///
private class SeededCryptoRandom
{
- private readonly byte[] keyState;
+ private readonly byte[] seed;
private int counter;
public SeededCryptoRandom(int key)
{
- // Create deterministic initial state from key using SHA256
- byte[] keyBytes = BitConverter.GetBytes(key);
- using (var sha256 = SHA256.Create())
- {
- keyState = sha256.ComputeHash(keyBytes);
- }
+ seed = BitConverter.GetBytes(key);
counter = 0;
}
@@ -1963,23 +1958,14 @@ public int Next(int maxValue)
if (maxValue <= 0)
throw new ArgumentOutOfRangeException(nameof(maxValue));
- // Derive random bytes deterministically from key state and counter
- byte[] input = new byte[keyState.Length + 4];
- Buffer.BlockCopy(keyState, 0, input, 0, keyState.Length);
- Buffer.BlockCopy(BitConverter.GetBytes(counter++), 0, input, keyState.Length, 4);
-
- // Use HMACSHA256 for cryptographically strong deterministic generation
- byte[] output;
- using (var hmac = new HMACSHA256(keyState))
+ // Use HMACSHA256 to derive random value from seed and counter
+ using (var hmac = new HMACSHA256(seed))
{
- output = hmac.ComputeHash(input);
+ byte[] counterBytes = BitConverter.GetBytes(counter++);
+ byte[] hash = hmac.ComputeHash(counterBytes);
+ uint randomValue = BitConverter.ToUInt32(hash, 0);
+ return (int)(randomValue % (uint)maxValue);
}
-
- // Convert first 4 bytes to int and ensure it's in the desired range
- // Note: Using modulo introduces slight bias, but we maintain this approach
- // for backward compatibility with the original implementation
- uint randomValue = BitConverter.ToUInt32(output, 0);
- return (int)(randomValue % (uint)maxValue);
}
}