22
33import java .util .function .Function ;
44
5- /*
6- * https://datatracker.ietf.org/doc/html/rfc4648
5+ /**
6+ * Base32 encoder and decoder based on RFC 4648.
7+ * <p>
8+ * Supports both standard Base32 and Base32hex variants, with optional padding.
9+ * </p>
10+ *
11+ * @see <a href="https://datatracker.ietf.org/doc/html/rfc4648">RFC 4648</a>
712 */
813public class Base32 {
914
10- public static char [] ALPHABET_UPPER = new char [] {
15+ /** RFC 4648 standard Base32 alphabet (uppercase). */
16+ public static final char [] ALPHABET_UPPER = new char [] {
1117 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' , 'H' , 'I' ,
1218 'J' , 'K' , 'L' , 'M' , 'N' , 'O' , 'P' , 'Q' , 'R' ,
1319 'S' , 'T' , 'U' , 'V' , 'W' , 'X' , 'Y' , 'Z' , '2' ,
1420 '3' , '4' , '5' , '6' , '7' ,
1521 };
1622
17- public static char [] ALPHABET_LOWER = new char [] {
23+ /** RFC 4648 standard Base32 alphabet (lowercase). */
24+ public static final char [] ALPHABET_LOWER = new char [] {
1825 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' ,
1926 'j' , 'k' , 'l' , 'm' , 'n' , 'o' , 'p' , 'q' , 'r' ,
2027 's' , 't' , 'u' , 'v' , 'w' , 'x' , 'y' , 'z' , '2' ,
2128 '3' , '4' , '5' , '6' , '7' ,
2229 };
2330
24- public static char [] ALPHABET_HEX_LOWER = new char [] {
31+ /** RFC 4648 Base32hex alphabet (lowercase). */
32+ public static final char [] ALPHABET_HEX_LOWER = new char [] {
2533 '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' ,
2634 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' , 'j' ,
2735 'k' , 'l' , 'm' , 'n' , 'o' , 'p' , 'q' , 'r' , 's' , 't' ,
2836 'u' , 'v' ,
2937 };
3038
31- public static char [] ALPHABET_HEX_UPPER = new char [] {
39+ /** RFC 4648 Base32hex alphabet (uppercase). */
40+ public static final char [] ALPHABET_HEX_UPPER = new char [] {
3241 '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' ,
3342 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' , 'H' , 'I' , 'J' ,
3443 'K' , 'L' , 'M' , 'N' , 'O' , 'P' , 'Q' , 'R' , 'S' , 'T' ,
3544 'U' , 'V' ,
3645 };
3746
38- static int [] PADDING = new int [] {
47+ static final int [] PADDING = new int [] {
3948 6 , 4 , 3 , 1 , 0 ,
4049 };
4150
42- static int [] PADDING_REVERSE = new int [] {
51+ static final int [] PADDING_REVERSE = new int [] {
4352 0 , 4 , -1 , 3 , 2 , -1 , 1 , -1 ,
4453 };
4554
55+ /**
56+ * Encodes the given byte array into a Base32 string using the specified
57+ * alphabet.
58+ *
59+ * @param data the data to encode
60+ * @param alphabet the encoding alphabet (must be 32 characters)
61+ * @param padding whether to include padding characters ('=') in the output
62+ * @return the encoded string
63+ * @throws IllegalArgumentException if {@code data} is null
64+ */
4665 public static String encode (final byte [] data , final char [] alphabet , final boolean padding ) {
4766 if (data == null ) {
48- throw new IllegalArgumentException ();
67+ throw new IllegalArgumentException ("Input data must not be null." );
4968 }
5069 if (data .length == 0 ) {
5170 return "" ;
@@ -101,9 +120,19 @@ public static String encode(final byte[] data, final char[] alphabet, final bool
101120 return encoded .toString ();
102121 }
103122
123+ /**
124+ * Decodes a Base32 string into a byte array.
125+ *
126+ * @param encoded the encoded string
127+ * @param charToCode a function that maps each character to its 5-bit code
128+ * @param padding whether padding is expected in the input
129+ * @return the decoded byte array
130+ * @throws IllegalArgumentException if the input is null, malformed, or contains
131+ * invalid characters
132+ */
104133 public static byte [] decode (final String encoded , final Function <Character , Integer > charToCode , boolean padding ) {
105134 if (encoded == null ) {
106- throw new IllegalArgumentException ();
135+ throw new IllegalArgumentException ("Encoded string must not be null." );
107136 }
108137 if (encoded .isEmpty ()) {
109138 return new byte [0 ];
@@ -118,7 +147,7 @@ public static byte[] decode(final String encoded, final Function<Character, Inte
118147
119148 if (padding ) {
120149 if (trailing > 0 ) {
121- throw new IllegalArgumentException ();
150+ throw new IllegalArgumentException ("Invalid padding: base32 string must be a multiple of 8 characters." );
122151 }
123152 pads = getPaddingLength (chars );
124153 length = chars .length - pads ;
@@ -185,7 +214,7 @@ public static byte[] decode(final String encoded, final Function<Character, Inte
185214 }
186215
187216 if (rest > 0 ) {
188- throw new IllegalArgumentException ();
217+ throw new IllegalArgumentException ("Invalid base32 string: leftover bits after decoding." );
189218 }
190219
191220 return data ;
@@ -198,7 +227,7 @@ static final int getDecodedLength(final int length, int pads) {
198227 final int diff = PADDING_REVERSE [pads ];
199228
200229 if (diff == -1 ) {
201- throw new IllegalArgumentException ("Unknown pad size '" + pads + "'" );
230+ throw new IllegalArgumentException ("Invalid number of padding characters: " + pads );
202231 }
203232
204233 return total + diff ;
@@ -218,6 +247,14 @@ static final int getPaddingLength(final char[] data) {
218247 return pads ;
219248 }
220249
250+ /**
251+ * Converts a Base32 character to its 5-bit code. Accepts both upper and
252+ * lowercase letters and digits '2' to '7'.
253+ *
254+ * @param ch the Base32 character
255+ * @return the 5-bit value
256+ * @throws IllegalArgumentException if the character is invalid
257+ */
221258 public static int charToCode (char ch ) {
222259 if (ch >= 'a' && ch <= 'z' ) {
223260 return ch - (int ) 'a' ;
@@ -228,9 +265,17 @@ public static int charToCode(char ch) {
228265 if (ch >= '2' && ch <= '7' ) {
229266 return ch - (int ) '2' + 26 ;
230267 }
231- throw new IllegalArgumentException ("Illegal character '" + ch + "'" );
268+ throw new IllegalArgumentException ("Invalid base32 character: '" + ch + "'" );
232269 }
233270
271+ /**
272+ * Converts a Base32hex character to its 5-bit code. Accepts lowercase letters
273+ * 'a' to 'v', uppercase 'A' to 'V', and digits '0' to '9'.
274+ *
275+ * @param ch the Base32hex character
276+ * @return the 5-bit value
277+ * @throws IllegalArgumentException if the character is invalid
278+ */
234279 public static int charToCodeHex (char ch ) {
235280 if (ch >= 'a' && ch <= 'v' ) {
236281 return ch - (int ) 'a' + 10 ;
@@ -241,6 +286,6 @@ public static int charToCodeHex(char ch) {
241286 if (ch >= '0' && ch <= '9' ) {
242287 return ch - (int ) '0' ;
243288 }
244- throw new IllegalArgumentException ("Illegal character '" + ch + "'" );
289+ throw new IllegalArgumentException ("Invalid base32hex character: '" + ch + "'" );
245290 }
246291}
0 commit comments