views:

7648

answers:

5

I'm trying to understand what the Java java.security.Signature class does. If I compute an SHA1 message digest, and then encrypt that digest using RSA, I get a different result to asking the Signature class to sign the same thing:

// Generate new key
KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
String plaintext = "This is the message being signed";

// Compute signature
Signature instance = Signature.getInstance("SHA1withRSA");
instance.initSign(privateKey);
instance.update((plaintext).getBytes());
byte[] signature = instance.sign();

// Compute digest
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
byte[] digest = sha1.digest((plaintext).getBytes());

// Encrypt digest
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] cipherText = cipher.doFinal(digest);

// Display results
System.out.println("Input data: " + plaintext);
System.out.println("Digest: " + bytes2String(digest));
System.out.println("Cipher text: " + bytes2String(cipherText));
System.out.println("Signature: " + bytes2String(signature));

Results in (for example):

Input data: This is the message being signed
Digest: 62b0a9ef15461c82766fb5bdaae9edbe4ac2e067
Cipher text: 057dc0d2f7f54acc95d3cf5cba9f944619394711003bdd12...
Signature: 7177c74bbbb871cc0af92e30d2808ebae146f25d3fd8ba1622...

I must have a fundamental misunderstanding of what Signature is doing - I've traced through it, and it appears to be calling update on a MessageDigest object, with the algorithm set to SHA1 as I would expect, then getting the digest, then doing the encryption. What's making the results differ?

EDIT:

Leonidas made me check whether the signature scheme is supposed to do what I think it does. There are two types of signature defined in the RFC:

The first of these (PKCS1) is the one I describe above. It uses a hash function to create a digest, and then encrypts the result with a private key.

The second algorithm uses a random salt value, and is more secure but non-deterministic. The signature produced from the code above does not change if the same key is used repeatedly, so I don't think it can be PSS.

EDIT:

Here's the bytes2string function I was using:

private static String bytes2String(byte[] bytes) {
 StringBuilder string = new StringBuilder();
 for (byte b: bytes) {
  String hexString = Integer.toHexString(0x00FF & b);
  string.append(hexString.length() == 1 ? "0" + hexString : hexString);
 }
 return string.toString();
}
+2  A: 

Erm, after understanding your question: are you sure that the signature-method only creates a SHA1 and encrypts it? GPG et al offer to compress/clear sign the data. Maybe this java-signature-alg also creates a detachable/attachable signature.

Leonidas
I'm not sure, no, but I would expect the algorithm to indicate if it were going to do more than just those two operations. I've been reading the RFC: http://www.ietf.org/rfc/rfc3447.txt, which as far as I understand, just hashes, then encrypts the hash. Is GPG's compression for encrypted messages?
Mike Houston
+9  A: 

OK, I've worked out what's going on. I was being stupid. Leonidas is right, it's not just the hash that gets encrypted, it's the ID of the hash algorithm concatenated with the digest:

  DigestInfo ::= SEQUENCE {
      digestAlgorithm AlgorithmIdentifier,
      digest OCTET STRING
  }

Which is why they are different.

Mike Houston
Hooray for finding it out by yourself :)
Leonidas
Exactly what I needed! Thanks so much! +20 points for you
yuku
A: 

i tried to convert byte array to string, but i failed how this can be done? i want to print the signature as a string like your example displays..

I've added my bytes2string implementation to the question Mohomed. Hope that helps.
Mike Houston
Also, take a look at this question: http://stackoverflow.com/questions/332079/in-java-how-do-i-convert-a-byte-array-to-a-string-of-hex-digits-while-keeping-le
Mike Houston
A: 

Does http://www.discryptor.net/ works with RSA?

Assuming this isn't spam, no, it only uses symmetric cryptographic algorithms. This should be its own question.
Mike Houston
A: 

In the XML digital signature API, what is being used to sign a multi-references document? i mean how is the SignatureValue computed from 2 or more digest values (one for each reference)?

m-tel
I think this should be a new question, but from what I can tell here: http://www.w3.org/TR/xmldsig-bestpractices/#id83801 the data to be signed is the union of the nodesets from each reference: "If there are multiple references in the signature,the result should be a union of these nodesets." - that's not exactly the right part of the spec. See also: http://www.w3.org/TR/xmldsig-core/#sec-o-Manifest - I think in general you just digest the data from each reference in turn, then sign the final digest output.
Mike Houston