Cryptography - RSA decryption using block cipher
Hi everybody,
I'am getting stuck around a decryption problem. It is my first time (since one month) I work in java cryptography - and even in cryptography at all.
Well, I made two programs (2 java applet) :
- The first one compute a MD5 hash code of a specified file. Then this hash code is signed with a private key thanks to a X509 certificate, ensuring data integrity (MD5 hash code) and authenticity (signature). This signature is stored in a file with extension .sig.
- The second one simply read the .sig. Then it decrypts the signature thanks to the same certificate (providing the public key). Hence I will be able to read the crypted MD5 hash code in clear.
The problem is that I don't manage to decrypt the signature successfully. Indeed, I sign the MD5 hash code with the algorithm "MD5withRSA", the only one which seems suitable for my case (I want to crypt/decrypt with RSA).
On the other side, when I try to decrypt the signature, this latter is too long : the .sig file has 217 bytes ! So when I pass all this content in a buffer, this one is too long for decryption (with RSA algorithm which works only with blocks of 128 bytes). I managed to have a look at how "block cipher" works including padding. I even found a bit of java code to crypt a long message in multipart. But in my case, I am interested for decryption in multi block. The signature was made in one block (called stream cipher).
My question is : How to do a decryption of a long message with RSA in multi block ?
I try a "debug" code (see below) and I have always the same error : "too much data for RSA block". And yet, I read only 1 byte !!
byte[] decryptedBytes;
for (int i = 0, j = 0; i < sig.length; i++){
if ((decryptedBytes = cipher.update(sig, i, 1)) ==null)
continue;
else{
System.out.println(new String(decryptedBytes));
System.arraycopy(decryptedBytes, 0, plainText, j, decryptedBytes.length);
j += decryptedBytes.length;
}
}
Thanks for your explanations.
[2515 byte] By [
kokoricoa] at [2007-11-26 23:22:59]

# 2
You are doing much more work than you need to. You can use the Signature class as illustrated by this example -
import java.security.*;import java.io.*;
public class SignatureExample
{
public static void main(String[] args) throws Exception
{
final String ALGORITHM ="SHA1withDSA";
final String KEY_TYPE = "DSA";
final File keyFile = new File(System.getProperty("user.home") + "/temp/dsakey");
keyFile.getParentFile().mkdirs();
if (!keyFile.exists())
{
KeyPairGenerator signerKeyGenerator = KeyPairGenerator.getInstance(KEY_TYPE);
signerKeyGenerator.initialize(1024);
KeyPair signerKeyPair = signerKeyGenerator.generateKeyPair();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(keyFile));
oos.writeObject(signerKeyPair.getPrivate());
oos.writeObject(signerKeyPair.getPublic());
oos.close();
}
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(keyFile));
PrivateKey privatekey = (PrivateKey)ois.readObject();
PublicKey publicKey = (PublicKey)ois.readObject();
ois.close();
final byte[] message = "The quick brown fox jumps over the lazy dog.".getBytes("UTF-8");
final byte[] signatureOfMessage;
{
final Signature signatureActor = Signature.getInstance(ALGORITHM);
signatureActor.initSign(privatekey);
signatureActor.update(message);
signatureOfMessage = signatureActor.sign();
}
{
final Signature verifyerActor = Signature.getInstance(ALGORITHM);
verifyerActor.initVerify(publicKey);
verifyerActor.update(message);
boolean signatureOK = verifyerActor.verify(signatureOfMessage);
System.out.println(ALGORITHM + " signature is " + (signatureOK?"Good":"Bad"));
}
}
}
In the example I get the data to be signed from a String but one can easily get the data from a file a few KBytes at a time and use the update() method until all the bytes of the file have been processed.
Also, you can change the algorithm to MD5withRSA with a very simple edit.
P.S. Ignore the Key generation and saving code. It is there just to make the example self contained.
Message was edited by:
sabre150
# 4
Thanks. But the Signature class only allows to sign
and verify signatures, doesn't it ?
I need more than simply verify the provenance i.e.
knowing that verify method returns true or false. I
need to decrypt the message (and get the decrypted
message in a buffer), not to know "true" or "false".
I don't understand. To quote your original post
<quote>
- The first one compute a MD5 hash code of a specified file. Then this hash code is signed with a private key thanks to a X509 certificate, ensuring data integrity (MD5 hash code) and authenticity (signature). This signature is stored in a file with extension .sig.
- The second one simply read the .sig. Then it decrypts the signature thanks to the same certificate (providing the public key). Hence I will be able to read the crypted MD5 hash code in clear.
</quote>
This looks to be exactly what the Signature class provides. What am I missing?
# 5
The Signature class never return a decrypted message (a byte[] array) :
The two methods available to verify a signature are :
boolean verify(byte[] signature)
Verifies the passed-in signature.
boolean verify(byte[] signature, int offset, int length)
Verifies the passed-in signature in the specified array of bytes, starting at the specified offset.
The problem is that it only returns a boolean. In fact, I crypted the MD5 hash code doing a signature of that hash code. On the other side, I need to decrypt the signature so as to recover the original MD5 hash code. So I use the Cipher class in DECRYPT_MODE and I pass the array of byte[] read from the .sig file and the public key of the certificate. But I have trouble doing like this (so my topic).
# 6
From my previous reply, it follows a more global question :
A signature is usefull to prove the authenticity : by verifying it, we can know if the message comes from the expected person (yes if it returns true, no if it returns false).
But doing a signature (that is crypt the message with the private key) on a given message, is it like "crypting" message in addition ?
So next I need to decrypt message with the public key. I consider it like a "DECRYPT_MODE" operation in the Cipher class.
Or maybe I don't have to crypt the hash code MD5 signing with the private key ... I am a little confuse with signature.
For me, I can crypt with either the private key or the public key. The difference is that crypting with the private key ensures authenticity (not for the public key) but "everybody" having the public key will be able to decrypt the message (what is a nonsense crypting operation, just authenticity is certain crypting with the private key).
# 7
Sorry but I don't understand why you think you need the decrypted hash of the message. All you can do with it is compare it with the hash of the message you are sent with the signature and if they are the same then the chances are the message has not been tampered with.
The act of comparing hashes yields true or false (there are really no other possibilities) which is just what the Signature class does!
You seem to be saying that you are encryption the message with the private key. Why are you doing this? Why not sent the message unencrypted and just sent a signature (which is the digest of the message encrypted with the private key).
Obviously I don't understand what you are trying to do.
Message was edited by:
sabre150
# 8
Well I explain what I do :
In the first applet :
1) I sign the MD5Hash
hashString = computeMD5Hash();PrivateKey privatekey = (PrivateKey) keyStore.getKey(keyStore
.aliases().nextElement(), password);
Signature sig = Signature.getInstance("MD5withRSA", provBC);
sig.initSign(privatekey);
sig.update(hashString.getBytes());
return sig.sign();
2) I encode signature data in Base64. Then I write the signature data into a zipped file.
// write signature into file.makeZipFile(Base64.der2pem(sig, "PKCS7").getBytes(), outputSigFileName);
In the second applet :
1) I load the signature file into a byte[] array :
// load signature fileFile sigFile = new File(selectedSignature);
byte[] sigData = new byte[(int) sigFile.length()];
DataInputStream in = new DataInputStream(new FileInputStream(sigFile));
in.readFully(sigData);
in.close();
sigData = Base64.decode(sigData);
2) I verify the signature :
Signature sigInst = Signature.getInstance("MD5withRSA",provBC);sigInst.initVerify(cert.getPublicKey());
sigInst.update(sigData);
System.out.println(sigInst.verify(sigData));
It prints always false. Why ? Where is the error ?
N.B. : sigData is 162 length and sig.sign() return a 128 array length. Why do they differ ?