Home | History | Annotate | Download | only in utils
      1 // Copyright (c) 1999-2004 Brian Wellington (bwelling (at) xbill.org)
      2 
      3 package org.xbill.DNS.utils;
      4 
      5 import 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 
     15 public class base32 {
     16 
     17 public 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 
     26 private String alphabet;
     27 private 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  */
     36 public
     37 base32(String alphabet, boolean padding, boolean lowercase) {
     38 	this.alphabet = alphabet;
     39 	this.padding = padding;
     40 	this.lowercase = lowercase;
     41 }
     42 
     43 static private int
     44 blockLenToPadding(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 
     61 static private int
     62 paddingToBlockLen(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  */
     85 public String
     86 toString(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  */
    147 public byte[]
    148 fromString(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 }
    214