Multiple changes to HashHelper and RandomHelper

- Renamed HashHelper to CryptoHelper
- Moved CryptoHelper.GenerateRandomBytes to RandomHelper
- Documented RandomHelper
This commit is contained in:
jvyden 2022-05-01 15:27:35 -04:00
parent 396477c05d
commit f31a73ccaa
No known key found for this signature in database
GPG key ID: 18BCF2BE0262B278
22 changed files with 86 additions and 86 deletions

View file

@ -16,8 +16,8 @@ public class DatabaseTests : LighthouseServerTest
await using Database database = new();
int rand = new Random().Next();
User userA = await database.CreateUser("unitTestUser" + rand, HashHelper.GenerateAuthToken());
User userB = await database.CreateUser("unitTestUser" + rand, HashHelper.GenerateAuthToken());
User userA = await database.CreateUser("unitTestUser" + rand, CryptoHelper.GenerateAuthToken());
User userB = await database.CreateUser("unitTestUser" + rand, CryptoHelper.GenerateAuthToken());
Assert.NotNull(userA);
Assert.NotNull(userB);

View file

@ -20,8 +20,8 @@ public class SlotTests : LighthouseServerTest
Random r = new();
User userA = await database.CreateUser($"unitTestUser{r.Next()}", HashHelper.GenerateAuthToken());
User userB = await database.CreateUser($"unitTestUser{r.Next()}", HashHelper.GenerateAuthToken());
User userA = await database.CreateUser($"unitTestUser{r.Next()}", CryptoHelper.GenerateAuthToken());
User userB = await database.CreateUser($"unitTestUser{r.Next()}", CryptoHelper.GenerateAuthToken());
Location l = new()
{

View file

@ -18,12 +18,12 @@ public class AdminTests : LighthouseWebTest
{
await using Database database = new();
Random random = new();
User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("i'm an engineering failure"));
User user = await database.CreateUser($"unitTestUser{random.Next()}", CryptoHelper.BCryptHash("i'm an engineering failure"));
WebToken webToken = new()
{
UserId = user.UserId,
UserToken = HashHelper.GenerateAuthToken(),
UserToken = CryptoHelper.GenerateAuthToken(),
};
database.WebTokens.Add(webToken);
@ -42,12 +42,12 @@ public class AdminTests : LighthouseWebTest
{
await using Database database = new();
Random random = new();
User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("i'm an engineering failure"));
User user = await database.CreateUser($"unitTestUser{random.Next()}", CryptoHelper.BCryptHash("i'm an engineering failure"));
WebToken webToken = new()
{
UserId = user.UserId,
UserToken = HashHelper.GenerateAuthToken(),
UserToken = CryptoHelper.GenerateAuthToken(),
};
database.WebTokens.Add(webToken);

View file

@ -19,8 +19,8 @@ public class AuthenticationTests : LighthouseWebTest
await using Database database = new();
Random random = new();
string password = HashHelper.Sha256Hash(HashHelper.GenerateRandomBytes(64).ToArray());
User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash(HashHelper.Sha256Hash(password)));
string password = CryptoHelper.Sha256Hash(RandomHelper.GenerateRandomBytes(64).ToArray());
User user = await database.CreateUser($"unitTestUser{random.Next()}", CryptoHelper.BCryptHash(CryptoHelper.Sha256Hash(password)));
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login");
@ -40,7 +40,7 @@ public class AuthenticationTests : LighthouseWebTest
{
await using Database database = new();
Random random = new();
User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("just like the hindenberg,"));
User user = await database.CreateUser($"unitTestUser{random.Next()}", CryptoHelper.BCryptHash("just like the hindenberg,"));
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login");
@ -59,7 +59,7 @@ public class AuthenticationTests : LighthouseWebTest
{
await using Database database = new();
Random random = new();
User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("i'm an engineering failure"));
User user = await database.CreateUser($"unitTestUser{random.Next()}", CryptoHelper.BCryptHash("i'm an engineering failure"));
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login");
@ -81,12 +81,12 @@ public class AuthenticationTests : LighthouseWebTest
await using Database database = new();
Random random = new();
User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("i'm an engineering failure"));
User user = await database.CreateUser($"unitTestUser{random.Next()}", CryptoHelper.BCryptHash("i'm an engineering failure"));
WebToken webToken = new()
{
UserId = user.UserId,
UserToken = HashHelper.GenerateAuthToken(),
UserToken = CryptoHelper.GenerateAuthToken(),
};
database.WebTokens.Add(webToken);

View file

@ -19,7 +19,7 @@ public class RegisterTests : LighthouseWebTest
await using Database database = new();
string username = ("unitTestUser" + new Random().Next()).Substring(0, 16);
string password = HashHelper.Sha256Hash(HashHelper.GenerateRandomBytes(64).ToArray());
string password = CryptoHelper.Sha256Hash(RandomHelper.GenerateRandomBytes(64).ToArray());
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/register");
@ -42,7 +42,7 @@ public class RegisterTests : LighthouseWebTest
await using Database database = new();
string username = ("unitTestUser" + new Random().Next()).Substring(0, 16);
string password = HashHelper.Sha256Hash(HashHelper.GenerateRandomBytes(64).ToArray());
string password = CryptoHelper.Sha256Hash(RandomHelper.GenerateRandomBytes(64).ToArray());
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/register");
@ -63,9 +63,9 @@ public class RegisterTests : LighthouseWebTest
await using Database database = new();
string username = ("unitTestUser" + new Random().Next()).Substring(0, 16);
string password = HashHelper.Sha256Hash(HashHelper.GenerateRandomBytes(64).ToArray());
string password = CryptoHelper.Sha256Hash(RandomHelper.GenerateRandomBytes(64).ToArray());
await database.CreateUser(username, HashHelper.BCryptHash(password));
await database.CreateUser(username, CryptoHelper.BCryptHash(password));
User? user = await database.Users.FirstOrDefaultAsync(u => u.Username == username);
Assert.NotNull(user);

View file

@ -34,7 +34,7 @@ public class LighthouseServerTest
{
await using Database database = new();
if (await database.Users.FirstOrDefaultAsync(u => u.Username == $"{username}{number}") == null)
await database.CreateUser($"{username}{number}", HashHelper.BCryptHash($"unitTestPassword{number}"));
await database.CreateUser($"{username}{number}", CryptoHelper.BCryptHash($"unitTestPassword{number}"));
}
//TODO: generate actual tickets
@ -68,7 +68,7 @@ public class LighthouseServerTest
public async Task<HttpResponseMessage> UploadFileEndpointRequest(string filePath)
{
byte[] bytes = await File.ReadAllBytesAsync(filePath);
string hash = HashHelper.Sha1Hash(bytes).ToLower();
string hash = CryptoHelper.Sha1Hash(bytes).ToLower();
return await this.Client.PostAsync($"/LITTLEBIGPLANETPS3_XML/upload/{hash}", new ByteArrayContent(bytes));
}
@ -76,7 +76,7 @@ public class LighthouseServerTest
public async Task<HttpResponseMessage> AuthenticatedUploadFileEndpointRequest(string filePath, string mmAuth)
{
byte[] bytes = await File.ReadAllBytesAsync(filePath);
string hash = HashHelper.Sha1Hash(bytes).ToLower();
string hash = CryptoHelper.Sha1Hash(bytes).ToLower();
using HttpRequestMessage requestMessage = new(HttpMethod.Post, $"/LITTLEBIGPLANETPS3_XML/upload/{hash}");
requestMessage.Headers.Add("Cookie", mmAuth);
requestMessage.Content = new ByteArrayContent(bytes);

View file

@ -17,6 +17,20 @@ public class MessageController : ControllerBase
{
private readonly Database database;
private const string license = @"
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.";
public MessageController(Database database)
{
this.database = database;
@ -28,7 +42,7 @@ public class MessageController : ControllerBase
User? user = await this.database.UserFromGameRequest(this.Request);
if (user == null) return this.StatusCode(403, "");
return this.Ok($"{EulaHelper.License}\n{ServerSettings.Instance.EulaText}");
return this.Ok($"{license}\n{ServerSettings.Instance.EulaText}");
}
[HttpGet("announce")]

View file

@ -100,7 +100,7 @@ public class Database : DbContext
GameToken gameToken = new()
{
UserToken = HashHelper.GenerateAuthToken(),
UserToken = CryptoHelper.GenerateAuthToken(),
User = user,
UserId = user.UserId,
UserLocation = userLocation,

View file

@ -48,7 +48,7 @@ public static class CensorHelper
{
case FilterMode.Random:
for(int i = 0; i < profanityLength; i++)
lock(RandomHelper.random)
lock(RandomHelper.Random)
{
if (message[i] == ' ')
{
@ -56,8 +56,8 @@ public static class CensorHelper
}
else
{
char randomChar = randomCharacters[RandomHelper.random.Next(0, randomCharacters.Length - 1)];
if (randomChar == prevRandomChar) randomChar = randomCharacters[RandomHelper.random.Next(0, randomCharacters.Length - 1)];
char randomChar = randomCharacters[RandomHelper.Random.Next(0, randomCharacters.Length - 1)];
if (randomChar == prevRandomChar) randomChar = randomCharacters[RandomHelper.Random.Next(0, randomCharacters.Length - 1)];
prevRandomChar = randomChar;
@ -81,9 +81,9 @@ public static class CensorHelper
break;
case FilterMode.Furry:
lock(RandomHelper.random)
lock(RandomHelper.Random)
{
string randomWord = randomFurry[RandomHelper.random.Next(0, randomFurry.Length - 1)];
string randomWord = randomFurry[RandomHelper.Random.Next(0, randomFurry.Length - 1)];
sb.Append(randomWord);
}

View file

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Security.Cryptography;
@ -9,35 +8,18 @@ using System.Threading.Tasks;
namespace LBPUnion.ProjectLighthouse.Helpers;
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public static class HashHelper
public static class CryptoHelper
{
// private static readonly SHA1 sha1 = SHA1.Create();
private static readonly SHA256 sha256 = SHA256.Create();
/// <summary>
/// Generates a specified amount of random bytes in an array.
/// </summary>
/// <param name="count">The amount of bytes to generate.</param>
/// <returns>The bytes generated</returns>
public static IEnumerable<byte> GenerateRandomBytes(int count)
{
byte[] b = new byte[count];
lock(RandomHelper.random)
{
RandomHelper.random.NextBytes(b);
}
return b;
}
/// <summary>
/// Generates a random SHA256 and BCrypted token
/// </summary>
/// <returns>The token as a string.</returns>
public static string GenerateAuthToken()
{
byte[] bytes = (byte[])GenerateRandomBytes(256);
byte[] bytes = (byte[])RandomHelper.GenerateRandomBytes(256);
return BCryptHash(Sha256Hash(bytes));
}

View file

@ -1,18 +0,0 @@
namespace LBPUnion.ProjectLighthouse.Helpers;
public static class EulaHelper
{
public const string License = @"
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.";
}

View file

@ -1,8 +1,29 @@
using System;
using System.Collections.Generic;
namespace LBPUnion.ProjectLighthouse.Helpers;
public static class RandomHelper
{
public static readonly Random random = new();
/// <summary>
/// An instance of Random. Must be locked when in use.
/// </summary>
public static readonly Random Random = new();
/// <summary>
/// Generates a specified amount of random bytes in an array.
/// </summary>
/// <param name="count">The amount of bytes to generate.</param>
/// <returns>The bytes generated</returns>
public static IEnumerable<byte> GenerateRandomBytes(int count)
{
byte[] b = new byte[count];
lock(Random)
{
Random.NextBytes(b);
}
return b;
}
}

View file

@ -19,12 +19,12 @@ public class CreateUserCommand : ICommand
string onlineId = args[0];
string password = args[1];
password = HashHelper.Sha256Hash(password);
password = CryptoHelper.Sha256Hash(password);
User? user = await this._database.Users.FirstOrDefaultAsync(u => u.Username == onlineId);
if (user == null)
{
user = await this._database.CreateUser(onlineId, HashHelper.BCryptHash(password));
user = await this._database.CreateUser(onlineId, CryptoHelper.BCryptHash(password));
Logger.Log($"Created user {user.UserId} with online ID (username) {user.Username} and the specified password.", LoggerLevelLogin.Instance);
user.PasswordResetRequired = true;

View file

@ -36,9 +36,9 @@ public class ResetPasswordCommand : ICommand
return;
}
string password = args[1];
if (password.Length != 64) password = HashHelper.Sha256Hash(password);
if (password.Length != 64) password = CryptoHelper.Sha256Hash(password);
user.Password = HashHelper.BCryptHash(password);
user.Password = CryptoHelper.BCryptHash(password);
user.PasswordResetRequired = true;
await this.database.SaveChangesAsync();

View file

@ -74,7 +74,7 @@ public class LoginForm : BaseLayout
{
UserId = user.UserId,
User = user,
EmailToken = HashHelper.GenerateAuthToken(),
EmailToken = CryptoHelper.GenerateAuthToken(),
};
this.Database.EmailSetTokens.Add(emailSetToken);
@ -86,7 +86,7 @@ public class LoginForm : BaseLayout
WebToken webToken = new()
{
UserId = user.UserId,
UserToken = HashHelper.GenerateAuthToken(),
UserToken = CryptoHelper.GenerateAuthToken(),
};
this.Database.WebTokens.Add(webToken);

View file

@ -33,7 +33,7 @@ public class PasswordResetPage : BaseLayout
return this.Page();
}
user.Password = HashHelper.BCryptHash(password);
user.Password = CryptoHelper.BCryptHash(password);
user.PasswordResetRequired = false;
await this.Database.SaveChangesAsync();

View file

@ -67,12 +67,12 @@ public class RegisterForm : BaseLayout
return this.Page();
}
User user = await this.Database.CreateUser(username, HashHelper.BCryptHash(password), emailAddress);
User user = await this.Database.CreateUser(username, CryptoHelper.BCryptHash(password), emailAddress);
WebToken webToken = new()
{
UserId = user.UserId,
UserToken = HashHelper.GenerateAuthToken(),
UserToken = CryptoHelper.GenerateAuthToken(),
};
this.Database.WebTokens.Add(webToken);

View file

@ -38,7 +38,7 @@ public class SendVerificationEmailPage : BaseLayout
{
UserId = user.UserId,
User = user,
EmailToken = HashHelper.GenerateAuthToken(),
EmailToken = CryptoHelper.GenerateAuthToken(),
};
this.Database.EmailVerificationTokens.Add(verifyToken);

View file

@ -50,7 +50,7 @@ public class SetEmailForm : BaseLayout
{
UserId = user.UserId,
User = user,
EmailToken = HashHelper.GenerateAuthToken(),
EmailToken = CryptoHelper.GenerateAuthToken(),
};
this.Database.EmailVerificationTokens.Add(emailVerifyToken);
@ -59,7 +59,7 @@ public class SetEmailForm : BaseLayout
WebToken webToken = new()
{
UserId = user.UserId,
UserToken = HashHelper.GenerateAuthToken(),
UserToken = CryptoHelper.GenerateAuthToken(),
};
this.Response.Cookies.Append

View file

@ -57,6 +57,7 @@
<ItemGroup>
<Compile Remove="Migrations\20220301204930_AddEmailVerificationTokens.Designer.cs" />
<Compile Remove="Helpers\EulaHelper.cs"/>
</ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">

View file

@ -173,7 +173,7 @@ public class Startup
if (computeDigests && digestPath.StartsWith("/LITTLEBIGPLANETPS3_XML"))
{
string clientRequestDigest = await HashHelper.ComputeDigest(digestPath, authCookie, body, ServerSettings.Instance.ServerDigestKey);
string clientRequestDigest = await CryptoHelper.ComputeDigest(digestPath, authCookie, body, ServerSettings.Instance.ServerDigestKey);
// Check the digest we've just calculated against the X-Digest-A header if the game set the header. They should match.
if (context.Request.Headers.TryGetValue("X-Digest-A", out StringValues sentDigest))
@ -186,7 +186,7 @@ public class Startup
// Reset the body stream
body.Position = 0;
clientRequestDigest = await HashHelper.ComputeDigest(digestPath, authCookie, body, ServerSettings.Instance.AlternateDigestKey);
clientRequestDigest = await CryptoHelper.ComputeDigest(digestPath, authCookie, body, ServerSettings.Instance.AlternateDigestKey);
if (clientRequestDigest != sentDigest)
{
#if DEBUG
@ -222,7 +222,7 @@ public class Startup
string digestKey = usedAlternateDigestKey ? ServerSettings.Instance.AlternateDigestKey : ServerSettings.Instance.ServerDigestKey;
// Compute the digest for the response.
string serverDigest = await HashHelper.ComputeDigest(context.Request.Path, authCookie, responseBuffer, digestKey);
string serverDigest = await CryptoHelper.ComputeDigest(context.Request.Path, authCookie, responseBuffer, digestKey);
context.Response.Headers.Add("X-Digest-A", serverDigest);
}

View file

@ -24,7 +24,7 @@ public class LbpFile
this.Data = data;
this.FileType = FileHelper.DetermineFileType(this.Data);
this.Hash = HashHelper.Sha1Hash(this.Data).ToLower();
this.Hash = CryptoHelper.Sha1Hash(this.Data).ToLower();
}
public static LbpFile? FromHash(string hash)