2017-04-12 22:04:23 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
|
|
|
|
namespace MongoAuth
|
|
|
|
|
{
|
|
|
|
|
/* Based off http://stackoverflow.com/a/7135008 */
|
|
|
|
|
internal static class Base32Encoding
|
|
|
|
|
{
|
|
|
|
|
public static byte[] ToBytes(string input)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrEmpty(input))
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentNullException(nameof(input));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
input = input.TrimEnd('='); //remove padding characters
|
|
|
|
|
int byteCount = input.Length * 5 / 8; //this must be TRUNCATED
|
|
|
|
|
var returnArray = new byte[byteCount];
|
|
|
|
|
|
|
|
|
|
byte curByte = 0,
|
2018-02-07 06:16:37 +08:00
|
|
|
|
bitsRemaining = 8;
|
2017-04-12 22:04:23 +08:00
|
|
|
|
|
|
|
|
|
int arrayIndex = 0;
|
|
|
|
|
|
|
|
|
|
foreach (char c in input)
|
|
|
|
|
{
|
|
|
|
|
int 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 ToString(byte[] input)
|
|
|
|
|
{
|
|
|
|
|
if (input == null || input.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentNullException(nameof(input));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int charCount = (int)Math.Ceiling(input.Length / 5d) * 8;
|
|
|
|
|
var returnArray = new char[charCount];
|
|
|
|
|
|
|
|
|
|
byte nextChar = 0,
|
2018-02-07 06:16:37 +08:00
|
|
|
|
bitsRemaining = 5;
|
2017-04-12 22:04:23 +08:00
|
|
|
|
int arrayIndex = 0;
|
|
|
|
|
|
|
|
|
|
foreach (byte 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)
|
2018-02-07 06:16:37 +08:00
|
|
|
|
{
|
2017-04-12 22:04:23 +08:00
|
|
|
|
returnArray[arrayIndex++] = '='; //padding
|
2018-02-07 06:16:37 +08:00
|
|
|
|
}
|
2017-04-12 22:04:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new string(returnArray);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int CharToValue(char c)
|
|
|
|
|
{
|
|
|
|
|
int value = c;
|
|
|
|
|
|
|
|
|
|
//65-90 == uppercase letters
|
|
|
|
|
if (value < 91 && value > 64)
|
|
|
|
|
{
|
|
|
|
|
return value - 65;
|
|
|
|
|
}
|
2018-02-07 06:16:37 +08:00
|
|
|
|
|
2017-04-12 22:04:23 +08:00
|
|
|
|
//50-55 == numbers 2-7
|
|
|
|
|
if (value < 56 && value > 49)
|
|
|
|
|
{
|
|
|
|
|
return value - 24;
|
|
|
|
|
}
|
2018-02-07 06:16:37 +08:00
|
|
|
|
|
2017-04-12 22:04:23 +08:00
|
|
|
|
//97-122 == lowercase letters
|
|
|
|
|
if (value < 123 && value > 96)
|
|
|
|
|
{
|
|
|
|
|
return value - 97;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw new ArgumentException("Character is not a Base32 character.", nameof(c));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static char ValueToChar(byte b)
|
|
|
|
|
{
|
|
|
|
|
if (b < 26)
|
|
|
|
|
{
|
|
|
|
|
return (char)(b + 65);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (b < 32)
|
|
|
|
|
{
|
|
|
|
|
return (char)(b + 24);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw new ArgumentException("Byte is not a value Base32 value.", nameof(b));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|