summaryrefslogtreecommitdiffstats
path: root/base/util/src/com/netscape/cmsutil/util/HMACDigest.java
diff options
context:
space:
mode:
Diffstat (limited to 'base/util/src/com/netscape/cmsutil/util/HMACDigest.java')
-rw-r--r--base/util/src/com/netscape/cmsutil/util/HMACDigest.java198
1 files changed, 198 insertions, 0 deletions
diff --git a/base/util/src/com/netscape/cmsutil/util/HMACDigest.java b/base/util/src/com/netscape/cmsutil/util/HMACDigest.java
new file mode 100644
index 000000000..09bf53bbf
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/util/HMACDigest.java
@@ -0,0 +1,198 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.util;
+
+import java.security.MessageDigest;
+
+/**
+ * This class implements the HMAC algorithm specified in RFC 2104 using
+ * any MessageDigest.
+ *
+ * @author mikep
+ * @version $Revision$, $Date$
+ * @see java.security.MessageDigest
+ */
+public class HMACDigest implements Cloneable {
+ public static final int PAD_BYTES = 64;
+ public static final int IPAD = 0x36;
+ public static final int OPAD = 0x5C;
+
+ /**
+ * inner padding - key XORd with ipad
+ */
+ private byte[] mKeyIpad = new byte[PAD_BYTES];
+
+ /**
+ * outer padding - key XORd with opad
+ */
+ private byte[] mKeyOpad = new byte[PAD_BYTES];
+
+ /**
+ * The real MessageDigest
+ */
+ private MessageDigest mMD = null;
+
+ /**
+ * Creates an HMACDigest
+ *
+ * @param md The MessageDigest to be used for the HMAC calculation. It
+ * must be clonable.
+ */
+ public HMACDigest(MessageDigest md) {
+ mMD = md;
+ }
+
+ /**
+ * Creates an HMACDigest and initializes the HMAC function
+ * with the given key.
+ *
+ * @param md The MessageDigest to be used for the HMAC calculation. It
+ * must be clonable.
+ * @param key The key value to be used in the HMAC calculation
+ */
+ public HMACDigest(MessageDigest md, byte[] key) {
+ this(md);
+ init(key);
+ }
+
+ /**
+ * Return the MessageDigest used for this HMAC
+ */
+ public MessageDigest getMessageDigest() {
+ return mMD;
+ }
+
+ /**
+ * Initialize the HMAC function
+ *
+ * The HMAC transform looks like:
+ *
+ * hash(key XOR opad, hash(key XOR ipad, text))
+ *
+ * where key is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ *
+ * This routine must be called after every reset.
+ *
+ * @param key The password used to protect the hash value
+ */
+ public void init(byte[] key) {
+ int i;
+
+ reset();
+
+ // If the key is longer than 64 bytes, just hash it down
+ if (key.length > 64) {
+ key = mMD.digest(key);
+ mMD.reset(); // Redundant?
+ }
+
+ // Copy the key. Truncate if key is too long
+ for (i = 0; i < key.length && i < PAD_BYTES; i++) {
+ mKeyIpad[i] = key[i];
+ mKeyOpad[i] = key[i];
+ }
+
+ // XOR in the pads
+ for (i = 0; i < PAD_BYTES; i++) {
+ mKeyIpad[i] ^= IPAD;
+ mKeyOpad[i] ^= OPAD;
+ }
+
+ mMD.update(mKeyIpad);
+
+ // Hmmm, we really shouldn't key Opad around in memory for so
+ // long, but it would just force the user to key their key around
+ // until digest() time. Oh well, at least clear the key and Ipad
+ for (i = 0; i < PAD_BYTES; i++) {
+ mKeyIpad[i] = 0;
+ }
+ for (i = 0; i < key.length; i++) {
+ key[0] = 0;
+ }
+ }
+
+ /**
+ * Updates the digest using the specified array of bytes.
+ *
+ * @param input the array of bytes.
+ */
+ public void update(byte[] input) {
+ mMD.update(input);
+ }
+
+ /**
+ * Completes the HMAC computation with the outer pad
+ * The digest is reset after this call is made.
+ *
+ * @return the array of bytes for the resulting hash value.
+ */
+ public byte[] digest() {
+ byte[] finalDigest;
+ byte[] innerDigest = mMD.digest();
+
+ mMD.reset(); // Redundant?
+ mMD.update(mKeyOpad);
+ mMD.update(innerDigest);
+ finalDigest = mMD.digest();
+ reset(); // Clear pad arrays
+ return finalDigest;
+ }
+
+ /**
+ * Resets the digest for further use.
+ */
+ public void reset() {
+ int i;
+
+ mMD.reset();
+
+ // Clear out the pads
+ for (i = 0; i < PAD_BYTES; i++) {
+ mKeyIpad[i] = 0;
+ mKeyOpad[i] = 0;
+ }
+ }
+
+ /**
+ * Clone the HMACDigest
+ *
+ * @return a clone if the implementation is cloneable.
+ * @exception CloneNotSupportedException if this is called on a
+ * MessageDigest implementation that does not support <code>Cloneable</code>.
+ */
+ public Object clone() throws CloneNotSupportedException {
+ int i;
+
+ HMACDigest hd = (HMACDigest) super.clone();
+
+ hd.mKeyOpad = new byte[PAD_BYTES];
+ hd.mKeyIpad = new byte[PAD_BYTES];
+
+ for (i = 0; i < PAD_BYTES; i++) {
+ hd.mKeyOpad[i] = mKeyOpad[i];
+ hd.mKeyIpad[i] = mKeyIpad[i];
+ }
+
+ hd.mMD = (MessageDigest) mMD.clone();
+ return hd;
+ }
+
+}