diff options
Diffstat (limited to 'src/org/xbill/DNS/utils')
-rw-r--r-- | src/org/xbill/DNS/utils/HMAC.java | 182 | ||||
-rw-r--r-- | src/org/xbill/DNS/utils/base16.java | 73 | ||||
-rw-r--r-- | src/org/xbill/DNS/utils/base32.java | 213 | ||||
-rw-r--r-- | src/org/xbill/DNS/utils/base64.java | 145 | ||||
-rw-r--r-- | src/org/xbill/DNS/utils/hexdump.java | 56 |
5 files changed, 669 insertions, 0 deletions
diff --git a/src/org/xbill/DNS/utils/HMAC.java b/src/org/xbill/DNS/utils/HMAC.java new file mode 100644 index 0000000..5eb5afd --- /dev/null +++ b/src/org/xbill/DNS/utils/HMAC.java @@ -0,0 +1,182 @@ +// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org) + +package org.xbill.DNS.utils; + +import java.util.Arrays; +import java.security.*; + +/** + * An implementation of the HMAC message authentication code. + * + * @author Brian Wellington + */ + +public class HMAC { + +private MessageDigest digest; +private int blockLength; + +private byte [] ipad, opad; + +private static final byte IPAD = 0x36; +private static final byte OPAD = 0x5c; + +private void +init(byte [] key) { + int i; + + if (key.length > blockLength) { + key = digest.digest(key); + digest.reset(); + } + ipad = new byte[blockLength]; + opad = new byte[blockLength]; + for (i = 0; i < key.length; i++) { + ipad[i] = (byte) (key[i] ^ IPAD); + opad[i] = (byte) (key[i] ^ OPAD); + } + for (; i < blockLength; i++) { + ipad[i] = IPAD; + opad[i] = OPAD; + } + digest.update(ipad); +} + +/** + * Creates a new HMAC instance + * @param digest The message digest object. + * @param blockLength The block length of the message digest. + * @param key The secret key + */ +public +HMAC(MessageDigest digest, int blockLength, byte [] key) { + digest.reset(); + this.digest = digest; + this.blockLength = blockLength; + init(key); +} + +/** + * Creates a new HMAC instance + * @param digestName The name of the message digest function. + * @param blockLength The block length of the message digest. + * @param key The secret key. + */ +public +HMAC(String digestName, int blockLength, byte [] key) { + try { + digest = MessageDigest.getInstance(digestName); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException("unknown digest algorithm " + + digestName); + } + this.blockLength = blockLength; + init(key); +} + +/** + * Creates a new HMAC instance + * @param digest The message digest object. + * @param key The secret key + * @deprecated won't work with digests using a padding length other than 64; + * use {@code HMAC(MessageDigest digest, int blockLength, + * byte [] key)} instead. + * @see HMAC#HMAC(MessageDigest digest, int blockLength, byte [] key) + */ +public +HMAC(MessageDigest digest, byte [] key) { + this(digest, 64, key); +} + +/** + * Creates a new HMAC instance + * @param digestName The name of the message digest function. + * @param key The secret key. + * @deprecated won't work with digests using a padding length other than 64; + * use {@code HMAC(String digestName, int blockLength, byte [] key)} + * instead + * @see HMAC#HMAC(String digestName, int blockLength, byte [] key) + */ +public +HMAC(String digestName, byte [] key) { + this(digestName, 64, key); +} + +/** + * Adds data to the current hash + * @param b The data + * @param offset The index at which to start adding to the hash + * @param length The number of bytes to hash + */ +public void +update(byte [] b, int offset, int length) { + digest.update(b, offset, length); +} + +/** + * Adds data to the current hash + * @param b The data + */ +public void +update(byte [] b) { + digest.update(b); +} + +/** + * Signs the data (computes the secure hash) + * @return An array with the signature + */ +public byte [] +sign() { + byte [] output = digest.digest(); + digest.reset(); + digest.update(opad); + return digest.digest(output); +} + +/** + * Verifies the data (computes the secure hash and compares it to the input) + * @param signature The signature to compare against + * @return true if the signature matches, false otherwise + */ +public boolean +verify(byte [] signature) { + return verify(signature, false); +} + +/** + * Verifies the data (computes the secure hash and compares it to the input) + * @param signature The signature to compare against + * @param truncation_ok If true, the signature may be truncated; only the + * number of bytes in the provided signature are compared. + * @return true if the signature matches, false otherwise + */ +public boolean +verify(byte [] signature, boolean truncation_ok) { + byte [] expected = sign(); + if (truncation_ok && signature.length < expected.length) { + byte [] truncated = new byte[signature.length]; + System.arraycopy(expected, 0, truncated, 0, truncated.length); + expected = truncated; + } + return Arrays.equals(signature, expected); +} + +/** + * Resets the HMAC object for further use + */ +public void +clear() { + digest.reset(); + digest.update(ipad); +} + +/** + * Returns the length of the digest. + */ +public int +digestLength() { + return digest.getDigestLength(); +} + +} diff --git a/src/org/xbill/DNS/utils/base16.java b/src/org/xbill/DNS/utils/base16.java new file mode 100644 index 0000000..58024e6 --- /dev/null +++ b/src/org/xbill/DNS/utils/base16.java @@ -0,0 +1,73 @@ +// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org) + +package org.xbill.DNS.utils; + +import java.io.*; + +/** + * Routines for converting between Strings of hex-encoded data and arrays of + * binary data. This is not actually used by DNS. + * + * @author Brian Wellington + */ + +public class base16 { + +private static final String Base16 = "0123456789ABCDEF"; + +private +base16() {} + +/** + * Convert binary data to a hex-encoded String + * @param b An array containing binary data + * @return A String containing the encoded data + */ +public static String +toString(byte [] b) { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + + for (int i = 0; i < b.length; i++) { + short value = (short) (b[i] & 0xFF); + byte high = (byte) (value >> 4); + byte low = (byte) (value & 0xF); + os.write(Base16.charAt(high)); + os.write(Base16.charAt(low)); + } + return new String(os.toByteArray()); +} + +/** + * Convert a hex-encoded String to binary data + * @param str A String containing the encoded data + * @return An array containing the binary data, or null if the string is invalid + */ +public static byte [] +fromString(String str) { + ByteArrayOutputStream bs = new ByteArrayOutputStream(); + byte [] raw = str.getBytes(); + for (int i = 0; i < raw.length; i++) { + if (!Character.isWhitespace((char)raw[i])) + bs.write(raw[i]); + } + byte [] in = bs.toByteArray(); + if (in.length % 2 != 0) { + return null; + } + + bs.reset(); + DataOutputStream ds = new DataOutputStream(bs); + + for (int i = 0; i < in.length; i += 2) { + byte high = (byte) Base16.indexOf(Character.toUpperCase((char)in[i])); + byte low = (byte) Base16.indexOf(Character.toUpperCase((char)in[i+1])); + try { + ds.writeByte((high << 4) + low); + } + catch (IOException e) { + } + } + return bs.toByteArray(); +} + +} diff --git a/src/org/xbill/DNS/utils/base32.java b/src/org/xbill/DNS/utils/base32.java new file mode 100644 index 0000000..a2f26ea --- /dev/null +++ b/src/org/xbill/DNS/utils/base32.java @@ -0,0 +1,213 @@ +// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org) + +package org.xbill.DNS.utils; + +import java.io.*; + +/** + * Routines for converting between Strings of base32-encoded data and arrays + * of binary data. This currently supports the base32 and base32hex alphabets + * specified in RFC 4648, sections 6 and 7. + * + * @author Brian Wellington + */ + +public class base32 { + +public static class Alphabet { + private Alphabet() {} + + public static final String BASE32 = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567="; + public static final String BASE32HEX = + "0123456789ABCDEFGHIJKLMNOPQRSTUV="; +}; + +private String alphabet; +private boolean padding, lowercase; + +/** + * Creates an object that can be used to do base32 conversions. + * @param alphabet Which alphabet should be used + * @param padding Whether padding should be used + * @param lowercase Whether lowercase characters should be used. + * default parameters (The standard base32 alphabet, no padding, uppercase) + */ +public +base32(String alphabet, boolean padding, boolean lowercase) { + this.alphabet = alphabet; + this.padding = padding; + this.lowercase = lowercase; +} + +static private int +blockLenToPadding(int blocklen) { + switch (blocklen) { + case 1: + return 6; + case 2: + return 4; + case 3: + return 3; + case 4: + return 1; + case 5: + return 0; + default: + return -1; + } +} + +static private int +paddingToBlockLen(int padlen) { + switch (padlen) { + case 6: + return 1; + case 4: + return 2; + case 3: + return 3; + case 1: + return 4; + case 0: + return 5; + default : + return -1; + } +} + +/** + * Convert binary data to a base32-encoded String + * + * @param b An array containing binary data + * @return A String containing the encoded data + */ +public String +toString(byte [] b) { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + + for (int i = 0; i < (b.length + 4) / 5; i++) { + short s[] = new short[5]; + int t[] = new int[8]; + + int blocklen = 5; + for (int j = 0; j < 5; j++) { + if ((i * 5 + j) < b.length) + s[j] = (short) (b[i * 5 + j] & 0xFF); + else { + s[j] = 0; + blocklen--; + } + } + int padlen = blockLenToPadding(blocklen); + + // convert the 5 byte block into 8 characters (values 0-31). + + // upper 5 bits from first byte + t[0] = (byte) ((s[0] >> 3) & 0x1F); + // lower 3 bits from 1st byte, upper 2 bits from 2nd. + t[1] = (byte) (((s[0] & 0x07) << 2) | ((s[1] >> 6) & 0x03)); + // bits 5-1 from 2nd. + t[2] = (byte) ((s[1] >> 1) & 0x1F); + // lower 1 bit from 2nd, upper 4 from 3rd + t[3] = (byte) (((s[1] & 0x01) << 4) | ((s[2] >> 4) & 0x0F)); + // lower 4 from 3rd, upper 1 from 4th. + t[4] = (byte) (((s[2] & 0x0F) << 1) | ((s[3] >> 7) & 0x01)); + // bits 6-2 from 4th + t[5] = (byte) ((s[3] >> 2) & 0x1F); + // lower 2 from 4th, upper 3 from 5th; + t[6] = (byte) (((s[3] & 0x03) << 3) | ((s[4] >> 5) & 0x07)); + // lower 5 from 5th; + t[7] = (byte) (s[4] & 0x1F); + + // write out the actual characters. + for (int j = 0; j < t.length - padlen; j++) { + char c = alphabet.charAt(t[j]); + if (lowercase) + c = Character.toLowerCase(c); + os.write(c); + } + + // write out the padding (if any) + if (padding) { + for (int j = t.length - padlen; j < t.length; j++) + os.write('='); + } + } + + return new String(os.toByteArray()); +} + +/** + * Convert a base32-encoded String to binary data + * + * @param str A String containing the encoded data + * @return An array containing the binary data, or null if the string is invalid + */ +public byte[] +fromString(String str) { + ByteArrayOutputStream bs = new ByteArrayOutputStream(); + byte [] raw = str.getBytes(); + for (int i = 0; i < raw.length; i++) + { + char c = (char) raw[i]; + if (!Character.isWhitespace(c)) { + c = Character.toUpperCase(c); + bs.write((byte) c); + } + } + + if (padding) { + if (bs.size() % 8 != 0) + return null; + } else { + while (bs.size() % 8 != 0) + bs.write('='); + } + + byte [] in = bs.toByteArray(); + + bs.reset(); + DataOutputStream ds = new DataOutputStream(bs); + + for (int i = 0; i < in.length / 8; i++) { + short[] s = new short[8]; + int[] t = new int[5]; + + int padlen = 8; + for (int j = 0; j < 8; j++) { + char c = (char) in[i * 8 + j]; + if (c == '=') + break; + s[j] = (short) alphabet.indexOf(in[i * 8 + j]); + if (s[j] < 0) + return null; + padlen--; + } + int blocklen = paddingToBlockLen(padlen); + if (blocklen < 0) + return null; + + // all 5 bits of 1st, high 3 (of 5) of 2nd + t[0] = (s[0] << 3) | s[1] >> 2; + // lower 2 of 2nd, all 5 of 3rd, high 1 of 4th + t[1] = ((s[1] & 0x03) << 6) | (s[2] << 1) | (s[3] >> 4); + // lower 4 of 4th, high 4 of 5th + t[2] = ((s[3] & 0x0F) << 4) | ((s[4] >> 1) & 0x0F); + // lower 1 of 5th, all 5 of 6th, high 2 of 7th + t[3] = (s[4] << 7) | (s[5] << 2) | (s[6] >> 3); + // lower 3 of 7th, all of 8th + t[4] = ((s[6] & 0x07) << 5) | s[7]; + + try { + for (int j = 0; j < blocklen; j++) + ds.writeByte((byte) (t[j] & 0xFF)); + } + catch (IOException e) { + } + } + + return bs.toByteArray(); +} + +} diff --git a/src/org/xbill/DNS/utils/base64.java b/src/org/xbill/DNS/utils/base64.java new file mode 100644 index 0000000..54567cf --- /dev/null +++ b/src/org/xbill/DNS/utils/base64.java @@ -0,0 +1,145 @@ +// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org) + +package org.xbill.DNS.utils; + +import java.io.*; + +/** + * Routines for converting between Strings of base64-encoded data and arrays of + * binary data. + * + * @author Brian Wellington + */ + +public class base64 { + +private static final String Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + +private +base64() {} + +/** + * Convert binary data to a base64-encoded String + * @param b An array containing binary data + * @return A String containing the encoded data + */ +public static String +toString(byte [] b) { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + + for (int i = 0; i < (b.length + 2) / 3; i++) { + short [] s = new short[3]; + short [] t = new short[4]; + for (int j = 0; j < 3; j++) { + if ((i * 3 + j) < b.length) + s[j] = (short) (b[i*3+j] & 0xFF); + else + s[j] = -1; + } + + t[0] = (short) (s[0] >> 2); + if (s[1] == -1) + t[1] = (short) (((s[0] & 0x3) << 4)); + else + t[1] = (short) (((s[0] & 0x3) << 4) + (s[1] >> 4)); + if (s[1] == -1) + t[2] = t[3] = 64; + else if (s[2] == -1) { + t[2] = (short) (((s[1] & 0xF) << 2)); + t[3] = 64; + } + else { + t[2] = (short) (((s[1] & 0xF) << 2) + (s[2] >> 6)); + t[3] = (short) (s[2] & 0x3F); + } + for (int j = 0; j < 4; j++) + os.write(Base64.charAt(t[j])); + } + return new String(os.toByteArray()); +} + +/** + * Formats data into a nicely formatted base64 encoded String + * @param b An array containing binary data + * @param lineLength The number of characters per line + * @param prefix A string prefixing the characters on each line + * @param addClose Whether to add a close parenthesis or not + * @return A String representing the formatted output + */ +public static String +formatString(byte [] b, int lineLength, String prefix, boolean addClose) { + String s = toString(b); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < s.length(); i += lineLength) { + sb.append (prefix); + if (i + lineLength >= s.length()) { + sb.append(s.substring(i)); + if (addClose) + sb.append(" )"); + } + else { + sb.append(s.substring(i, i + lineLength)); + sb.append("\n"); + } + } + return sb.toString(); +} + + +/** + * Convert a base64-encoded String to binary data + * @param str A String containing the encoded data + * @return An array containing the binary data, or null if the string is invalid + */ +public static byte [] +fromString(String str) { + ByteArrayOutputStream bs = new ByteArrayOutputStream(); + byte [] raw = str.getBytes(); + for (int i = 0; i < raw.length; i++) { + if (!Character.isWhitespace((char)raw[i])) + bs.write(raw[i]); + } + byte [] in = bs.toByteArray(); + if (in.length % 4 != 0) { + return null; + } + + bs.reset(); + DataOutputStream ds = new DataOutputStream(bs); + + for (int i = 0; i < (in.length + 3) / 4; i++) { + short [] s = new short[4]; + short [] t = new short[3]; + + for (int j = 0; j < 4; j++) + s[j] = (short) Base64.indexOf(in[i*4+j]); + + t[0] = (short) ((s[0] << 2) + (s[1] >> 4)); + if (s[2] == 64) { + t[1] = t[2] = (short) (-1); + if ((s[1] & 0xF) != 0) + return null; + } + else if (s[3] == 64) { + t[1] = (short) (((s[1] << 4) + (s[2] >> 2)) & 0xFF); + t[2] = (short) (-1); + if ((s[2] & 0x3) != 0) + return null; + } + else { + t[1] = (short) (((s[1] << 4) + (s[2] >> 2)) & 0xFF); + t[2] = (short) (((s[2] << 6) + s[3]) & 0xFF); + } + + try { + for (int j = 0; j < 3; j++) + if (t[j] >= 0) + ds.writeByte(t[j]); + } + catch (IOException e) { + } + } + return bs.toByteArray(); +} + +} diff --git a/src/org/xbill/DNS/utils/hexdump.java b/src/org/xbill/DNS/utils/hexdump.java new file mode 100644 index 0000000..1a79a40 --- /dev/null +++ b/src/org/xbill/DNS/utils/hexdump.java @@ -0,0 +1,56 @@ +// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org) + +package org.xbill.DNS.utils; + +/** + * A routine to produce a nice looking hex dump + * + * @author Brian Wellington + */ + +public class hexdump { + +private static final char [] hex = "0123456789ABCDEF".toCharArray(); + +/** + * Dumps a byte array into hex format. + * @param description If not null, a description of the data. + * @param b The data to be printed. + * @param offset The start of the data in the array. + * @param length The length of the data in the array. + */ +public static String +dump(String description, byte [] b, int offset, int length) { + StringBuffer sb = new StringBuffer(); + + sb.append(length + "b"); + if (description != null) + sb.append(" (" + description + ")"); + sb.append(':'); + + int prefixlen = sb.toString().length(); + prefixlen = (prefixlen + 8) & ~ 7; + sb.append('\t'); + + int perline = (80 - prefixlen) / 3; + for (int i = 0; i < length; i++) { + if (i != 0 && i % perline == 0) { + sb.append('\n'); + for (int j = 0; j < prefixlen / 8 ; j++) + sb.append('\t'); + } + int value = (int)(b[i + offset]) & 0xFF; + sb.append(hex[(value >> 4)]); + sb.append(hex[(value & 0xF)]); + sb.append(' '); + } + sb.append('\n'); + return sb.toString(); +} + +public static String +dump(String s, byte [] b) { + return dump(s, b, 0, b.length); +} + +} |