You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@santuario.apache.org by Christian Geuer-Pollmann <ge...@nue.et-inf.uni-siegen.de> on 2002/09/26 10:48:27 UTC

Re: Just getting the hash


--On Monday, September 23, 2002 11:25 AM -0700 Michael Halcrow 
<ma...@email.byu.edu> wrote:

> What is the most efficient way to just get the digest of an XML
> document? I would also like to know how to get the digest of the result
> of a set of transforms (i.e., XPath filtered set of nodes).

Hm, not sure what you mean:

----------------------------------------------

(1) If you have an XML Document (i.e. a file on your disk), you simply get 
the octets and pipe them into the digest. But I guess that's not what you 
wanted.

----------------------------------------------

(2) If you have an XML Document (i.e. a file on your disk) and you want the 
digest of the canonical form, simply read the File into a byte[] array and 
send these byte[]s to the Canonicalizer:

org.apache.xml.security.Init.init();
Canonicalizer c14n = Canonicalizer.getInstance(
      Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS);
// read in XML file
byte[] octetsFromInstance = ...;
byte[] octetsToDigest = c14n.canonicalize(octetsFromInstance);
// now simply digest octetsToDigest

----------------------------------------------

(3) If you talk about Transforms (or filtered node sets), you don't have a 
document but a document subset. In that case, the Reference object does 
what you need: de-referencing the document, applying Transforms and 
calculating the digest. Reference is *not* intended to be used without a 
surrounding container (that's why all constructors are protected). But you 
can create a Manifest (which is essentially a collection of References).

Manifest manifest = new Manifest(doc);
doc.appendChild(manifest.getElement());
Transforms transforms = new Transforms(doc);
// transforms.addTransform(....);
manifest.addDocument(
    "./whereDoIStoreTheManifest.xml",
    "xmlInQuestion.xml",
    transforms,
    MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA1,
    null, null);
manifest.generateDigestValues();
// serialize doc to whereDoIStoreTheManifest.xml
// inside that file, the digest of the transformed xmlInQuestion.xml resides

----------------------------------------------

Regards,
Christian

Re: Just getting the hash

Posted by Christian Geuer-Pollmann <ge...@nue.et-inf.uni-siegen.de>.
Hi Michael,

now I understand the problem. First of all, you don't have to mess around 
in the output to get the digest. This is OOP ;-)) Simply fetch it from the 
signature *object*.

Simply? Sorry, Reference does not have a getDigestValue() method. I forgot 
it ;-)) I've added one in CVS now. So you must use a trick till 1.0.5 is 
released:

Element digestValueElem =
  sig.getSignedInfo().item(0).getChildElementLocalName(0,
          Constants.SignatureSpecNS,
          Constants._TAG_DIGESTVALUE);
byte[] elemDig = Base64.decode(digestValueElem);

In the above code, you take the 1st Reference [sig.getSignedInfo().item(0)] 
and get the DigestValue element out of it. Then simply decode and that's 
it.

BTW, your code has a bug ;-)) If you say sig.addDocument("", ...) and hope 
that you get comments because you use TRANSFORM_C14N_WITH_COMMENTS, then 
your wrong. URI="" trims all comments out of the input. Use 
URI="#xpointer(/)" instead if you need comments.

And -- you don't need the OfflineResolver. This is *ONLY* for the test 
vectors.

I attached the java sample which runs out of the box.

Regards,
Christian

BTW, the program outputs this:

# The document ##########
<docElement><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod 
Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:Canonicali
zationMethod>
<ds:SignatureMethod 
Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"></ds:SignatureMetho
d>
<ds:Reference URI="#xpointer(/)">
<ds:Transforms>
<ds:Transform 
Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Tran
sform>
<ds:Transform 
Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"></
ds:Transform>
</ds:Transforms>
<ds:DigestMethod 
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>BZl3yisN3tsmsNoRw3u/SHictZU=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>vzoZqD8ImNq8650sh5gdO23MQSk=</ds:SignatureValue>
<ds:KeyInfo>
<ds:KeyName>The secret passphrase for the MAC is 
"secret".getBytes()</ds:KeyName>
</ds:KeyInfo>
</ds:Signature></docElement>

# The signed part #######

<docElement></docElement>
<!-- some comment -->

# The digest (hex) ######

05 99 77 CA 2B 0D DE DB 26 B0 DA 11 C3 7B BF 48 78 9C B5 95

#########################

Re: Just getting the hash

Posted by Michael Halcrow <ma...@email.byu.edu>.
Thanks, Christian. This helped me understand a little better how the
tools work. I have a question about this hash.

If I perform an enveloped signature on the root document:

XMLSignature sig = new XMLSignature( doc, baseURI, 

XMLSignature.ALGO_ID_SIGNATURE_DSA );
docElement.appendChild( sig.getElement() );
sig.getSignedInfo().addResourceResolver( new
org.apache.xml.security.samples.utils.resolver.OfflineResolver() );

Transforms transforms = new Transforms( doc );

transforms.addTransform( Transforms.TRANSFORM_ENVELOPED_SIGNATURE );

transforms.addTransform( Transforms.TRANSFORM_C14N_WITH_COMMENTS );

sig.addDocument( "", transforms, Constants.ALGO_ID_DIGEST_SHA1 );

sig.addKeyInfo( publicKey );

sig.sign( privateKey );

And then:

ByteArrayOutputStream baos = new ByteArrayOutputStream();
XMLUtils.outputDOMc14nWithComments( docElement, baos );
docStr = baos.toString();
int startDigestLocation = docStr.indexOf( "<ds:DigestValue>" );
int endDigestLocation = docStr.indexOf( "</ds:DigestValue>" );
startDigestLocation += 16;
digest = docStr.substring( startDigestLocation, endDigestLocation );

I get a certain digest from the resulting document. Of course, the
undesirable thing about this is that if I just want the digest, then I'm
going through more work than I feel I should be going through.

I'm having a bit of trouble getting the digest from the preceding code
to match the digest of any code I write that does not actually sign the
document.

Canonicalizer c14n = Canonicalizer.getInstance(
Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XMLUtils.outputDOMc14nWithComments( docElement, baos );
byte[] octetsFromInstance = baos.toByteArray();
XMLSignatureInput xmlsi = new XMLSignatureInput( octetsFromInstance );

Transforms t = new Transforms( doc );
t.addTransform( Transforms.TRANSFORM_C14N_WITH_COMMENTS );
byte[] octetsToDigest = t.performTransforms( xmlsi ).getBytes();
	    
MessageDigest md = MessageDigest.getInstance("SHA");

digest = new String( org.apache.xml.security.utils.Base64.encode(
md.digest( octetsToDigest ) ) );

Of course, I am not applying the enveloped signature transform, because
when I do, I get the exception 'TransformationException: No message with
ID "envelopedSignatureTransformNotInSignatureElement" found in resource
bundle "org/apache/xml/security/resource/xmlsecurity"', which is to be
expected :-)

I guess my question is, when creating an enveloped signature, is there a
way to get the same hash as I would if I were signing the whole thing
and extracting the text of the digest (as in the first example I gave)?

Mike

On Thu, 2002-09-26 at 02:48, Christian Geuer-Pollmann wrote:
> 
> 
> --On Monday, September 23, 2002 11:25 AM -0700 Michael Halcrow 
> <ma...@email.byu.edu> wrote:
> 
> > What is the most efficient way to just get the digest of an XML
> > document? I would also like to know how to get the digest of the result
> > of a set of transforms (i.e., XPath filtered set of nodes).
> 
> Hm, not sure what you mean:
> 
> ----------------------------------------------
> 
> (1) If you have an XML Document (i.e. a file on your disk), you simply get 
> the octets and pipe them into the digest. But I guess that's not what you 
> wanted.
> 
> ----------------------------------------------
> 
> (2) If you have an XML Document (i.e. a file on your disk) and you want the 
> digest of the canonical form, simply read the File into a byte[] array and 
> send these byte[]s to the Canonicalizer:
> 
> org.apache.xml.security.Init.init();
> Canonicalizer c14n = Canonicalizer.getInstance(
>       Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS);
> // read in XML file
> byte[] octetsFromInstance = ...;
> byte[] octetsToDigest = c14n.canonicalize(octetsFromInstance);
> // now simply digest octetsToDigest
> 
> ----------------------------------------------
> 
> (3) If you talk about Transforms (or filtered node sets), you don't have a 
> document but a document subset. In that case, the Reference object does 
> what you need: de-referencing the document, applying Transforms and 
> calculating the digest. Reference is *not* intended to be used without a 
> surrounding container (that's why all constructors are protected). But you 
> can create a Manifest (which is essentially a collection of References).
> 
> Manifest manifest = new Manifest(doc);
> doc.appendChild(manifest.getElement());
> Transforms transforms = new Transforms(doc);
> // transforms.addTransform(....);
> manifest.addDocument(
>     "./whereDoIStoreTheManifest.xml",
>     "xmlInQuestion.xml",
>     transforms,
>     MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA1,
>     null, null);
> manifest.generateDigestValues();
> // serialize doc to whereDoIStoreTheManifest.xml
> // inside that file, the digest of the transformed xmlInQuestion.xml resides
> 
> ----------------------------------------------
> 
> Regards,
> Christian
-- 
---------------------------------------- | ------------------------
Michael Halcrow                          | mhalcrow@byu.edu    
Research Assistant, Network Security Lab | Dept. of Comp. Science  
                                         | Brigham Young University
The sum of the Universe is zero.         |
---------------------------------------- | ------------------------