Implement GetInt and GetString for Randomness
MODIFY
WalletWasabi.Tests/UnitTests/IoTests.cs
WalletWasabi.Tests/UnitTests/IoTests.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using WalletWasabi.Crypto.Randomness;
using WalletWasabi.Helpers;
using WalletWasabi.Io;
using Xunit;
@@ -23,8 +24,7 @@ namespace WalletWasabi.Tests.UnitTests
List<string> lines = new List<string>();
for (int i = 0; i < 1000; i++)
{
- string line = new string(Enumerable.Repeat(Constants.Chars, 100)
- .Select(s => s[random.Next(s.Length)]).ToArray());
+ string line = (new UnsecureRandom() as IWasabiRandom).GetString(100, Characters.AlphaNumeric);
lines.Add(line);
}

MODIFY
WalletWasabi.Tests/UnitTests/KeyManagementTests.cs
WalletWasabi.Tests/UnitTests/KeyManagementTests.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Security;
using WalletWasabi.Blockchain.Analysis.Clustering;
using WalletWasabi.Blockchain.Keys;
+using WalletWasabi.Crypto.Randomness;
using WalletWasabi.Helpers;
using WalletWasabi.Logging;
using WalletWasabi.Tests.XunitConfiguration;
@@ -123,7 +124,7 @@ namespace WalletWasabi.Tests.UnitTests
for (int i = 0; i < 1000; i++)
{
var isInternal = random.Next(2) == 0;
- var label = RandomString.Generate(21);
+ var label = (new WalletWasabi.Crypto.Randomness.UnsecureRandom() as IWasabiRandom).GetString(21, Characters.AlphaNumeric);
var keyState = (KeyState)random.Next(3);
manager.GenerateNewKey(label, keyState, isInternal, toFile: false);
}
@@ -156,7 +157,7 @@ namespace WalletWasabi.Tests.UnitTests
for (int i = 0; i < 1000; i++)
{
var isInternal = random.Next(2) == 0;
- var label = RandomString.Generate(21);
+ var label = (new WalletWasabi.Crypto.Randomness.UnsecureRandom() as IWasabiRandom).GetString(21, Characters.AlphaNumeric);
var keyState = (KeyState)random.Next(3);
var generatedKey = manager.GenerateNewKey(label, keyState, isInternal);

MODIFY
WalletWasabi.Tests/UnitTests/PasswordTests.cs
WalletWasabi.Tests/UnitTests/PasswordTests.cs
@@ -7,6 +7,7 @@ using WalletWasabi.Helpers;
using Xunit;
using WalletWasabi.Logging;
using WalletWasabi.Blockchain.Keys;
+using WalletWasabi.Crypto.Randomness;
namespace WalletWasabi.Tests.UnitTests
{
@@ -58,13 +59,13 @@ namespace WalletWasabi.Tests.UnitTests
PasswordHelper.GetMasterExtKey(keyManager, original, out _);
// This should not throw format exception but pw is not correct.
- Assert.Throws<SecurityException>(() => PasswordHelper.GetMasterExtKey(keyManager, RandomString.Generate(PasswordHelper.MaxPasswordLength), out _));
+ Assert.Throws<SecurityException>(() => PasswordHelper.GetMasterExtKey(keyManager, (new UnsecureRandom() as IWasabiRandom).GetString(PasswordHelper.MaxPasswordLength, Characters.AlphaNumeric), out _));
// Password should be formatted, before entering here.
- Assert.Throws<FormatException>(() => PasswordHelper.GetMasterExtKey(keyManager, RandomString.Generate(PasswordHelper.MaxPasswordLength + 1), out _));
+ Assert.Throws<FormatException>(() => PasswordHelper.GetMasterExtKey(keyManager, (new UnsecureRandom() as IWasabiRandom).GetString(PasswordHelper.MaxPasswordLength + 1, Characters.AlphaNumeric), out _));
// Too long password with extra spaces.
- var badPassword = $" {RandomString.Generate(PasswordHelper.MaxPasswordLength + 1)} ";
+ var badPassword = $" {(new UnsecureRandom() as IWasabiRandom).GetString(PasswordHelper.MaxPasswordLength + 1, Characters.AlphaNumeric)} ";
// Password should be formatted, before entering here.
Assert.Throws<FormatException>(() => PasswordHelper.GetMasterExtKey(keyManager, badPassword, out _));

MODIFY
WalletWasabi/CoinJoin/Client/Clients/CoinJoinClientBase.cs
WalletWasabi/CoinJoin/Client/Clients/CoinJoinClientBase.cs
@@ -19,6 +19,7 @@ using WalletWasabi.CoinJoin.Client.Rounds;
using WalletWasabi.CoinJoin.Common.Crypto;
using WalletWasabi.CoinJoin.Common.Models;
using WalletWasabi.Crypto;
+using WalletWasabi.Crypto.Randomness;
using WalletWasabi.Helpers;
using WalletWasabi.Logging;
using WalletWasabi.Models;
@@ -967,7 +968,8 @@ namespace WalletWasabi.CoinJoin.Client.Clients
{
ingredients ??= "";
- Salt = TokenGenerator.GetUniqueKey(21);
+ using var rand = new SecureRandom();
+ Salt = (rand as IWasabiRandom).GetString(21, Characters.AlphaNumeric);
Soup = StringCipher.Encrypt(ingredients, Salt);
}
}

ADD
WalletWasabi/Crypto/Randomness/Characters.cs
+using System;
+using System.Collections.Generic;
+using System.Text;
+using WalletWasabi.Helpers;
+
+namespace WalletWasabi.Crypto.Randomness
+{
+ public class Characters
+ {
+ public readonly static Characters AlphaNumeric = new Characters("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
+ public readonly static Characters CapitalAlphaNumeric = new Characters("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
+
+ public Characters(string chars)
+ {
+ Guard.NotNullOrEmpty(nameof(chars), chars);
+ Chars = chars;
+ }
+
+ public string Chars { get; }
+ }
+}

MODIFY
WalletWasabi/Crypto/Randomness/IWasabiRandom.cs
WalletWasabi/Crypto/Randomness/IWasabiRandom.cs
@@ -2,6 +2,7 @@ using NBitcoin;
using NBitcoin.Secp256k1;
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Text;
using WalletWasabi.Helpers;
@@ -17,6 +18,22 @@ namespace WalletWasabi.Crypto.Randomness
return buffer;
}
+ public int GetInt(int fromInclusive, int toExclusive);
+
+ public string GetString(int length, string chars)
+ {
+ Guard.MinimumAndNotNull(nameof(length), length, 1);
+ Guard.NotNullOrEmpty(nameof(chars), chars);
+
+ var random = new string(Enumerable
+ .Repeat(chars, length)
+ .Select(s => s[GetInt(0, s.Length)])
+ .ToArray());
+ return random;
+ }
+
+ public string GetString(int length, Characters chars) => GetString(length, chars.Chars);
+
public Scalar GetScalar()
{
Scalar randomScalar;

MODIFY
WalletWasabi/Crypto/Randomness/MockRandom.cs
WalletWasabi/Crypto/Randomness/MockRandom.cs
@@ -23,5 +23,10 @@ namespace WalletWasabi.Crypto.Randomness
GetBytesResults.RemoveFirst();
first.AsSpan().CopyTo(output);
}
+
+ public int GetInt(int fromInclusive, int toExclusive)
+ {
+ throw new NotImplementedException();
+ }
}
}

MODIFY
WalletWasabi/Crypto/Randomness/SecureRandom.cs
WalletWasabi/Crypto/Randomness/SecureRandom.cs
@@ -20,6 +20,8 @@ namespace WalletWasabi.Crypto.Randomness
public void GetBytes(Span<byte> buffer) => Random.GetBytes(buffer);
+ public int GetInt(int fromInclusive, int toExclusive) => RandomNumberGenerator.GetInt32(fromInclusive, toExclusive);
+
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)

MODIFY
WalletWasabi/Crypto/Randomness/UnsecureRandom.cs
WalletWasabi/Crypto/Randomness/UnsecureRandom.cs
@@ -16,5 +16,7 @@ namespace WalletWasabi.Crypto.Randomness
public void GetBytes(byte[] buffer) => Random.NextBytes(buffer);
public void GetBytes(Span<byte> buffer) => Random.NextBytes(buffer);
+
+ public int GetInt(int fromInclusive, int toExclusive) => Random.Next(fromInclusive, toExclusive);
}
}

DELETE
WalletWasabi/Crypto/TokenGenerator.cs
-using System.Security.Cryptography;
-using System.Text;
-
-namespace WalletWasabi.Crypto
-{
- // https://gist.github.com/diegojancic/9f78750f05550fa6039d2f6092e461e5
- // Based on Eric J's answer here: https://stackoverflow.com/a/1344255/72350
- // - Fixed bias by using 64 characters
- // - Removed unneeded 'new char[62]' and 'new byte[1]'
- // - Using GetBytes instead of GetNonZeroBytes
- public static class TokenGenerator
- {
- public static string GetUniqueKey(int length)
- {
- char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.-".ToCharArray();
- byte[] data = new byte[length];
- using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
- {
- crypto.GetBytes(data);
- }
- StringBuilder result = new StringBuilder(length);
- foreach (byte b in data)
- {
- result.Append(chars[b % (chars.Length)]);
- }
- return result.ToString();
- }
- }
-}

MODIFY
WalletWasabi/Helpers/Constants.cs
WalletWasabi/Helpers/Constants.cs
@@ -47,8 +47,6 @@ namespace WalletWasabi.Helpers
public const int DefaultTestNetBitcoinCoreRpcPort = 18332;
public const int DefaultRegTestBitcoinCoreRpcPort = 18443;
- public const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-
public const double TransactionRBFSignalRate = 0.02; // 2% RBF transactions
public const decimal DefaultDustThreshold = 0.00005m;

DELETE
WalletWasabi/Helpers/RandomString.cs
-using System.Linq;
-using WalletWasabi.Helpers;
-
-namespace System
-{
- public static class RandomString
- {
- private static Random Random { get; } = new Random();
-
- public static string Generate(int length)
- {
- Guard.MinimumAndNotNull(nameof(length), length, 1);
-
- return new string(Enumerable.Repeat(Constants.Chars, length)
- .Select(s => s[Random.Next(s.Length)]).ToArray());
- }
- }
-}

MODIFY
WalletWasabi/TorSocks5/TorSocks5Client.cs
WalletWasabi/TorSocks5/TorSocks5Client.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
+using WalletWasabi.Crypto.Randomness;
using WalletWasabi.Exceptions;
using WalletWasabi.Helpers;
using WalletWasabi.Logging;
@@ -120,7 +121,7 @@ namespace WalletWasabi.TorSocks5
/// </summary>
internal async Task HandshakeAsync(bool isolateStream = true)
{
- await HandshakeAsync(isolateStream ? RandomString.Generate(21) : "").ConfigureAwait(false);
+ await HandshakeAsync(isolateStream ? (new UnsecureRandom() as IWasabiRandom).GetString(21, Characters.CapitalAlphaNumeric) : "").ConfigureAwait(false);
}
/// <summary>

Implement GetInt and GetString for Randomness