Created
January 4, 2019 20:33
-
-
Save alexsandro-xpt/153de71c3602832e8c70eaecd3419742 to your computer and use it in GitHub Desktop.
ToBase32 http://seehashrun.blogspot.com/2016/09/base32-encoding-and-decoding-in-c.html Demo at https://dotnetfiddle.net/WsKkJG
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public sealed class Base32 { | |
| // the valid chars for the encoding | |
| private static string ValidChars = "QAZ2WSX3" + "EDC4RFV5" + "TGB6YHN7" + "UJM8K9LP"; | |
| /// <summary> | |
| /// Converts an array of bytes to a Base32-k string. | |
| /// </summary> | |
| public static string ToBase32String(byte[] bytes) { | |
| StringBuilder sb = new StringBuilder(); // holds the base32 chars | |
| byte index; | |
| int hi = 5; | |
| int currentByte = 0; | |
| while (currentByte < bytes.Length) { | |
| // do we need to use the next byte? | |
| if (hi > 8) { | |
| // get the last piece from the current byte, shift it to the right | |
| // and increment the byte counter | |
| index = (byte)(bytes[currentByte++] >> (hi - 5)); | |
| if (currentByte != bytes.Length) { | |
| // if we are not at the end, get the first piece from | |
| // the next byte, clear it and shift it to the left | |
| index = (byte)(((byte)(bytes[currentByte] << (16 - hi)) >> 3) | index); | |
| } | |
| hi -= 3; | |
| } else if(hi == 8) { | |
| index = (byte)(bytes[currentByte++] >> 3); | |
| hi -= 3; | |
| } else { | |
| // simply get the stuff from the current byte | |
| index = (byte)((byte)(bytes[currentByte] << (8 - hi)) >> 3); | |
| hi += 5; | |
| } | |
| sb.Append(ValidChars[index]); | |
| } | |
| return sb.ToString(); | |
| } | |
| /// <summary> | |
| /// Converts a Base32-k string into an array of bytes. | |
| /// </summary> | |
| /// <exception cref="System.ArgumentException"> | |
| /// Input string <paramref name="s">s</paramref> contains invalid Base32-k characters. | |
| /// </exception> | |
| public static byte[] FromBase32String(string str) { | |
| int numBytes = str.Length * 5 / 8; | |
| byte[] bytes = new Byte[numBytes]; | |
| // all UPPERCASE chars | |
| str = str.ToUpper(); | |
| int bit_buffer; | |
| int currentCharIndex; | |
| int bits_in_buffer; | |
| if (str.Length < 3) { | |
| bytes[0] = (byte)(ValidChars.IndexOf(str[0]) | ValidChars.IndexOf(str[1]) << 5); | |
| return bytes; | |
| } | |
| bit_buffer = (ValidChars.IndexOf(str[0]) | ValidChars.IndexOf(str[1]) << 5); | |
| bits_in_buffer = 10; | |
| currentCharIndex = 2; | |
| for (int i = 0; i < bytes.Length; i++) { | |
| bytes[i] = (byte)bit_buffer; | |
| bit_buffer >>= 8; | |
| bits_in_buffer -= 8; | |
| while (bits_in_buffer < 8 && currentCharIndex < str.Length) { | |
| bit_buffer |= ValidChars.IndexOf(str[currentCharIndex++]) << bits_in_buffer; | |
| bits_in_buffer += 5; | |
| } | |
| } | |
| return bytes; | |
| } | |
| } | |
| public static class Base322 { | |
| private static readonly char[] DIGITS; | |
| private static readonly int MASK; | |
| private static readonly int SHIFT; | |
| private static Dictionary<char, int> CHAR_MAP = new Dictionary<char, int>(); | |
| private const string SEPARATOR = "-"; | |
| static Base322() { | |
| DIGITS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".ToCharArray(); | |
| MASK = DIGITS.Length - 1; | |
| SHIFT = numberOfTrailingZeros(DIGITS.Length); | |
| for (int i = 0; i < DIGITS.Length; i++) CHAR_MAP[DIGITS[i]] = i; | |
| } | |
| private static int numberOfTrailingZeros(int i) { | |
| // HD, Figure 5-14 | |
| int y; | |
| if (i == 0) return 32; | |
| int n = 31; | |
| y = i << 16; if (y != 0) { n = n - 16; i = y; } | |
| y = i << 8; if (y != 0) { n = n - 8; i = y; } | |
| y = i << 4; if (y != 0) { n = n - 4; i = y; } | |
| y = i << 2; if (y != 0) { n = n - 2; i = y; } | |
| return n - (int)((uint)(i << 1) >> 31); | |
| } | |
| public static byte[] Decode(string encoded) { | |
| // Remove whitespace and separators | |
| encoded = encoded.Trim().Replace(SEPARATOR, ""); | |
| // Remove padding. Note: the padding is used as hint to determine how many | |
| // bits to decode from the last incomplete chunk (which is commented out | |
| // below, so this may have been wrong to start with). | |
| encoded = Regex.Replace(encoded, "[=]*$", ""); | |
| // Canonicalize to all upper case | |
| encoded = encoded.ToUpper(); | |
| if (encoded.Length == 0) { | |
| return new byte[0]; | |
| } | |
| int encodedLength = encoded.Length; | |
| int outLength = encodedLength * SHIFT / 8; | |
| byte[] result = new byte[outLength]; | |
| int buffer = 0; | |
| int next = 0; | |
| int bitsLeft = 0; | |
| foreach (char c in encoded.ToCharArray()) { | |
| if (!CHAR_MAP.ContainsKey(c)) { | |
| throw new DecodingException("Illegal character: " + c); | |
| } | |
| buffer <<= SHIFT; | |
| buffer |= CHAR_MAP[c] & MASK; | |
| bitsLeft += SHIFT; | |
| if (bitsLeft >= 8) { | |
| result[next++] = (byte)(buffer >> (bitsLeft - 8)); | |
| bitsLeft -= 8; | |
| } | |
| } | |
| // We'll ignore leftover bits for now. | |
| // | |
| // if (next != outLength || bitsLeft >= SHIFT) { | |
| // throw new DecodingException("Bits left: " + bitsLeft); | |
| // } | |
| return result; | |
| } | |
| public static string Encode(byte[] data, bool padOutput = false) { | |
| if (data.Length == 0) { | |
| return ""; | |
| } | |
| // SHIFT is the number of bits per output character, so the length of the | |
| // output is the length of the input multiplied by 8/SHIFT, rounded up. | |
| if (data.Length >= (1 << 28)) { | |
| // The computation below will fail, so don't do it. | |
| throw new ArgumentOutOfRangeException("data"); | |
| } | |
| int outputLength = (data.Length * 8 + SHIFT - 1) / SHIFT; | |
| StringBuilder result = new StringBuilder(outputLength); | |
| int buffer = data[0]; | |
| int next = 1; | |
| int bitsLeft = 8; | |
| while (bitsLeft > 0 || next < data.Length) { | |
| if (bitsLeft < SHIFT) { | |
| if (next < data.Length) { | |
| buffer <<= 8; | |
| buffer |= (data[next++] & 0xff); | |
| bitsLeft += 8; | |
| } else { | |
| int pad = SHIFT - bitsLeft; | |
| buffer <<= pad; | |
| bitsLeft += pad; | |
| } | |
| } | |
| int index = MASK & (buffer >> (bitsLeft - SHIFT)); | |
| bitsLeft -= SHIFT; | |
| result.Append(DIGITS[index]); | |
| } | |
| if (padOutput) { | |
| int padding = 8 - (result.Length % 8); | |
| if (padding > 0) result.Append(new string('=', padding == 8 ? 0 : padding)); | |
| } | |
| return result.ToString(); | |
| } | |
| private class DecodingException : Exception { | |
| public DecodingException(string message) : base(message) { | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Text; | |
| using System.Text.RegularExpressions; | |
| using System.Linq; | |
| public static class Base32 | |
| { | |
| private static readonly char[] DIGITS; | |
| private static readonly int MASK; | |
| private static readonly int SHIFT; | |
| private static Dictionary<char, int> CHAR_MAP = new Dictionary<char, int>(); | |
| private const string SEPARATOR = "-"; | |
| static Base32() { | |
| DIGITS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".ToCharArray(); | |
| MASK = DIGITS.Length - 1; | |
| SHIFT = numberOfTrailingZeros(DIGITS.Length); | |
| for (int i = 0; i < DIGITS.Length; i++) CHAR_MAP[DIGITS[i]] = i; | |
| } | |
| private static int numberOfTrailingZeros(int i) { | |
| // HD, Figure 5-14 | |
| int y; | |
| if (i == 0) return 32; | |
| int n = 31; | |
| y = i << 16; if (y != 0) { n = n - 16; i = y; } | |
| y = i << 8; if (y != 0) { n = n - 8; i = y; } | |
| y = i << 4; if (y != 0) { n = n - 4; i = y; } | |
| y = i << 2; if (y != 0) { n = n - 2; i = y; } | |
| return n - (int)((uint)(i << 1) >> 31); | |
| } | |
| public static byte[] Decode(string encoded) { | |
| // Remove whitespace and separators | |
| encoded = encoded.Trim().Replace(SEPARATOR, ""); | |
| // Remove padding. Note: the padding is used as hint to determine how many | |
| // bits to decode from the last incomplete chunk (which is commented out | |
| // below, so this may have been wrong to start with). | |
| encoded = Regex.Replace(encoded, "[=]*$", ""); | |
| // Canonicalize to all upper case | |
| encoded = encoded.ToUpper(); | |
| if (encoded.Length == 0) { | |
| return new byte[0]; | |
| } | |
| int encodedLength = encoded.Length; | |
| int outLength = encodedLength * SHIFT / 8; | |
| byte[] result = new byte[outLength]; | |
| int buffer = 0; | |
| int next = 0; | |
| int bitsLeft = 0; | |
| foreach (char c in encoded.ToCharArray()) { | |
| if (!CHAR_MAP.ContainsKey(c)) { | |
| throw new DecodingException("Illegal character: " + c); | |
| } | |
| buffer <<= SHIFT; | |
| buffer |= CHAR_MAP[c] & MASK; | |
| bitsLeft += SHIFT; | |
| if (bitsLeft >= 8) { | |
| result[next++] = (byte)(buffer >> (bitsLeft - 8)); | |
| bitsLeft -= 8; | |
| } | |
| } | |
| // We'll ignore leftover bits for now. | |
| // | |
| // if (next != outLength || bitsLeft >= SHIFT) { | |
| // throw new DecodingException("Bits left: " + bitsLeft); | |
| // } | |
| return result; | |
| } | |
| public static string Encode(byte[] data, bool padOutput = false) { | |
| if (data.Length == 0) { | |
| return ""; | |
| } | |
| // SHIFT is the number of bits per output character, so the length of the | |
| // output is the length of the input multiplied by 8/SHIFT, rounded up. | |
| if (data.Length >= (1 << 28)) { | |
| // The computation below will fail, so don't do it. | |
| throw new ArgumentOutOfRangeException("data"); | |
| } | |
| int outputLength = (data.Length * 8 + SHIFT - 1) / SHIFT; | |
| StringBuilder result = new StringBuilder(outputLength); | |
| int buffer = data[0]; | |
| int next = 1; | |
| int bitsLeft = 8; | |
| while (bitsLeft > 0 || next < data.Length) { | |
| if (bitsLeft < SHIFT) { | |
| if (next < data.Length) { | |
| buffer <<= 8; | |
| buffer |= (data[next++] & 0xff); | |
| bitsLeft += 8; | |
| } else { | |
| int pad = SHIFT - bitsLeft; | |
| buffer <<= pad; | |
| bitsLeft += pad; | |
| } | |
| } | |
| int index = MASK & (buffer >> (bitsLeft - SHIFT)); | |
| bitsLeft -= SHIFT; | |
| result.Append(DIGITS[index]); | |
| } | |
| if (padOutput) { | |
| int padding = 8 - (result.Length % 8); | |
| if (padding > 0) result.Append(new string('=', padding == 8 ? 0 : padding)); | |
| } | |
| return result.ToString(); | |
| } | |
| private class DecodingException : Exception { | |
| public DecodingException(string message) : base(message) { | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public static class PasswordGeneratorService | |
| { | |
| /// <summary> | |
| /// Generates a random password based on the rules passed in the parameters | |
| /// </summary> | |
| /// <param name="includeLowercase">Bool to say if lowercase are required</param> | |
| /// <param name="includeUppercase">Bool to say if uppercase are required</param> | |
| /// <param name="includeNumeric">Bool to say if numerics are required</param> | |
| /// <param name="includeSpecial">Bool to say if special characters are required</param> | |
| /// <param name="includeSpaces">Bool to say if spaces are required</param> | |
| /// <param name="lengthOfPassword">Length of password required. Should be between 8 and 128</param> | |
| /// <returns></returns> | |
| public static string GeneratePassword(bool includeLowercase, bool includeUppercase, bool includeNumeric, bool includeSpecial, bool includeSpaces, int lengthOfPassword) | |
| { | |
| const int MAXIMUM_IDENTICAL_CONSECUTIVE_CHARS = 2; | |
| const string LOWERCASE_CHARACTERS = "abcdefghijklmnopqrstuvwxyz"; | |
| const string UPPERCASE_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |
| const string NUMERIC_CHARACTERS = "0123456789"; | |
| const string SPECIAL_CHARACTERS = @"!#$%&*@\"; | |
| const string SPACE_CHARACTER = " "; | |
| const int PASSWORD_LENGTH_MIN = 8; | |
| const int PASSWORD_LENGTH_MAX = 128; | |
| if (lengthOfPassword < PASSWORD_LENGTH_MIN || lengthOfPassword > PASSWORD_LENGTH_MAX) | |
| { | |
| return "Password length must be between 8 and 128."; | |
| } | |
| string characterSet = ""; | |
| if (includeLowercase) | |
| { | |
| characterSet += LOWERCASE_CHARACTERS; | |
| } | |
| if (includeUppercase) | |
| { | |
| characterSet += UPPERCASE_CHARACTERS; | |
| } | |
| if (includeNumeric) | |
| { | |
| characterSet += NUMERIC_CHARACTERS; | |
| } | |
| if (includeSpecial) | |
| { | |
| characterSet += SPECIAL_CHARACTERS; | |
| } | |
| if (includeSpaces) | |
| { | |
| characterSet += SPACE_CHARACTER; | |
| } | |
| char[] password = new char[lengthOfPassword]; | |
| int characterSetLength = characterSet.Length; | |
| System.Random random = new System.Random(); | |
| for (int characterPosition = 0; characterPosition < lengthOfPassword; characterPosition++) | |
| { | |
| password[characterPosition] = characterSet[random.Next(characterSetLength - 1)]; | |
| bool moreThanTwoIdenticalInARow = | |
| characterPosition > MAXIMUM_IDENTICAL_CONSECUTIVE_CHARS | |
| && password[characterPosition] == password[characterPosition - 1] | |
| && password[characterPosition - 1] == password[characterPosition - 2]; | |
| if (moreThanTwoIdenticalInARow) | |
| { | |
| characterPosition--; | |
| } | |
| } | |
| return string.Join(null, password); | |
| } | |
| /// <summary> | |
| /// Checks if the password created is valid | |
| /// </summary> | |
| /// <param name="includeLowercase">Bool to say if lowercase are required</param> | |
| /// <param name="includeUppercase">Bool to say if uppercase are required</param> | |
| /// <param name="includeNumeric">Bool to say if numerics are required</param> | |
| /// <param name="includeSpecial">Bool to say if special characters are required</param> | |
| /// <param name="includeSpaces">Bool to say if spaces are required</param> | |
| /// <param name="password">Generated password</param> | |
| /// <returns>True or False to say if the password is valid or not</returns> | |
| public static bool PasswordIsValid(bool includeLowercase, bool includeUppercase, bool includeNumeric, bool includeSpecial, bool includeSpaces, string password) | |
| { | |
| const string REGEX_LOWERCASE = @"[a-z]"; | |
| const string REGEX_UPPERCASE = @"[A-Z]"; | |
| const string REGEX_NUMERIC = @"[\d]"; | |
| const string REGEX_SPECIAL = @"([!#$%&*@\\])+"; | |
| const string REGEX_SPACE = @"([ ])+"; | |
| bool lowerCaseIsValid = !includeLowercase || (includeLowercase && Regex.IsMatch(password, REGEX_LOWERCASE)); | |
| bool upperCaseIsValid = !includeUppercase || (includeUppercase && Regex.IsMatch(password, REGEX_UPPERCASE)); | |
| bool numericIsValid = !includeNumeric || (includeNumeric && Regex.IsMatch(password, REGEX_NUMERIC)); | |
| bool symbolsAreValid = !includeSpecial || (includeSpecial && Regex.IsMatch(password, REGEX_SPECIAL)); | |
| bool spacesAreValid = !includeSpaces || (includeSpaces && Regex.IsMatch(password, REGEX_SPACE)); | |
| return lowerCaseIsValid && upperCaseIsValid && numericIsValid && symbolsAreValid && spacesAreValid; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
for the viewer:
in short, base32-k.cs is not a standard base32 implementation comply to rfc4648.
https://stackoverflow.com/questions/641361/base32-decoding/7135008,
but still good code :thumb up: