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(); await using Database database = new();
int rand = new Random().Next(); int rand = new Random().Next();
User userA = await database.CreateUser("unitTestUser" + rand, HashHelper.GenerateAuthToken()); User userA = await database.CreateUser("unitTestUser" + rand, CryptoHelper.GenerateAuthToken());
User userB = await database.CreateUser("unitTestUser" + rand, HashHelper.GenerateAuthToken()); User userB = await database.CreateUser("unitTestUser" + rand, CryptoHelper.GenerateAuthToken());
Assert.NotNull(userA); Assert.NotNull(userA);
Assert.NotNull(userB); Assert.NotNull(userB);

View file

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

View file

@ -18,12 +18,12 @@ public class AdminTests : LighthouseWebTest
{ {
await using Database database = new(); await using Database database = new();
Random random = 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() WebToken webToken = new()
{ {
UserId = user.UserId, UserId = user.UserId,
UserToken = HashHelper.GenerateAuthToken(), UserToken = CryptoHelper.GenerateAuthToken(),
}; };
database.WebTokens.Add(webToken); database.WebTokens.Add(webToken);
@ -42,12 +42,12 @@ public class AdminTests : LighthouseWebTest
{ {
await using Database database = new(); await using Database database = new();
Random random = 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() WebToken webToken = new()
{ {
UserId = user.UserId, UserId = user.UserId,
UserToken = HashHelper.GenerateAuthToken(), UserToken = CryptoHelper.GenerateAuthToken(),
}; };
database.WebTokens.Add(webToken); database.WebTokens.Add(webToken);

View file

@ -19,8 +19,8 @@ public class AuthenticationTests : LighthouseWebTest
await using Database database = new(); await using Database database = new();
Random random = new(); Random random = new();
string password = HashHelper.Sha256Hash(HashHelper.GenerateRandomBytes(64).ToArray()); string password = CryptoHelper.Sha256Hash(RandomHelper.GenerateRandomBytes(64).ToArray());
User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash(HashHelper.Sha256Hash(password))); User user = await database.CreateUser($"unitTestUser{random.Next()}", CryptoHelper.BCryptHash(CryptoHelper.Sha256Hash(password)));
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login"); this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login");
@ -40,7 +40,7 @@ public class AuthenticationTests : LighthouseWebTest
{ {
await using Database database = new(); await using Database database = new();
Random random = 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"); this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login");
@ -59,7 +59,7 @@ public class AuthenticationTests : LighthouseWebTest
{ {
await using Database database = new(); await using Database database = new();
Random random = 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"); this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login");
@ -81,12 +81,12 @@ public class AuthenticationTests : LighthouseWebTest
await using Database database = new(); await using Database database = new();
Random random = 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() WebToken webToken = new()
{ {
UserId = user.UserId, UserId = user.UserId,
UserToken = HashHelper.GenerateAuthToken(), UserToken = CryptoHelper.GenerateAuthToken(),
}; };
database.WebTokens.Add(webToken); database.WebTokens.Add(webToken);

View file

@ -19,7 +19,7 @@ public class RegisterTests : LighthouseWebTest
await using Database database = new(); await using Database database = new();
string username = ("unitTestUser" + new Random().Next()).Substring(0, 16); 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"); this.Driver.Navigate().GoToUrl(this.BaseAddress + "/register");
@ -42,7 +42,7 @@ public class RegisterTests : LighthouseWebTest
await using Database database = new(); await using Database database = new();
string username = ("unitTestUser" + new Random().Next()).Substring(0, 16); 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"); this.Driver.Navigate().GoToUrl(this.BaseAddress + "/register");
@ -63,9 +63,9 @@ public class RegisterTests : LighthouseWebTest
await using Database database = new(); await using Database database = new();
string username = ("unitTestUser" + new Random().Next()).Substring(0, 16); 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); User? user = await database.Users.FirstOrDefaultAsync(u => u.Username == username);
Assert.NotNull(user); Assert.NotNull(user);

View file

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

View file

@ -17,6 +17,20 @@ public class MessageController : ControllerBase
{ {
private readonly Database database; 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) public MessageController(Database database)
{ {
this.database = database; this.database = database;
@ -28,7 +42,7 @@ public class MessageController : ControllerBase
User? user = await this.database.UserFromGameRequest(this.Request); User? user = await this.database.UserFromGameRequest(this.Request);
if (user == null) return this.StatusCode(403, ""); 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")] [HttpGet("announce")]

View file

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

View file

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

View file

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Security.Cryptography; using System.Security.Cryptography;
@ -9,35 +8,18 @@ using System.Threading.Tasks;
namespace LBPUnion.ProjectLighthouse.Helpers; namespace LBPUnion.ProjectLighthouse.Helpers;
[SuppressMessage("ReSharper", "UnusedMember.Global")] [SuppressMessage("ReSharper", "UnusedMember.Global")]
public static class HashHelper public static class CryptoHelper
{ {
// private static readonly SHA1 sha1 = SHA1.Create(); // private static readonly SHA1 sha1 = SHA1.Create();
private static readonly SHA256 sha256 = SHA256.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> /// <summary>
/// Generates a random SHA256 and BCrypted token /// Generates a random SHA256 and BCrypted token
/// </summary> /// </summary>
/// <returns>The token as a string.</returns> /// <returns>The token as a string.</returns>
public static string GenerateAuthToken() public static string GenerateAuthToken()
{ {
byte[] bytes = (byte[])GenerateRandomBytes(256); byte[] bytes = (byte[])RandomHelper.GenerateRandomBytes(256);
return BCryptHash(Sha256Hash(bytes)); 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;
using System.Collections.Generic;
namespace LBPUnion.ProjectLighthouse.Helpers; namespace LBPUnion.ProjectLighthouse.Helpers;
public static class RandomHelper 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 onlineId = args[0];
string password = args[1]; string password = args[1];
password = HashHelper.Sha256Hash(password); password = CryptoHelper.Sha256Hash(password);
User? user = await this._database.Users.FirstOrDefaultAsync(u => u.Username == onlineId); User? user = await this._database.Users.FirstOrDefaultAsync(u => u.Username == onlineId);
if (user == null) 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); Logger.Log($"Created user {user.UserId} with online ID (username) {user.Username} and the specified password.", LoggerLevelLogin.Instance);
user.PasswordResetRequired = true; user.PasswordResetRequired = true;

View file

@ -36,9 +36,9 @@ public class ResetPasswordCommand : ICommand
return; return;
} }
string password = args[1]; 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; user.PasswordResetRequired = true;
await this.database.SaveChangesAsync(); await this.database.SaveChangesAsync();

View file

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

View file

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

View file

@ -67,12 +67,12 @@ public class RegisterForm : BaseLayout
return this.Page(); 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() WebToken webToken = new()
{ {
UserId = user.UserId, UserId = user.UserId,
UserToken = HashHelper.GenerateAuthToken(), UserToken = CryptoHelper.GenerateAuthToken(),
}; };
this.Database.WebTokens.Add(webToken); this.Database.WebTokens.Add(webToken);

View file

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

View file

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

View file

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

View file

@ -173,7 +173,7 @@ public class Startup
if (computeDigests && digestPath.StartsWith("/LITTLEBIGPLANETPS3_XML")) 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. // 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)) if (context.Request.Headers.TryGetValue("X-Digest-A", out StringValues sentDigest))
@ -186,7 +186,7 @@ public class Startup
// Reset the body stream // Reset the body stream
body.Position = 0; 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 (clientRequestDigest != sentDigest)
{ {
#if DEBUG #if DEBUG
@ -222,7 +222,7 @@ public class Startup
string digestKey = usedAlternateDigestKey ? ServerSettings.Instance.AlternateDigestKey : ServerSettings.Instance.ServerDigestKey; string digestKey = usedAlternateDigestKey ? ServerSettings.Instance.AlternateDigestKey : ServerSettings.Instance.ServerDigestKey;
// Compute the digest for the response. // 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); context.Response.Headers.Add("X-Digest-A", serverDigest);
} }

View file

@ -24,7 +24,7 @@ public class LbpFile
this.Data = data; this.Data = data;
this.FileType = FileHelper.DetermineFileType(this.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) public static LbpFile? FromHash(string hash)