package org.springframework.crypto.digest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; /** * @author Rob Harrop */ public class MessageDigestTemplate implements InitializingBean { private static final Log log = LogFactory.getLog(MessageDigestTemplate.class); private MessageDigest messageDigest; private boolean cloneable; public void setMessageDigest(MessageDigest messageDigest) { this.messageDigest = messageDigest; } public Object execute(MessageDigestCallback callback) { if (cloneable) { try { return executeWithClone(callback); } catch (CloneNotSupportedException ex) { log.warn("CloneNotSupportedException thrown for MessageDigest that supports clone(). " + "Executing under synchronization instead.", ex); return executeSynchronized(callback); } } else { return executeSynchronized(callback); } } protected Object executeWithClone(MessageDigestCallback callback) throws CloneNotSupportedException { MessageDigest md = (MessageDigest) messageDigest.clone(); return callback.doWithMessageDigest(md); } protected Object executeSynchronized(MessageDigestCallback callback) { synchronized (messageDigest) { messageDigest.reset(); return callback.doWithMessageDigest(messageDigest); } } public byte[] digest(final String data) { return digest(data.getBytes()); } public byte[] digest(final String data, final String encoding) { try { return digest(data.getBytes(encoding)); } catch (UnsupportedEncodingException ex) { throw new IllegalArgumentException("Invalid encoding [" + encoding + "]."); } } public byte[] digest(final byte[] data) { return (byte[])execute(new MessageDigestCallback() { public Object doWithMessageDigest(MessageDigest messageDigest) { messageDigest.update(data); return messageDigest.digest(); } }); } public byte[] digest(final byte[] data, final byte[] salt) { return (byte[])execute(new MessageDigestCallback() { public Object doWithMessageDigest(MessageDigest messageDigest) { messageDigest.update(salt); messageDigest.update(data); return messageDigest.digest(); } }); } public void afterPropertiesSet() throws Exception { if (messageDigest == null) { throw new IllegalArgumentException("Property [messageDigest] of class [" + MessageDigestTemplate.class + "] is required."); } this.cloneable = isCloneable(messageDigest); } private boolean isCloneable(MessageDigest messageDigest) { try { messageDigest.clone(); return true; } catch (CloneNotSupportedException ex) { return false; } } }