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