This repository has been archived by the owner on Dec 20, 2018. It is now read-only.
/
Base32.cs
119 lines (103 loc) · 4.2 KB
/
Base32.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Text;
namespace Microsoft.AspNetCore.Identity
{
// See http://tools.ietf.org/html/rfc3548#section-5
internal static class Base32
{
private static readonly string _base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
public static string ToBase32(byte[] input)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
StringBuilder sb = new StringBuilder();
for (int offset = 0; offset < input.Length;)
{
byte a, b, c, d, e, f, g, h;
int numCharsToOutput = GetNextGroup(input, ref offset, out a, out b, out c, out d, out e, out f, out g, out h);
sb.Append((numCharsToOutput >= 1) ? _base32Chars[a] : '=');
sb.Append((numCharsToOutput >= 2) ? _base32Chars[b] : '=');
sb.Append((numCharsToOutput >= 3) ? _base32Chars[c] : '=');
sb.Append((numCharsToOutput >= 4) ? _base32Chars[d] : '=');
sb.Append((numCharsToOutput >= 5) ? _base32Chars[e] : '=');
sb.Append((numCharsToOutput >= 6) ? _base32Chars[f] : '=');
sb.Append((numCharsToOutput >= 7) ? _base32Chars[g] : '=');
sb.Append((numCharsToOutput >= 8) ? _base32Chars[h] : '=');
}
return sb.ToString();
}
public static byte[] FromBase32(string input)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
input = input.TrimEnd('=').ToUpperInvariant();
if (input.Length == 0)
{
return new byte[0];
}
var output = new byte[input.Length * 5 / 8];
var bitIndex = 0;
var inputIndex = 0;
var outputBits = 0;
var outputIndex = 0;
while (outputIndex < output.Length)
{
var byteIndex = _base32Chars.IndexOf(input[inputIndex]);
if (byteIndex < 0)
{
throw new FormatException();
}
var bits = Math.Min(5 - bitIndex, 8 - outputBits);
output[outputIndex] <<= bits;
output[outputIndex] |= (byte)(byteIndex >> (5 - (bitIndex + bits)));
bitIndex += bits;
if (bitIndex >= 5)
{
inputIndex++;
bitIndex = 0;
}
outputBits += bits;
if (outputBits >= 8)
{
outputIndex++;
outputBits = 0;
}
}
return output;
}
// returns the number of bytes that were output
private static int GetNextGroup(byte[] input, ref int offset, out byte a, out byte b, out byte c, out byte d, out byte e, out byte f, out byte g, out byte h)
{
uint b1, b2, b3, b4, b5;
int retVal;
switch (offset - input.Length)
{
case 1: retVal = 2; break;
case 2: retVal = 4; break;
case 3: retVal = 5; break;
case 4: retVal = 7; break;
default: retVal = 8; break;
}
b1 = (offset < input.Length) ? input[offset++] : 0U;
b2 = (offset < input.Length) ? input[offset++] : 0U;
b3 = (offset < input.Length) ? input[offset++] : 0U;
b4 = (offset < input.Length) ? input[offset++] : 0U;
b5 = (offset < input.Length) ? input[offset++] : 0U;
a = (byte)(b1 >> 3);
b = (byte)(((b1 & 0x07) << 2) | (b2 >> 6));
c = (byte)((b2 >> 1) & 0x1f);
d = (byte)(((b2 & 0x01) << 4) | (b3 >> 4));
e = (byte)(((b3 & 0x0f) << 1) | (b4 >> 7));
f = (byte)((b4 >> 2) & 0x1f);
g = (byte)(((b4 & 0x3) << 3) | (b5 >> 5));
h = (byte)(b5 & 0x1f);
return retVal;
}
}
}