Author: sebb
Date: Thu May 19 11:33:20 2016
New Revision: 1744554

URL: http://svn.apache.org/viewvc?rev=1744554&view=rev
Log:
CODEC-222 Fluent interface for HmacUtils
Initial implementation

Modified:
    
commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/HmacUtils.java

Modified: 
commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/HmacUtils.java
URL: 
http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/HmacUtils.java?rev=1744554&r1=1744553&r2=1744554&view=diff
==============================================================================
--- 
commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/HmacUtils.java
 (original)
+++ 
commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/HmacUtils.java
 Thu May 19 11:33:20 2016
@@ -17,8 +17,12 @@
 
 package org.apache.commons.codec.digest;
 
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.ByteBuffer;
 import java.security.InvalidKeyException;
 import java.security.Key;
 import java.security.NoSuchAlgorithmException;
@@ -26,16 +30,32 @@ import java.security.NoSuchAlgorithmExce
 import javax.crypto.Mac;
 import javax.crypto.spec.SecretKeySpec;
 
+import org.apache.commons.codec.binary.Hex;
 import org.apache.commons.codec.binary.StringUtils;
 
 /**
  * Simplifies common {@link javax.crypto.Mac} tasks. This class is immutable 
and thread-safe.
- *
+ * However the Mac may not be.
  * <p>
- * <strong>Note: Not all JCE implementations supports all algorithms. If not 
supported, an IllegalArgumentException is
+ * <strong>Note: Not all JCE implementations support all algorithms. If not 
supported, an IllegalArgumentException is
  * thrown.</strong>
- * </p>
- *
+ * <p>
+ * Sample usage:
+ * <pre>
+ * byte[] key = {1,2,3,4}; // don't use this!
+ * String valueToDigest = "The quick brown fox jumps over the lazy dog";
+ * byte[] hmac = 
HmacUtils.use(HmacAlgorithms.HMAC_SHA_224).key(key).update(valueToDigest).doFinal();
+ * // Mac re-use
+ * HmacUtils hm1 = HmacUtils.use(HmacAlgorithms.HMAC_SHA_1).key(key);
+ * String hexPom = hm1.update(new File("pom.xml")).doFinalHex();
+ * String hexNot = hm1.update(new File("NOTICE.txt")).doFinalHex();
+ * // Mac key update
+ * String algo = "HmacNew";
+ * HmacUtils hm2 = HmacUtils.use(algo).key(key);
+ * byte[] key2 = {1,2,3,4,5}; // don't use this either!
+ * String hexPom2 = hm2.update(new File("pom.xml")).doFinalHex();
+ * String hexNot2 = hm2.key(key2).update(new File("NOTICE.txt")).doFinalHex();
+ * </pre>
  * @since 1.10
  * @version $Id$
  */
@@ -833,4 +853,198 @@ public final class HmacUtils {
         mac.update(StringUtils.getBytesUtf8(valueToDigest));
         return mac;
     }
+
+    HmacUtils() { // TODO why does test code try to instantiate this?
+        this(null);
+    }
+
+    // Fluent interface
+
+    private final Mac mac;
+
+    private HmacUtils(final Mac mac) {
+        this.mac = mac;
+    }
+
+
+    /**
+     * Creates an instance using the provided {@link Mac}
+     * If necessary, the
+     * key must be provided using the {@link #key(byte[])} method
+     * before it can be used further.
+     *
+     * @param algorithm to be used.
+     * @return the instance
+     * @since 1.11
+     */
+    public static HmacUtils use(final Mac mac) {
+        return new HmacUtils(mac);
+    }
+
+    /**
+     * Creates an instance using the provided algorithm type.
+     * The key must be provided using the {@link #key(byte[])} method
+     * before it can be used further.
+     *
+     * @param algorithm to be used.
+     * @return the instance
+     * @since 1.11
+     */
+    public static HmacUtils use(final String algorithm) {
+        try {
+            return new HmacUtils(Mac.getInstance(algorithm));
+        } catch (NoSuchAlgorithmException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    /**
+     * Creates an instance using the provided algorithm type.
+     * The key must be provided using the {@link #key(byte[])} method
+     * before it can be used further.
+     *
+     * @param algorithm to be used.
+     * @return the instance
+     * @since 1.11
+     */
+    public static HmacUtils use(final HmacAlgorithms algorithm) {
+        return use(algorithm.getName());
+    }
+
+    /**
+     * Updates the stored {@link Mac} with the new key.
+     * This resets the Mac ready for re-use.
+     *
+     * @param key the new key
+     * @return this instance
+     * @since 1.11
+     */
+    public HmacUtils key(byte[] key) {
+        final SecretKeySpec keySpec = new SecretKeySpec(key, 
mac.getAlgorithm());
+        try {
+            mac.init(keySpec);
+        } catch (InvalidKeyException e) {
+            throw new IllegalArgumentException(e);
+        }
+        return this;
+    }
+
+    /**
+     * Updates the stored {@link Mac} with the value.
+     *
+     * @param valueToDigest
+     *            the value to update the {@link Mac} with (maybe null or 
empty)
+     * @return the updated instance
+     * @throws IllegalStateException
+     *             if the Mac was not initialized
+     * @since 1.11
+     */
+    public HmacUtils update(final byte[] valueToDigest) {
+        mac.update(valueToDigest);
+        return this;
+    }
+    
+    /**
+     * Updates the stored {@link Mac} with the value.
+     *
+     * @param valueToDigest
+     *            the value to update the {@link Mac} with (maybe null or 
empty)
+     * @return the updated instance
+     * @throws IllegalStateException
+     *             if the Mac was not initialized
+     * @since 1.11
+     */
+    public HmacUtils update(final ByteBuffer valueToDigest) {
+        mac.update(valueToDigest);
+        return this;
+    }
+    
+    /**
+     * Updates the stored {@link Mac} with the value.
+     * String is converted to bytes using the UTF-8 charset.
+     * @param valueToDigest
+     *            the value to update the {@link Mac} with.
+     * @return the updated instance
+     * @throws IllegalStateException
+     *             if the Mac was not initialized
+     * @since 1.11
+     */
+    public HmacUtils update(final String valueToDigest) {
+        mac.update(StringUtils.getBytesUtf8(valueToDigest));
+        return this;
+    }
+    
+    /**
+     * Updates the stored {@link Mac} with the value.
+     *
+     * @param valueToDigest
+     *            the value to update the {@link Mac} with
+     *            <p>
+     *            The InputStream must not be null and will not be closed
+     *            </p>
+     * @return the updated instance
+     * @throws IOException
+     *             If an I/O error occurs.
+     * @throws IllegalStateException
+     *             If the Mac was not initialized
+     * @since 1.11
+     */
+    public HmacUtils update(final InputStream valueToDigest) throws 
IOException {
+        final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
+        int read;
+
+        while ((read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH) ) > 
-1) {
+            mac.update(buffer, 0, read);
+        }
+        return this;
+    }
+
+    /**
+     * Updates the stored {@link Mac} with the value.
+     *
+     * @param valueToDigest
+     *            the value to update the {@link Mac} with
+     *            <p>
+     *            The InputStream must not be null and will not be closed
+     *            </p>
+     * @return the updated instance
+     * @throws IOException
+     *             If an I/O error occurs.
+     * @throws IllegalStateException
+     *             If the Mac was not initialized
+     * @since 1.11
+     */
+    public HmacUtils update(final File valueToDigest) throws IOException {
+        final BufferedInputStream stream = new BufferedInputStream(new 
FileInputStream(valueToDigest));
+        try {
+            return update(stream);
+        } finally {
+            stream.close();
+        }
+    }
+
+    /**
+     * Finishes the MAC operation and returns the result.
+     * The Mac can be re-used to produce further results from the same key.
+     * Or the key can be reset and the Mac reused.
+     *
+     * @return the result as a byte array
+     * @since 1.11
+     */
+    public byte[] doFinal() {
+        return mac.doFinal();
+    }
+
+    /**
+     * Finishes the MAC operation and returns the result.
+     * The Mac can be re-used to produce further results from the same key.
+     * Or the key can be reset and the Mac reused.
+     *
+     * @return the result as a Hex String
+     * @since 1.11
+     */
+    public String doFinalHex() {
+        return Hex.encodeHexString(mac.doFinal());
+    }
+
 }


Reply via email to