From d3aed20843245c0183c7e6ac87f99a85092bea3d Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Mon, 27 May 2024 13:27:49 +0200 Subject: [PATCH] [backend] Replace cuid2 with System.Cryptography-based CSPRNG This allows us to drop the cuid.net dependency and is ~6x faster while improving security (cuid2 is dubious at best in this regard). We may switch to ULID or UUIDv7 in the future for even higher performance, but this change allows for improving performance and security without any side effects. --- .../Core/Helpers/CryptographyHelpers.cs | 30 +++++++++++++++++-- Iceshrimp.Backend/Core/Helpers/IdHelpers.cs | 6 ++-- Iceshrimp.Backend/Iceshrimp.Backend.csproj | 1 - 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/Iceshrimp.Backend/Core/Helpers/CryptographyHelpers.cs b/Iceshrimp.Backend/Core/Helpers/CryptographyHelpers.cs index 79538a0d..4a5ec90e 100644 --- a/Iceshrimp.Backend/Core/Helpers/CryptographyHelpers.cs +++ b/Iceshrimp.Backend/Core/Helpers/CryptographyHelpers.cs @@ -4,7 +4,31 @@ namespace Iceshrimp.Backend.Core.Helpers; public static class CryptographyHelpers { - private const string AlphaNumCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - public static string GenerateRandomString(int length) => RandomNumberGenerator.GetString(AlphaNumCharset, length); - public static string GenerateRandomHexString(int length) => RandomNumberGenerator.GetHexString(length, true); + public static string GenerateRandomHexString(int length) + => RandomNumberGenerator.GetHexString(length, true); + + public static string GenerateRandomString(int length, Charset charset = Charset.AlphaNum) + => RandomNumberGenerator.GetString(GetCharset(charset), length); + + public enum Charset + { + AlphaNum, + AlphaNumLower, + CrockfordBase32, + CrockfordBase32Lower + } + + private static string GetCharset(Charset charset) => charset switch + { + Charset.AlphaNum => AlphaNumCharset, + Charset.AlphaNumLower => AlphaNumLowerCharset, + Charset.CrockfordBase32 => CrockfordBase32Charset, + Charset.CrockfordBase32Lower => CrockfordBase32LowerCharset, + _ => throw new ArgumentOutOfRangeException(nameof(charset), charset, null) + }; + + private const string AlphaNumCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private const string AlphaNumLowerCharset = "abcdefghijklmnopqrstuvwxyz0123456789"; + private const string CrockfordBase32Charset = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"; + private const string CrockfordBase32LowerCharset = "0123456789abcdefghjkmnpqrstvwxyz"; } \ No newline at end of file diff --git a/Iceshrimp.Backend/Core/Helpers/IdHelpers.cs b/Iceshrimp.Backend/Core/Helpers/IdHelpers.cs index cecd0493..7e41132c 100644 --- a/Iceshrimp.Backend/Core/Helpers/IdHelpers.cs +++ b/Iceshrimp.Backend/Core/Helpers/IdHelpers.cs @@ -1,5 +1,4 @@ using Iceshrimp.Backend.Core.Extensions; -using Visus.Cuid; namespace Iceshrimp.Backend.Core.Helpers; @@ -14,10 +13,11 @@ public static class IdHelpers createdAt ??= DateTime.UtcNow; - var cuid = new Cuid2(8); + // We want to use a charset with a power-of-two amount of possible characters for optimal CSPRNG performance. + var random = CryptographyHelpers.GenerateRandomString(8, CryptographyHelpers.Charset.CrockfordBase32Lower); var now = (long)createdAt.Value.Subtract(DateTime.UnixEpoch).TotalMilliseconds; var time = Math.Max(now - Time2000, 0); var timestamp = time.ToBase36().PadLeft(8, '0'); - return timestamp + cuid; + return timestamp + random; } } \ No newline at end of file diff --git a/Iceshrimp.Backend/Iceshrimp.Backend.csproj b/Iceshrimp.Backend/Iceshrimp.Backend.csproj index 0a371c93..d537ccb6 100644 --- a/Iceshrimp.Backend/Iceshrimp.Backend.csproj +++ b/Iceshrimp.Backend/Iceshrimp.Backend.csproj @@ -33,7 +33,6 @@ -