Back to Contents


Compute a hash value from a 4GL string


Overview

This document explains how to compute a hash value of a 4GL string using the xml.signature API.

Actually, signing a XML document is nothing more than compute a hash over a fragment of XML, so if you set the string you need to hash in an XML node, and use the right XPath expression, the signature API will do it for you.

Notice however that some special characters are escaped in XML, therefore if you use one of them, the computed hash value will be wrong because the result is actually computed over the escaped string. The string to take care are : ", ', &, < and >.

Back to the top


4GL sample code

This program creates a simple XML document with the string to hash as text of the root node called ROOT.
Then uses the xml.signature API to compute a XML digital signature for the content of the root node, or in other words the string you wish to hash, using a XPath expression.
And finally, retrieves the hash value from the signature and returns it.
Notice that the computed hash value is encoded in Base64, so you may have additional conversion to do.

IMPORT XML

MAIN
  DEFINE result STRING
  IF num_args()!=2 THEN
    DISPLAY "Usage: ComputeHash <string> <hashcode>"    
    DISPLAY "  string: the string to hash"
    DISPLAY "  hashcode: SHA-1,SHA-512,SHA-384,SHA-256,SHA-224,MD5,RIPEMD160"
  ELSE
    LET result = ComputeHash(arg_val(1),arg_val(2))
    IF result IS NOT NULL THEN
      DISPLAY "Hash value is :",result
    ELSE
      DISPLAY "Error"
    END IF
  END IF
END MAIN

#
# Computes the hash value of the string 'str'
# according to the kind of hash 'hashcode'
# The returned hash value is encoded Base64
#
FUNCTION ComputeHash(str,hashcode)
  DEFINE str      STRING
  DEFINE hashcode STRING
  DEFINE doc      xml.DomDocument
  DEFINE node     xml.DomNode
  DEFINE txt      xml.DomNode
  DEFINE sign     xml.Signature
  DEFINE key      xml.CryptoKey
  DEFINE list     xml.DomNodeList
  DEFINE hashURL  STRING
  DEFINE index    INTEGER
  # Retrieve HASH URL from the hashcode
  CASE hashcode
    WHEN "SHA-1"
      LET hashURL = "http://www.w3.org/2000/09/xmldsig#sha1"
    WHEN "SHA-512"
      LET hashURL = "http://www.w3.org/2001/04/xmlenc#sha512"
    WHEN "SHA-384"
      LET hashURL = "http://www.w3.org/2001/04/xmldsig-more#sha384"
    WHEN "SHA-256"
      LET hashURL = "http://www.w3.org/2001/04/xmlenc#sha256"
    WHEN "SHA-224"
      LET hashURL = "http://www.w3.org/2001/04/xmldsig-more#sha224"
    WHEN "MD5"
      LET hashURL = "http://www.w3.org/2001/04/xmldsig-more#md5"
    WHEN "RIPEMD160"
      LET hashURL = "http://www.w3.org/2001/04/xmlenc#ripemd160"
    OTHERWISE
      RETURN NULL      
  END CASE
  # Create a XML document containing the string to hash
  LET doc = xml.DomDocument.CreateDocument("ROOT")
  LET node = doc.getDocumentElement()
  LET txt = doc.createTextNode(str)
  CALL node.appendChild(txt)
  # Create a HMAC key (notice that the password is not important)
  LET key = xml.CryptoKey.Create("http://www.w3.org/2000/09/xmldsig#hmac-sha1")
  CALL key.setKey("secretpassword")
  # Create XML signature
  LET sign = xml.Signature.Create()
  CALL sign.setKey(key)
  # Create Reference to sign and to hash
  LET index = sign.createReference(NULL,hashURL)
  CALL sign.appendReferenceTransformation(index, "http://www.w3.org/2002/06/xmldsig-filter2", "intersect", "//ROOT/text()")
  # Compute detached signature
  CALL sign.compute(doc)
  # Retrieve signature document
  LET doc=sign.getDocument()
  # Get the hash value
  LET list = doc.selectByXPath("//dsig:DigestValue/text()","dsig","http://www.w3.org/2000/09/xmldsig#")
  IF list.getCount() = 0 THEN     
    RETURN NULL # ERROR
  ELSE
    LET node = list.getItem(1)
    RETURN node.getNodeValue()
  END IF
END FUNCTION

Example of usage:

$ fglrun ComputeHash "Hello, world !!!" MD5
$ Hash value is :sENZtise4b7kRHz42jSA0Q==

Back to the top