From: <di...@us...> - 2009-01-03 16:03:48
|
Revision: 8464 http://exist.svn.sourceforge.net/exist/?rev=8464&view=rev Author: dizzzz Date: 2009-01-03 16:03:45 +0000 (Sat, 03 Jan 2009) Log Message: ----------- [feature] Added more generic util:hash() and deprecated md5() ; md5 is now officially EOL, this patch adds SHA-1, SHA-256 support (and more that is available in your JVM) Modified Paths: -------------- trunk/eXist/src/org/exist/http/servlets/DigestAuthenticator.java trunk/eXist/src/org/exist/security/User.java trunk/eXist/src/org/exist/storage/NativeBroker.java trunk/eXist/src/org/exist/xquery/functions/util/MD5.java trunk/eXist/src/org/exist/xquery/functions/util/UtilModule.java trunk/eXist/test/src/org/exist/xquery/XQueryTest.java trunk/eXist/webapp/docsetup.xql Added Paths: ----------- trunk/eXist/src/org/exist/security/MessageDigester.java trunk/eXist/src/org/exist/xquery/functions/util/Hash.java Removed Paths: ------------- trunk/eXist/src/org/exist/security/MD5.java Modified: trunk/eXist/src/org/exist/http/servlets/DigestAuthenticator.java =================================================================== --- trunk/eXist/src/org/exist/http/servlets/DigestAuthenticator.java 2009-01-03 10:26:53 UTC (rev 8463) +++ trunk/eXist/src/org/exist/http/servlets/DigestAuthenticator.java 2009-01-03 16:03:45 UTC (rev 8464) @@ -29,7 +29,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.exist.security.MD5; +import org.exist.security.MessageDigester; import org.exist.security.SecurityManager; import org.exist.security.User; import org.exist.storage.BrokerPool; @@ -77,12 +77,12 @@ "Digest realm=\"exist\", " + "nonce=\"" + createNonce(request) + "\", " + "domain=\"" + request.getContextPath() + "\", " + - "opaque=\"" + MD5.md(Integer.toString(hashCode(), 27),false) + '"'); + "opaque=\"" + MessageDigester.md5(Integer.toString(hashCode(), 27),false) + '"'); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); } private String createNonce(HttpServletRequest request) { - return MD5.md(request.getRemoteAddr() + ':' + + return MessageDigester.md5(request.getRemoteAddr() + ':' + Long.toString(System.currentTimeMillis()) + ':' + Integer.toString(hashCode()),false); } @@ -164,11 +164,11 @@ md.update((byte)':'); md.update(nonce.getBytes("ISO-8859-1")); md.update((byte)':'); - md.update(MD5.byteArrayToHex(ha2).getBytes("ISO-8859-1")); + md.update(MessageDigester.byteArrayToHex(ha2).getBytes("ISO-8859-1")); byte[] digest=md.digest(); // check digest - return (MD5.byteArrayToHex(digest).equalsIgnoreCase(response)); + return (MessageDigester.byteArrayToHex(digest).equalsIgnoreCase(response)); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("MD5 not supported"); } catch (UnsupportedEncodingException e) { Deleted: trunk/eXist/src/org/exist/security/MD5.java =================================================================== --- trunk/eXist/src/org/exist/security/MD5.java 2009-01-03 10:26:53 UTC (rev 8463) +++ trunk/eXist/src/org/exist/security/MD5.java 2009-01-03 16:03:45 UTC (rev 8464) @@ -1,77 +0,0 @@ - -package org.exist.security; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import org.apache.log4j.Logger; -import org.exist.util.Base64Encoder; - - -public class MD5 { - - private static String[] hex = {"0", "1", "2", "3", "4", "5", "6", "7", - "8", "9", "a", "b", "c", "d", "e", "f"}; - - private static final Logger LOG = Logger.getLogger(MD5.class); - - public static String md( String passwd, boolean base64) { - MessageDigest md5 = null; - String digest = passwd; - try { - md5 = MessageDigest.getInstance( "MD5" ); - md5.update( passwd.getBytes() ); - byte[] digestData = md5.digest(); - - if(base64) - { - Base64Encoder enc = new Base64Encoder(); - enc.translate(digestData); - digest = new String(enc.getCharArray()); - } - else - { - digest = byteArrayToHex( digestData ); - } - } catch ( NoSuchAlgorithmException e ) { - LOG.warn( "MD5 not supported. Using plain string as password!" ); - } catch ( Exception e ) { - LOG.warn( "Digest creation failed. Using plain string as password!" ); - } - return digest; - } - - - private static void byteToHex( StringBuffer buf, byte b ) { - int n = b; - if ( n < 0 ) { - n = 256 + n; - } - int d1 = n / 16; - int d2 = n % 16; - buf.append( hex[d1] ); - buf.append( hex[d2] ); - } - - - public static String byteArrayToHex( byte[] b ) { - StringBuffer buf = new StringBuffer( b.length * 2 ); - for ( int i = 0; i < b.length; i++ ) { - byteToHex( buf, b[i] ); - } - return buf.toString(); - } - - - /** - * The main program for the MD5 class - * - *@param args The command line arguments - */ - public static void main( String[] args ) { - System.out.println( "input: " + args[0] ); - System.out.println( "MD5: " + MD5.md( args[0], false ) ); - System.out.println( "MD5 (base64): " + MD5.md( args[0], true ) ); - } -} - Copied: trunk/eXist/src/org/exist/security/MessageDigester.java (from rev 8462, trunk/eXist/src/org/exist/security/MD5.java) =================================================================== --- trunk/eXist/src/org/exist/security/MessageDigester.java (rev 0) +++ trunk/eXist/src/org/exist/security/MessageDigester.java 2009-01-03 16:03:45 UTC (rev 8464) @@ -0,0 +1,111 @@ + +package org.exist.security; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.apache.log4j.Logger; +import org.exist.util.Base64Encoder; + + +public class MessageDigester { + + private static String[] hex = {"0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "a", "b", "c", "d", "e", "f"}; + + private static final Logger LOG = Logger.getLogger(MessageDigester.class); + + public static String md5( String message, boolean base64) { + MessageDigest md5 = null; + String digest = message; + try { + md5 = MessageDigest.getInstance( "MD5" ); + md5.update( message.getBytes() ); + byte[] digestData = md5.digest(); + + if(base64) + { + Base64Encoder enc = new Base64Encoder(); + enc.translate(digestData); + digest = new String(enc.getCharArray()); + } + else + { + digest = byteArrayToHex( digestData ); + } + } catch ( NoSuchAlgorithmException e ) { + LOG.warn( "MD5 not supported. Using plain string as password!" ); + } catch ( Exception e ) { + LOG.warn( "Digest creation failed. Using plain string as password!" ); + } + return digest; + } + + public static String calculate(String message, String algorithm, boolean base64) + throws IllegalArgumentException { + + // Can throw a NoSuchAlgorithmException + MessageDigest md = null; + try { + md = MessageDigest.getInstance(algorithm); + + } catch (NoSuchAlgorithmException e) { + String error = "'"+ algorithm + "' is not a supported MessageDigest algorithm."; + LOG.error(error, e); + throw new IllegalArgumentException(error); + } + + + // Calculate hash + md.update( message.getBytes() ); + byte[] digestData = md.digest(); + + // Write digest as string + String digest = null; + if(base64) + { + Base64Encoder enc = new Base64Encoder(); + enc.translate(digestData); + digest = new String(enc.getCharArray()); + + } else { + digest = byteArrayToHex( digestData ); + } + + return digest; + } + + + private static void byteToHex( StringBuffer buf, byte b ) { + int n = b; + if ( n < 0 ) { + n = 256 + n; + } + int d1 = n / 16; + int d2 = n % 16; + buf.append( hex[d1] ); + buf.append( hex[d2] ); + } + + + public static String byteArrayToHex( byte[] b ) { + StringBuffer buf = new StringBuffer( b.length * 2 ); + for ( int i = 0; i < b.length; i++ ) { + byteToHex( buf, b[i] ); + } + return buf.toString(); + } + + + /** + * The main program for the MD5 class + * + *@param args The command line arguments + */ + public static void main( String[] args ) { + System.out.println( "input: " + args[0] ); + System.out.println( "MD5: " + MessageDigester.md5( args[0], false ) ); + System.out.println( "MD5 (base64): " + MessageDigester.md5( args[0], true ) ); + } +} + Property changes on: trunk/eXist/src/org/exist/security/MessageDigester.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Modified: trunk/eXist/src/org/exist/security/User.java =================================================================== --- trunk/eXist/src/org/exist/security/User.java 2009-01-03 10:26:53 UTC (rev 8463) +++ trunk/eXist/src/org/exist/security/User.java 2009-01-03 16:03:45 UTC (rev 8464) @@ -323,7 +323,7 @@ this.password = null; this.digestPassword = null; } else { - this.password = MD5.md(passwd,true); + this.password = MessageDigester.md5(passwd,true); this.digestPassword = digest(passwd); } } @@ -352,9 +352,9 @@ case PLAIN_ENCODING: return passwd; case MD5_ENCODING: - return MD5.md(user + ":"+realm+":" + passwd,false); + return MessageDigester.md5(user + ":"+realm+":" + passwd,false); default: - return MD5.md(passwd,true); + return MessageDigester.md5(passwd,true); } } @@ -439,7 +439,7 @@ } if (password!=null) { - if (MD5.md(passwd,true).equals( password )) { + if (MessageDigester.md5(passwd,true).equals( password )) { return true; } } Modified: trunk/eXist/src/org/exist/storage/NativeBroker.java =================================================================== --- trunk/eXist/src/org/exist/storage/NativeBroker.java 2009-01-03 10:26:53 UTC (rev 8463) +++ trunk/eXist/src/org/exist/storage/NativeBroker.java 2009-01-03 16:03:45 UTC (rev 8464) @@ -34,11 +34,8 @@ import org.exist.indexing.StreamListener; import org.exist.memtree.DOMIndexer; import org.exist.numbering.NodeId; -import org.exist.security.MD5; -import org.exist.security.Permission; -import org.exist.security.PermissionDeniedException; +import org.exist.security.*; import org.exist.security.SecurityManager; -import org.exist.security.User; import org.exist.stax.EmbeddedXMLStreamReader; import org.exist.storage.btree.BTree; import org.exist.storage.btree.BTreeCallback; @@ -1443,7 +1440,7 @@ Txn transaction = transact.beginTransaction(); //create a name for the temporary document - XmldbURI docName = XmldbURI.create(MD5.md(Thread.currentThread().getName() + Long.toString(System.currentTimeMillis()),false) + ".xml"); + XmldbURI docName = XmldbURI.create(MessageDigester.md5(Thread.currentThread().getName() + Long.toString(System.currentTimeMillis()),false) + ".xml"); //get the temp collection Collection temp = openCollection(XmldbURI.TEMP_COLLECTION_URI, Lock.WRITE_LOCK); Added: trunk/eXist/src/org/exist/xquery/functions/util/Hash.java =================================================================== --- trunk/eXist/src/org/exist/xquery/functions/util/Hash.java (rev 0) +++ trunk/eXist/src/org/exist/xquery/functions/util/Hash.java 2009-01-03 16:03:45 UTC (rev 8464) @@ -0,0 +1,95 @@ +/* + * eXist Open Source Native XML Database + * Copyright (C) 2001-09 Wolfgang M. Meier + * wol...@ex... + * http://exist.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ +package org.exist.xquery.functions.util; + +import org.exist.dom.QName; +import org.exist.xquery.Cardinality; +import org.exist.xquery.BasicFunction; +import org.exist.xquery.FunctionSignature; +import org.exist.xquery.XPathException; +import org.exist.xquery.XQueryContext; +import org.exist.xquery.value.Sequence; +import org.exist.xquery.value.SequenceType; +import org.exist.xquery.value.StringValue; +import org.exist.xquery.value.Type; +import org.exist.security.MessageDigester; + +import java.security.NoSuchAlgorithmException; + +/** + * Generate a massage digest (hashcode) from a string. Typically supported + * algorithms are MD5 and SHA1. + * + * @author di...@ex... + */ +public class Hash extends BasicFunction { + public final static FunctionSignature signatures[] = { + new FunctionSignature( + new QName("hash", UtilModule.NAMESPACE_URI, UtilModule.PREFIX), + "Calculate an hashcode from string $a using alghorithm $b.", + new SequenceType[]{ + new SequenceType(Type.ITEM, Cardinality.EXACTLY_ONE), + new SequenceType(Type.STRING, Cardinality.EXACTLY_ONE), + }, + new SequenceType(Type.STRING, Cardinality.EXACTLY_ONE)), + + new FunctionSignature( + new QName("hash", UtilModule.NAMESPACE_URI, UtilModule.PREFIX), + "Calculate an hashcode from string $a using alghorithm $b. $c specifies whether to return result Base64 encoded", + new SequenceType[]{ + new SequenceType(Type.ITEM, Cardinality.EXACTLY_ONE), + new SequenceType(Type.STRING, Cardinality.EXACTLY_ONE), + new SequenceType(Type.BOOLEAN, Cardinality.EXACTLY_ONE) + }, + new SequenceType(Type.STRING, Cardinality.EXACTLY_ONE)) + }; + + public Hash(XQueryContext context, FunctionSignature signature) { + super(context, signature); + } + + /* (non-Javadoc) + * @see org.exist.xquery.Expression#eval(org.exist.dom.DocumentSet, org.exist.xquery.value.Sequence, org.exist.xquery.value.Item) + */ + public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException { + boolean base64 = false; + + String message = args[0].itemAt(0).getStringValue(); + String algorithm = args[1].itemAt(0).getStringValue(); + + if (args.length > 2) { + base64 = args[2].effectiveBooleanValue(); + } + + String md = null; + try { + md = MessageDigester.calculate(message, algorithm, base64); + + } catch (IllegalArgumentException ex) { + throw new XPathException(ex.getMessage()); + } + + return (new StringValue(md)); + } + +} Property changes on: trunk/eXist/src/org/exist/xquery/functions/util/Hash.java ___________________________________________________________________ Added: svn:keywords + Id Modified: trunk/eXist/src/org/exist/xquery/functions/util/MD5.java =================================================================== --- trunk/eXist/src/org/exist/xquery/functions/util/MD5.java 2009-01-03 10:26:53 UTC (rev 8463) +++ trunk/eXist/src/org/exist/xquery/functions/util/MD5.java 2009-01-03 16:03:45 UTC (rev 8464) @@ -28,11 +28,11 @@ import org.exist.xquery.FunctionSignature; import org.exist.xquery.XPathException; import org.exist.xquery.XQueryContext; -import org.exist.xquery.value.Item; import org.exist.xquery.value.Sequence; import org.exist.xquery.value.SequenceType; import org.exist.xquery.value.StringValue; import org.exist.xquery.value.Type; +import org.exist.security.MessageDigester; /** * Generate an MD5 key from a string. @@ -41,14 +41,16 @@ */ public class MD5 extends BasicFunction { - public final static FunctionSignature signatures[] = { + public final static FunctionSignature deprecated[] = { new FunctionSignature( new QName( "md5", UtilModule.NAMESPACE_URI, UtilModule.PREFIX ), "Generates an MD5 key from a string.", new SequenceType[] { new SequenceType( Type.ITEM, Cardinality.EXACTLY_ONE ), }, - new SequenceType( Type.STRING, Cardinality.EXACTLY_ONE ) ), + new SequenceType( Type.STRING, Cardinality.EXACTLY_ONE ), + "Use the hash($a, \"MD5\") function instead. SHA-1 is supported as " + + "more secure message digest algorithm."), new FunctionSignature( new QName( "md5", UtilModule.NAMESPACE_URI, UtilModule.PREFIX ), @@ -57,7 +59,9 @@ new SequenceType( Type.ITEM, Cardinality.EXACTLY_ONE ), new SequenceType( Type.BOOLEAN, Cardinality.EXACTLY_ONE ) }, - new SequenceType( Type.STRING, Cardinality.EXACTLY_ONE ) ) + new SequenceType( Type.STRING, Cardinality.EXACTLY_ONE ), + "Use the hash($a, \"MD5\") function instead. SHA-1 is supported as " + + "more secure message digest algorithm.") }; public MD5( XQueryContext context , FunctionSignature signature ) @@ -78,7 +82,7 @@ base64 = args[1].effectiveBooleanValue(); } - String md = org.exist.security.MD5.md( arg, base64 ); + String md = MessageDigester.md5( arg, base64 ); return( new StringValue( md ) ); } Modified: trunk/eXist/src/org/exist/xquery/functions/util/UtilModule.java =================================================================== --- trunk/eXist/src/org/exist/xquery/functions/util/UtilModule.java 2009-01-03 10:26:53 UTC (rev 8463) +++ trunk/eXist/src/org/exist/xquery/functions/util/UtilModule.java 2009-01-03 16:03:45 UTC (rev 8464) @@ -54,8 +54,6 @@ new FunctionDef(Eval.signatures[3], Eval.class), new FunctionDef(Eval.signatures[4], Eval.class), new FunctionDef(Compile.signature, Compile.class), - new FunctionDef(MD5.signatures[0], MD5.class), - new FunctionDef(MD5.signatures[1], MD5.class), new FunctionDef(DocumentNameOrId.docIdSignature, DocumentNameOrId.class), new FunctionDef(DocumentNameOrId.docNameSignature, DocumentNameOrId.class), new FunctionDef(CollectionName.signature, CollectionName.class), @@ -104,11 +102,15 @@ new FunctionDef(Parse.signatures[1], Parse.class), new FunctionDef(ExtractDocs.signature, ExtractDocs.class), new FunctionDef(NodeXPath.signature, NodeXPath.class), + new FunctionDef(Hash.signatures[0], Hash.class), + new FunctionDef(Hash.signatures[1], Hash.class), // deprecated functions new FunctionDef(GetVersion.deprecated, GetVersion.class), new FunctionDef(FileRead.deprecated[0], FileRead.class), new FunctionDef(FileRead.deprecated[1], FileRead.class), + new FunctionDef(MD5.deprecated[0], MD5.class), + new FunctionDef(MD5.deprecated[1], MD5.class), }; static { Modified: trunk/eXist/test/src/org/exist/xquery/XQueryTest.java =================================================================== --- trunk/eXist/test/src/org/exist/xquery/XQueryTest.java 2009-01-03 10:26:53 UTC (rev 8463) +++ trunk/eXist/test/src/org/exist/xquery/XQueryTest.java 2009-01-03 16:03:45 UTC (rev 8464) @@ -3033,6 +3033,73 @@ } + public void testMessageDigester() { + + try { + String query = "let $value:=\"ABCDEF\"\n" + + "let $alg:=\"MD5\"\n" + + "return\n" + + "(util:hash($value, $alg), util:hash($value, $alg, xs:boolean('true')))"; + + XPathQueryService service = (XPathQueryService) getTestCollection().getService("XPathQueryService", "1.0"); + ResourceSet result = service.query(query); + + assertEquals(2, result.getSize()); + assertEquals(query, "8827a41122a5028b9808c7bf84b9fcf6", + result.getResource(0).getContent().toString()); + assertEquals(query, "iCekESKlAouYCMe/hLn89g==", + result.getResource(1).getContent().toString()); + + + } catch (XMLDBException ex) { + ex.printStackTrace(); + fail(ex.toString()); + } + + try { + String query = "let $value:=\"ABCDEF\"\n" + + "let $alg:=\"SHA-1\"\n" + + "return\n" + + "(util:hash($value, $alg), util:hash($value, $alg, xs:boolean('true')))"; + + XPathQueryService service = (XPathQueryService) getTestCollection().getService("XPathQueryService", "1.0"); + ResourceSet result = service.query(query); + + assertEquals(2, result.getSize()); + assertEquals(query, "970093678b182127f60bb51b8af2c94d539eca3a", + result.getResource(0).getContent().toString()); + assertEquals(query, "lwCTZ4sYISf2C7UbivLJTVOeyjo=", + result.getResource(1).getContent().toString()); + + + } catch (XMLDBException ex) { + ex.printStackTrace(); + fail(ex.toString()); + } + + try { + String query = "let $value:=\"ABCDEF\"\n" + + "let $alg:=\"SHA-256\"\n" + + "return\n" + + "(util:hash($value, $alg), util:hash($value, $alg, xs:boolean('true')))"; + + XPathQueryService service = (XPathQueryService) getTestCollection().getService("XPathQueryService", "1.0"); + ResourceSet result = service.query(query); + + assertEquals(2, result.getSize()); + assertEquals(query, "e9c0f8b575cbfcb42ab3b78ecc87efa3b011d9a5d10b09fa4e96f240bf6a82f5", + result.getResource(0).getContent().toString()); + assertEquals(query, "6cD4tXXL/LQqs7eOzIfvo7AR2aXRCwn6TpbyQL9qgvU=", + result.getResource(1).getContent().toString()); + + + } catch (XMLDBException ex) { + ex.printStackTrace(); + fail(ex.toString()); + } + } + + // ====================================== /** * @return Modified: trunk/eXist/webapp/docsetup.xql =================================================================== --- trunk/eXist/webapp/docsetup.xql 2009-01-03 10:26:53 UTC (rev 8463) +++ trunk/eXist/webapp/docsetup.xql 2009-01-03 16:03:45 UTC (rev 8464) @@ -31,7 +31,7 @@ declare function setup:load-fundocs() { for $moduleURI in util:registered-modules() let $moduleDocs := util:extract-docs($moduleURI) - let $docName := concat(util:md5($moduleURI), ".xml") + let $docName := concat(util:hash($moduleURI, "MD5"), ".xml") return ( xdb:store($setup:COLLECTION, $docName, $moduleDocs, "text/xml"), xdb:chmod-resource($setup:COLLECTION, $docName, 508) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |