From d4ef0dc34e0613db9c4a333ea73f792b2dd70fae Mon Sep 17 00:00:00 2001 From: Alex Macocian Date: Sun, 8 Sep 2024 18:37:38 +0200 Subject: [PATCH] Base32 conversions --- .../SystemExtensions.NetCore.csproj | 2 +- .../Encoding/Base32.cs | 128 ++++++++++++++++++ .../SystemExtensions.NetStandard.csproj | 2 +- 3 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 SystemExtensions.NetStandard/Encoding/Base32.cs diff --git a/SystemExtensions.NetCore/SystemExtensions.NetCore.csproj b/SystemExtensions.NetCore/SystemExtensions.NetCore.csproj index ebc91b2..cd68814 100644 --- a/SystemExtensions.NetCore/SystemExtensions.NetCore.csproj +++ b/SystemExtensions.NetCore/SystemExtensions.NetCore.csproj @@ -8,7 +8,7 @@ System LICENSE true - 1.6.7 + 1.6.8 Alexandru Macocian https://github.com/AlexMacocian/SystemExtensions Extensions for the System namespace diff --git a/SystemExtensions.NetStandard/Encoding/Base32.cs b/SystemExtensions.NetStandard/Encoding/Base32.cs new file mode 100644 index 0000000..f6779f6 --- /dev/null +++ b/SystemExtensions.NetStandard/Encoding/Base32.cs @@ -0,0 +1,128 @@ +namespace System.Extensions; + +/// +/// https://stackoverflow.com/questions/641361/base32-decoding +/// +public static partial class Convert +{ + public static byte[] FromBase32String(string input) + { + if (string.IsNullOrEmpty(input)) + { + throw new ArgumentNullException("input"); + } + + input = input.TrimEnd('='); //remove padding characters + var byteCount = input.Length * 5 / 8; //this must be TRUNCATED + var returnArray = new byte[byteCount]; + + byte curByte = 0, bitsRemaining = 8; + int arrayIndex = 0; + + foreach (var c in input) + { + var cValue = CharToValue(c); + int mask; + if (bitsRemaining > 5) + { + mask = cValue << (bitsRemaining - 5); + curByte = (byte)(curByte | mask); + bitsRemaining -= 5; + } + else + { + mask = cValue >> (5 - bitsRemaining); + curByte = (byte)(curByte | mask); + returnArray[arrayIndex++] = curByte; + curByte = (byte)(cValue << (3 + bitsRemaining)); + bitsRemaining += 3; + } + } + + //if we didn't end with a full byte + if (arrayIndex != byteCount) + { + returnArray[arrayIndex] = curByte; + } + + return returnArray; + } + + public static string ToBase32String(byte[] input) + { + if (input == null || input.Length == 0) + { + throw new ArgumentNullException("input"); + } + + var charCount = (int)Math.Ceiling(input.Length / 5d) * 8; + var returnArray = new char[charCount]; + + byte nextChar = 0, bitsRemaining = 5; + var arrayIndex = 0; + + foreach (var b in input) + { + nextChar = (byte)(nextChar | (b >> (8 - bitsRemaining))); + returnArray[arrayIndex++] = ValueToChar(nextChar); + + if (bitsRemaining < 4) + { + nextChar = (byte)((b >> (3 - bitsRemaining)) & 31); + returnArray[arrayIndex++] = ValueToChar(nextChar); + bitsRemaining += 5; + } + + bitsRemaining -= 3; + nextChar = (byte)((b << bitsRemaining) & 31); + } + + //if we didn't end with a full char + if (arrayIndex != charCount) + { + returnArray[arrayIndex++] = ValueToChar(nextChar); + while (arrayIndex != charCount) returnArray[arrayIndex++] = '='; //padding + } + + return new string(returnArray); + } + + private static int CharToValue(char c) + { + var value = (int)c; + + //65-90 == uppercase letters + if (value < 91 && value > 64) + { + return value - 65; + } + //50-55 == numbers 2-7 + if (value < 56 && value > 49) + { + return value - 24; + } + //97-122 == lowercase letters + if (value < 123 && value > 96) + { + return value - 97; + } + + throw new ArgumentException($"Character {c} is not a Base32 character."); + } + + private static char ValueToChar(byte b) + { + if (b < 26) + { + return (char)(b + 65); + } + + if (b < 32) + { + return (char)(b + 24); + } + + throw new ArgumentException($"Byte {b} is not a value Base32 value."); + } + +} diff --git a/SystemExtensions.NetStandard/SystemExtensions.NetStandard.csproj b/SystemExtensions.NetStandard/SystemExtensions.NetStandard.csproj index 0347364..6e1456a 100644 --- a/SystemExtensions.NetStandard/SystemExtensions.NetStandard.csproj +++ b/SystemExtensions.NetStandard/SystemExtensions.NetStandard.csproj @@ -7,7 +7,7 @@ LICENSE true System - 1.6.7 + 1.6.8 Alexandru Macocian https://github.com/AlexMacocian/SystemExtensions Extensions for the System namespace