4 Replies Latest reply: Mar 7, 2012 2:23 AM by jortri RSS

    MD5. DBMS_CRYPTO.Hash vs java.security.MessageDigest

    jortri
      Hi,
      I have xml in CLOB column.
      I want to get MD5 with DBMS_CRYPTO.Hash:
      (Oracle Database 10g Enterprise Edition Release 10.2.0.5.0)
      SET SERVEROUTPUT ON
      DECLARE
      
        vXml_ CLOB;
        tam NUMBER;
      
        l_hash   raw(2000);
        l_hashCa   varchar2(2000);
      
      BEGIN
      
        SELECT COL, dbms_lob.getlength(COL) AS TAMA
        INTO vXml_, tam
        FROM BORRAME 
        WHERE ID = 1;
      
        l_hash := DBMS_CRYPTO.Hash (
           vXml_,
           DBMS_CRYPTO.HASH_MD5);
      
        l_hashCa := lower(rawtohex(l_hash));
      
        dbms_output.put_line('Size: ' || tam);
        dbms_output.put_line('Hash: ' || l_hash);
        dbms_output.put_line('Hash-1: ' || l_hashCa);
      
      END;
      /
      Size: 9902
      Hash: 36D0C059092B450C0598EBFECC015FF5
      Hash-1: 36d0c059092b450c0598ebfecc015ff5
      I need get same MD5 with java.security.MessageDigest.
      Create
      SET def off
      create or replace java source named "MD5" as 
      import java.security.MessageDigest;
      import java.security.NoSuchAlgorithmException;
      import java.sql.Clob;
      import java.sql.Blob;
       
      public class MD5 {
        public static String getMD5HashFromClob(Clob inhalt) throws Exception{
      
          MessageDigest algorithm;
          StringBuffer hexString;
          String s;
          String salida = null;
          int i;
          byte[] digest;
      
          String tepFordigest = inhalt.getSubString(1L, (int)inhalt.length());
      
          try {
              algorithm = MessageDigest.getInstance("MD5");
              algorithm.reset();
              algorithm.update(tepFordigest.getBytes());
      
              digest = algorithm.digest();
      
              hexString = new StringBuffer();
              for (i = 0; i < digest.length; i++) {
                  s = "0" + Integer.toHexString(0xFF & digest);
      hexString.append(s.substring(s.length() - 2));
      }

      salida = hexString.toString();
      } catch (java.security.NoSuchAlgorithmException nsae) {
      salida = "No es posible cifrar MD5";
      }
      return salida;

      }
      }
      /
      sho err



      alter java source "MD5" compile
      /
      sho err

      CREATE OR REPLACE FUNCTION get_md5_CLOB(inhalt CLOB) RETURN VARCHAR2 DETERMINISTIC
      AS LANGUAGE JAVA
      name 'MD5.getMD5HashFromClob(java.sql.Clob) return java.lang.String';
      /
      Now, i use:
      SET SERVEROUTPUT ON
      DECLARE

      vXml_ CLOB;
      tam NUMBER;

      l_hash raw(2000);
      l_hashCa varchar2(2000);

      BEGIN

      SELECT COL, dbms_lob.getlength(COL) AS TAMA
      INTO vXml_, tam
      FROM BORRAME
      WHERE ID = 1;

      l_hash := get_md5_CLOB (vXml_);

      l_hashCa := lower(rawtohex(l_hash));

      dbms_output.put_line('Size: ' || tam);
      dbms_output.put_line('Hash: ' || l_hash);
      dbms_output.put_line('Hash-1: ' || l_hashCa);

      END;
      /
      Size: 9902
      Hash: 77E252BC18244BEDDE13072BC3918DBF
      Hash-1: 77e252bc18244bedde13072bc3918dbf
      Why are they different???:
      36d0c059092b450c0598ebfecc015ff5
      77e252bc18244bedde13072bc3918dbf                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
        • 1. Re: MD5. DBMS_CRYPTO.Hash vs java.security.MessageDigest
          rp0428
          >
          Why are they different???:
          >
          Either the CLOB being used by Java is different or your conversion code to create the string from the byte array is giving wrong results. The MD5 Java functionality produces the correct results and I have been using it for over 10 years.

          Are you sure your conversion code is correct? This is what I use to do these conversions and I know they produce correct results.
              private static final byte [] hexDigit = {
               '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
              };
          
              /** Converts a byte array to a hex string
               *  Returns an empty string if the byte array is null
               */
              public static final String toHexString(byte [] bytes) {
                  if (bytes == null) return new String("");
                  StringBuffer buf = new StringBuffer(bytes.length * 2);
                  for (int i = 0; i < bytes.length; i++) {
                      buf.append((char) hexDigit[((bytes[i] >>> 4) & 0x0F)]);
                      buf.append((char) hexDigit[(bytes[i] & 0x0F)]);
                  }
                  return buf.toString();
              }
          
          // Convert Hex String to Byte Array
          
              public static final byte[] byteArrayFromHexString(String str) {
                  byte[] bytes = new byte[str.length() / 2];
                  for (int i = 0; i < bytes.length; i++)
                  {
                      bytes[i] = (byte) Integer.parseInt(str.substring(2 * i, 2 * i + 2), 16);
                  }
                  return bytes;
              }
          Modify your code to add a call to my 'toHexString' function passing in your 'digest' byte array. Compare the results of the string I return to 'salida' and post the results.
          • 2. Re: MD5. DBMS_CRYPTO.Hash vs java.security.MessageDigest
            jortri
            Hi,
            Thanks for your answer.

            CLOB is the same. Table "BORRAME" has not been touched.

            Change MD5:
            SET def off
            create or replace java source named "MD5" as 
            import java.security.MessageDigest;
            import java.security.NoSuchAlgorithmException;
            import java.sql.Clob;
            import java.sql.Blob;
             
            public class MD5 {
            
            private static final byte [] hexDigit = {
                 '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
                };
            
                /** Converts a byte array to a hex string
                 *  Returns an empty string if the byte array is null
                 */
                public static final String toHexString(byte [] bytes) {
                    if (bytes == null) return new String("");
                    StringBuffer buf = new StringBuffer(bytes.length * 2);
                    for (int i = 0; i < bytes.length; i++) {
                        buf.append((char) hexDigit[((bytes[i] >>> 4) & 0x0F)]);
                        buf.append((char) hexDigit[(bytes[i] & 0x0F)]);
                    }
                    return buf.toString();
                }
             
            // Convert Hex String to Byte Array
             
                public static final byte[] byteArrayFromHexString(String str) {
                    byte[] bytes = new byte[str.length() / 2];
                    for (int i = 0; i < bytes.length; i++)
                    {
                        bytes[i] = (byte) Integer.parseInt(str.substring(2 * i, 2 * i + 2), 16);
                    }
                    return bytes;
                }
            
              public static String getMD5HashFromClob(Clob inhalt) throws Exception{
            
                MessageDigest algorithm;
                StringBuffer hexString;
                String s = null;
                String salida = null;
                int i;
                byte[] digest;
            
                String tepFordigest = inhalt.getSubString(1L, (int)inhalt.length());
            
                try {
                    algorithm = MessageDigest.getInstance("MD5");
                    algorithm.reset();
                    algorithm.update(tepFordigest.getBytes());
            
                    digest = algorithm.digest();
            
                    s = toHexString(digest);
            
                } catch (java.security.NoSuchAlgorithmException nsae) {
                    s = "No es posible cifrar MD5";
                }
                return s;
            
              } 
            }
            /
            sho err
            Now:
            SQL>DECLARE
              2  
              3    vXml_ CLOB;
              4    tam NUMBER;
              5  
              6    l_hash   raw(2000);
              7    l_hashCa   varchar2(2000);
              8  
              9  BEGIN
             10  
             11    SELECT COL, dbms_lob.getlength(COL) AS TAMA
             12    INTO vXml_, tam
             13    FROM BORRAME 
             14    WHERE ID = 1;
             15  
             16    l_hash := get_md5_CLOB (vXml_);
             17  
             18    l_hashCa := lower(rawtohex(l_hash));
             19  
             20    dbms_output.put_line('Size: ' || tam);
             21    dbms_output.put_line('Hash: ' || l_hash);
             22    dbms_output.put_line('Hash-1: ' || l_hashCa);
             23  
             24  END;
             25  /
            Size: 9902
            Hash: 77E252BC18244BEDDE13072BC3918DBF
            Hash-1: 77e252bc18244bedde13072bc3918dbf
            Result don't change.
            Different to "DBMS_CRYPTO.Hash"!!!!
            SQL>DECLARE
              2  
              3    vXml_ CLOB;
              4    tam NUMBER;
              5  
              6    l_hash   raw(2000);
              7    l_hashCa   varchar2(2000);
              8  
              9  BEGIN
             10  
             11    SELECT COL, dbms_lob.getlength(COL) AS TAMA
             12    INTO vXml_, tam
             13    FROM BORRAME 
             14    WHERE ID = 1;
             15  
             16    l_hash := DBMS_CRYPTO.Hash (
             17       vXml_,
             18       DBMS_CRYPTO.HASH_MD5);
             19  
             20    l_hashCa := lower(rawtohex(l_hash));
             21  
             22    dbms_output.put_line('Size: ' || tam);
             23    dbms_output.put_line('Hash: ' || l_hash);
             24    dbms_output.put_line('Hash-1: ' || l_hashCa);
             25  
             26  END;
             27  /
            Size: 9902
            Hash: 36D0C059092B450C0598EBFECC015FF5
            Hash-1: 36d0c059092b450c0598ebfecc015ff5
            Can you think of another mistake?

            Thanks.
            • 3. Re: MD5. DBMS_CRYPTO.Hash vs java.security.MessageDigest
              rp0428
              >
              Can you think of another mistake?
              >
              Not a mistake but the character set being used by Java (UTF-16) may be different. The Crypto package always converts everything to AL32UTF8 before hashing so if the Java character set is different the hash can be different.

              If you look at the spec header for the DBMS_CRYPTO package it shows this not:
              >
              -- Prior to encryption, hashing or keyed hashing, CLOB datatype is
              -- converted to AL32UTF8. This allows cryptographic data to be
              -- transferred and understood between databases with different
              -- character sets, across character set changes and between
              -- separate processes (for example, Java programs).
              --
              • 4. Re: MD5. DBMS_CRYPTO.Hash vs java.security.MessageDigest
                jortri
                Hi,
                Thanks for your answers.
                Very interesting... DBMS_CRYPTO.Hash always use AL32UTF8...

                I use in Java "getBytes" but parameter charset with "UTF-8": "algorithm.update(tepFordigest.getBytes("UTF-8")".
                SET def off
                create or replace java source named "MD5" as 
                import java.security.MessageDigest;
                import java.security.NoSuchAlgorithmException;
                import java.sql.Clob;
                import java.sql.Blob;
                 
                public class MD5 {
                
                private static final byte [] hexDigit = {
                     '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
                    };
                
                    /** Converts a byte array to a hex string
                     *  Returns an empty string if the byte array is null
                     */
                    public static final String toHexString(byte [] bytes) {
                        if (bytes == null) return new String("");
                        StringBuffer buf = new StringBuffer(bytes.length * 2);
                        for (int i = 0; i < bytes.length; i++) {
                            buf.append((char) hexDigit[((bytes[i] >>> 4) & 0x0F)]);
                            buf.append((char) hexDigit[(bytes[i] & 0x0F)]);
                        }
                        return buf.toString();
                    }
                 
                // Convert Hex String to Byte Array
                 
                    public static final byte[] byteArrayFromHexString(String str) {
                        byte[] bytes = new byte[str.length() / 2];
                        for (int i = 0; i < bytes.length; i++)
                        {
                            bytes[i] = (byte) Integer.parseInt(str.substring(2 * i, 2 * i + 2), 16);
                        }
                        return bytes;
                    }
                
                  public static String getMD5HashFromClob(Clob inhalt) throws Exception{
                
                    MessageDigest algorithm;
                    StringBuffer hexString;
                    String s = null;
                    String salida = null;
                    int i;
                    byte[] digest;
                
                    String tepFordigest = inhalt.getSubString(1L, (int)inhalt.length());
                
                    try {
                        algorithm = MessageDigest.getInstance("MD5");
                        algorithm.reset();
                        algorithm.update(tepFordigest.getBytes("UTF-8"));
                
                        digest = algorithm.digest();
                
                        s = toHexString(digest);
                
                    } catch (java.security.NoSuchAlgorithmException nsae) {
                        s = "No es posible cifrar MD5";
                    }
                    return s;
                
                  } 
                }
                /
                sho err
                Now, I execute:
                SET SERVEROUTPUT ON
                DECLARE
                
                  vXml_ CLOB;
                  tam NUMBER;
                
                  l_hash   raw(2000);
                  l_hashCa   varchar2(2000);
                
                BEGIN
                
                  SELECT COL, dbms_lob.getlength(COL) AS TAMA
                  INTO vXml_, tam
                  FROM BORRAME 
                  WHERE ID = 1;
                
                  l_hash := get_md5_CLOB (vXml_);
                
                  l_hashCa := lower(rawtohex(l_hash));
                
                  dbms_output.put_line('Size: ' || tam);
                  dbms_output.put_line('Hash: ' || l_hash);
                  dbms_output.put_line('Hash-1: ' || l_hashCa);
                
                END;
                /
                Size: 9902
                Hash: 36D0C059092B450C0598EBFECC015FF5
                Hash-1: 36d0c059092b450c0598ebfecc015ff5
                Yes!!
                Same hash!!

                Thanks