aboutsummaryrefslogtreecommitdiff
path: root/src/org/xbill/DNS/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/xbill/DNS/utils')
-rw-r--r--src/org/xbill/DNS/utils/HMAC.java182
-rw-r--r--src/org/xbill/DNS/utils/base16.java73
-rw-r--r--src/org/xbill/DNS/utils/base32.java213
-rw-r--r--src/org/xbill/DNS/utils/base64.java145
-rw-r--r--src/org/xbill/DNS/utils/hexdump.java56
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);
+}
+
+}