blob: a2f26eaa6f4c9dd82d73626bfc08e05dc5dcd7b9 [file] [log] [blame]
Shuyi Chend7955ce2013-05-22 14:51:55 -07001// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
2
3package org.xbill.DNS.utils;
4
5import java.io.*;
6
7/**
8 * Routines for converting between Strings of base32-encoded data and arrays
9 * of binary data. This currently supports the base32 and base32hex alphabets
10 * specified in RFC 4648, sections 6 and 7.
11 *
12 * @author Brian Wellington
13 */
14
15public class base32 {
16
17public static class Alphabet {
18 private Alphabet() {}
19
20 public static final String BASE32 =
21 "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=";
22 public static final String BASE32HEX =
23 "0123456789ABCDEFGHIJKLMNOPQRSTUV=";
24};
25
26private String alphabet;
27private boolean padding, lowercase;
28
29/**
30 * Creates an object that can be used to do base32 conversions.
31 * @param alphabet Which alphabet should be used
32 * @param padding Whether padding should be used
33 * @param lowercase Whether lowercase characters should be used.
34 * default parameters (The standard base32 alphabet, no padding, uppercase)
35 */
36public
37base32(String alphabet, boolean padding, boolean lowercase) {
38 this.alphabet = alphabet;
39 this.padding = padding;
40 this.lowercase = lowercase;
41}
42
43static private int
44blockLenToPadding(int blocklen) {
45 switch (blocklen) {
46 case 1:
47 return 6;
48 case 2:
49 return 4;
50 case 3:
51 return 3;
52 case 4:
53 return 1;
54 case 5:
55 return 0;
56 default:
57 return -1;
58 }
59}
60
61static private int
62paddingToBlockLen(int padlen) {
63 switch (padlen) {
64 case 6:
65 return 1;
66 case 4:
67 return 2;
68 case 3:
69 return 3;
70 case 1:
71 return 4;
72 case 0:
73 return 5;
74 default :
75 return -1;
76 }
77}
78
79/**
80 * Convert binary data to a base32-encoded String
81 *
82 * @param b An array containing binary data
83 * @return A String containing the encoded data
84 */
85public String
86toString(byte [] b) {
87 ByteArrayOutputStream os = new ByteArrayOutputStream();
88
89 for (int i = 0; i < (b.length + 4) / 5; i++) {
90 short s[] = new short[5];
91 int t[] = new int[8];
92
93 int blocklen = 5;
94 for (int j = 0; j < 5; j++) {
95 if ((i * 5 + j) < b.length)
96 s[j] = (short) (b[i * 5 + j] & 0xFF);
97 else {
98 s[j] = 0;
99 blocklen--;
100 }
101 }
102 int padlen = blockLenToPadding(blocklen);
103
104 // convert the 5 byte block into 8 characters (values 0-31).
105
106 // upper 5 bits from first byte
107 t[0] = (byte) ((s[0] >> 3) & 0x1F);
108 // lower 3 bits from 1st byte, upper 2 bits from 2nd.
109 t[1] = (byte) (((s[0] & 0x07) << 2) | ((s[1] >> 6) & 0x03));
110 // bits 5-1 from 2nd.
111 t[2] = (byte) ((s[1] >> 1) & 0x1F);
112 // lower 1 bit from 2nd, upper 4 from 3rd
113 t[3] = (byte) (((s[1] & 0x01) << 4) | ((s[2] >> 4) & 0x0F));
114 // lower 4 from 3rd, upper 1 from 4th.
115 t[4] = (byte) (((s[2] & 0x0F) << 1) | ((s[3] >> 7) & 0x01));
116 // bits 6-2 from 4th
117 t[5] = (byte) ((s[3] >> 2) & 0x1F);
118 // lower 2 from 4th, upper 3 from 5th;
119 t[6] = (byte) (((s[3] & 0x03) << 3) | ((s[4] >> 5) & 0x07));
120 // lower 5 from 5th;
121 t[7] = (byte) (s[4] & 0x1F);
122
123 // write out the actual characters.
124 for (int j = 0; j < t.length - padlen; j++) {
125 char c = alphabet.charAt(t[j]);
126 if (lowercase)
127 c = Character.toLowerCase(c);
128 os.write(c);
129 }
130
131 // write out the padding (if any)
132 if (padding) {
133 for (int j = t.length - padlen; j < t.length; j++)
134 os.write('=');
135 }
136 }
137
138 return new String(os.toByteArray());
139}
140
141/**
142 * Convert a base32-encoded String to binary data
143 *
144 * @param str A String containing the encoded data
145 * @return An array containing the binary data, or null if the string is invalid
146 */
147public byte[]
148fromString(String str) {
149 ByteArrayOutputStream bs = new ByteArrayOutputStream();
150 byte [] raw = str.getBytes();
151 for (int i = 0; i < raw.length; i++)
152 {
153 char c = (char) raw[i];
154 if (!Character.isWhitespace(c)) {
155 c = Character.toUpperCase(c);
156 bs.write((byte) c);
157 }
158 }
159
160 if (padding) {
161 if (bs.size() % 8 != 0)
162 return null;
163 } else {
164 while (bs.size() % 8 != 0)
165 bs.write('=');
166 }
167
168 byte [] in = bs.toByteArray();
169
170 bs.reset();
171 DataOutputStream ds = new DataOutputStream(bs);
172
173 for (int i = 0; i < in.length / 8; i++) {
174 short[] s = new short[8];
175 int[] t = new int[5];
176
177 int padlen = 8;
178 for (int j = 0; j < 8; j++) {
179 char c = (char) in[i * 8 + j];
180 if (c == '=')
181 break;
182 s[j] = (short) alphabet.indexOf(in[i * 8 + j]);
183 if (s[j] < 0)
184 return null;
185 padlen--;
186 }
187 int blocklen = paddingToBlockLen(padlen);
188 if (blocklen < 0)
189 return null;
190
191 // all 5 bits of 1st, high 3 (of 5) of 2nd
192 t[0] = (s[0] << 3) | s[1] >> 2;
193 // lower 2 of 2nd, all 5 of 3rd, high 1 of 4th
194 t[1] = ((s[1] & 0x03) << 6) | (s[2] << 1) | (s[3] >> 4);
195 // lower 4 of 4th, high 4 of 5th
196 t[2] = ((s[3] & 0x0F) << 4) | ((s[4] >> 1) & 0x0F);
197 // lower 1 of 5th, all 5 of 6th, high 2 of 7th
198 t[3] = (s[4] << 7) | (s[5] << 2) | (s[6] >> 3);
199 // lower 3 of 7th, all of 8th
200 t[4] = ((s[6] & 0x07) << 5) | s[7];
201
202 try {
203 for (int j = 0; j < blocklen; j++)
204 ds.writeByte((byte) (t[j] & 0xFF));
205 }
206 catch (IOException e) {
207 }
208 }
209
210 return bs.toByteArray();
211}
212
213}