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 >.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==