1
2
3
4
5
6
7
8 package edu.internet2.middleware.shibboleth.common.util;
9
10
11
12
13
14
15 public class Base32 {
16
17
18 private static final String base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
19
20
21 private static final byte[] base32Lookup =
22 { 26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,
23 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
24 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
25 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
26 15,16,17,18,19,20,21,22,23,24,25
27 };
28
29
30 private static final String errorCanonicalLength = "non canonical Base32 string length";
31 private static final String errorCanonicalEnd = "non canonical bits at end of Base32 string";
32 private static final String errorInvalidChar = "invalid character in Base32 string";
33
34
35
36
37
38
39 static public String encode(final byte[] bytes) {
40
41 StringBuffer base32 = new StringBuffer((bytes.length * 8 + 4) / 5);
42 int currByte, digit, i = 0;
43
44 while (i < bytes.length) {
45
46
47
48
49
50
51 currByte = bytes[i++] & 255;
52 base32.append(base32Chars.charAt(currByte >> 3));
53 digit = (currByte & 7) << 2;
54 if (i >= bytes.length) {
55 base32.append(base32Chars.charAt(digit));
56 break;
57 }
58
59
60
61 currByte = bytes[i++] & 255;
62 base32.append(base32Chars.charAt(digit | (currByte >> 6)));
63 base32.append(base32Chars.charAt((currByte >> 1) & 31));
64 digit = (currByte & 1) << 4;
65 if (i >= bytes.length) {
66 base32.append(base32Chars.charAt(digit));
67 break;
68 }
69
70
71 currByte = bytes[i++] & 255;
72 base32.append(base32Chars.charAt(digit | (currByte >> 4)));
73 digit = (currByte & 15) << 1;
74 if (i >= bytes.length) {
75 base32.append(base32Chars.charAt(digit));
76 break;
77 }
78
79
80 currByte = bytes[i++] & 255;
81 base32.append(base32Chars.charAt(digit | (currByte >> 7)));
82 base32.append(base32Chars.charAt((currByte >> 2) & 31));
83 digit = (currByte & 3) << 3;
84 if (i >= bytes.length) {
85 base32.append(base32Chars.charAt(digit));
86 break;
87 }
88
89
90 currByte = bytes[i++] & 255;
91 base32.append(base32Chars.charAt(digit | (currByte >> 5)));
92 base32.append(base32Chars.charAt(currByte & 31));
93
94 }
95
96 return base32.toString();
97 }
98
99
100
101
102
103
104
105
106 static public byte[] decode(final String base32) throws IllegalArgumentException {
107
108
109
110
111
112
113
114
115
116 switch (base32.length() % 8) {
117
118 case 1:
119 case 3:
120 case 6:
121
122 throw new IllegalArgumentException(errorCanonicalLength);
123 }
124
125 byte[] bytes = new byte[base32.length() * 5 / 8];
126 int offset = 0, i = 0, lookup;
127 byte nextByte, digit;
128
129
130
131 while (i < base32.length()) {
132
133
134 lookup = base32.charAt(i++) - '2';
135 if (lookup < 0 || lookup >= base32Lookup.length) {
136 throw new IllegalArgumentException(errorInvalidChar);
137 }
138 digit = base32Lookup[lookup];
139 if (digit == -1) {
140 throw new IllegalArgumentException(errorInvalidChar);
141 }
142
143
144 nextByte = (byte)(digit << 3);
145
146
147
148 lookup = base32.charAt(i++) - '2';
149 if (lookup < 0 || lookup >= base32Lookup.length) {
150 throw new IllegalArgumentException(errorInvalidChar);
151 }
152 digit = base32Lookup[lookup];
153 if (digit == -1) {
154 throw new IllegalArgumentException(errorInvalidChar);
155 }
156
157
158 bytes[offset++] = (byte)(nextByte | (digit >> 2));
159 nextByte = (byte)((digit & 3) << 6);
160 if (i >= base32.length()) {
161 if (nextByte != (byte)0) {
162 throw new IllegalArgumentException(errorCanonicalEnd);
163 }
164 break;
165 }
166
167
168
169 lookup = base32.charAt(i++) - '2';
170 if (lookup < 0 || lookup >= base32Lookup.length) {
171 throw new IllegalArgumentException(errorInvalidChar);
172 }
173 digit = base32Lookup[lookup];
174 if (digit == -1) {
175 throw new IllegalArgumentException(errorInvalidChar);
176 }
177
178
179 nextByte |= (byte)(digit << 1);
180
181
182
183 lookup = base32.charAt(i++) - '2';
184 if (lookup < 0 || lookup >= base32Lookup.length) {
185 throw new IllegalArgumentException(errorInvalidChar);
186 }
187 digit = base32Lookup[lookup];
188 if (digit == -1) {
189 throw new IllegalArgumentException(errorInvalidChar);
190 }
191
192
193 bytes[offset++] = (byte)(nextByte | (digit >> 4));
194 nextByte = (byte)((digit & 15) << 4);
195 if (i >= base32.length()) {
196 if (nextByte != (byte)0) {
197 throw new IllegalArgumentException(errorCanonicalEnd);
198 }
199 break;
200 }
201
202
203
204 lookup = base32.charAt(i++) - '2';
205 if (lookup < 0 || lookup >= base32Lookup.length) {
206 throw new IllegalArgumentException(errorInvalidChar);
207 }
208 digit = base32Lookup[lookup];
209 if (digit == -1) {
210 throw new IllegalArgumentException(errorInvalidChar);
211 }
212
213
214 bytes[offset++] = (byte)(nextByte | (digit >> 1));
215 nextByte = (byte)((digit & 1) << 7);
216 if (i >= base32.length()) {
217 if (nextByte != (byte)0) {
218 throw new IllegalArgumentException(errorCanonicalEnd);
219 }
220 break;
221 }
222
223
224
225 lookup = base32.charAt(i++) - '2';
226 if (lookup < 0 || lookup >= base32Lookup.length) {
227 throw new IllegalArgumentException(errorInvalidChar);
228 }
229 digit = base32Lookup[lookup];
230 if (digit == -1) {
231 throw new IllegalArgumentException(errorInvalidChar);
232 }
233
234
235 nextByte |= (byte)(digit << 2);
236
237
238
239 lookup = base32.charAt(i++) - '2';
240 if (lookup < 0 || lookup >= base32Lookup.length) {
241 throw new IllegalArgumentException(errorInvalidChar);
242 }
243 digit = base32Lookup[lookup];
244 if (digit == -1) {
245 throw new IllegalArgumentException(errorInvalidChar);
246 }
247
248
249 bytes[offset++] = (byte)(nextByte | (digit >> 3));
250 nextByte = (byte)((digit & 7) << 5);
251 if (i >= base32.length()) {
252 if (nextByte != (byte)0) {
253 throw new IllegalArgumentException(errorCanonicalEnd);
254 }
255 break;
256 }
257
258
259
260 lookup = base32.charAt(i++) - '2';
261 if (lookup < 0 || lookup >= base32Lookup.length) {
262 throw new IllegalArgumentException(errorInvalidChar);
263 }
264 digit = base32Lookup[lookup];
265 if (digit == -1) {
266 throw new IllegalArgumentException(errorInvalidChar);
267 }
268
269
270 bytes[offset++] = (byte)(nextByte | digit);
271
272 }
273
274
275 return bytes;
276 }
277 }
278