I'm trying to sign a message on-card and verifying it off-card.
The result is always false.
I'm probably getting fetching the modulus and exponent incorrectly. Any ideas?
Java applet code:
protected MainApplet() {
try {
// CREATE RSA KEYS AND PAIR
m_keyPair = new KeyPair(KeyPair.ALG_RSA_CRT, KeyBuilder.LENGTH_RSA_1024);
// STARTS ON-CARD KEY GENERATION PROCESS
m_keyPair.genKeyPair();
// OBTAIN KEY REFERENCES
m_publicKey = (RSAPublicKey) m_keyPair.getPublic();
m_privateKey = (RSAPrivateCrtKey) m_keyPair.getPrivate();
} catch (CryptoException c) {
//this line will give you the reason of problem
short reason = c.getReason();
ISOException.throwIt(reason); // for check
}
}
.......
switch (INS) {
case 0x00:
getPublicKeyExp(apdu);
break;
case 0x10:
getPublicKeyMod(apdu);
break;
case 0x21:
signMessage(apdu);
break;
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
}
private void getExponent(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getExponent(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend((short) 0, length);
}
private void getModulus(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getModulus(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend((short) 0, length);
}
Java host code:
/*************** EXECUTE COMMAND *************/
byte[] get_exponent = {
(byte) 0x80, // CLA Class
0x00, // INS Instruction
0x00, // P1 Parameter 1
0x00, // P2 Parameter 2
0x00 // LE maximal number of bytes expected in result
};
byte[] get_modulus = {
(byte) 0x80, // CLA Class
0x10, // INS Instruction
0x00, // P1 Parameter 1
0x00, // P2 Parameter 2
0x00 // LE maximal number of bytes expected in result
};
ResponseAPDU resp_modulus = channel.transmit(new CommandAPDU(get_modulus));
System.out.println(resp_modulus.toString());
ResponseAPDU resp_exponent = channel.transmit(new CommandAPDU(get_exponent));
System.out.println(resp_exponent.toString());
byte[] modulus = resp_modulus.getData();
byte[] exponent = resp_exponent.getData();
Code to create public key:
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(new BigInteger(1, modulus), new BigInteger(1, exponent));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
publicKey = keyFactory.generatePublic(keySpec);
Code to verify message:
byte[] get_signed_message = {
(byte) 0x80, // CLA Class
0x21, // INS Instruction
0x00, // P1 Parameter 1
0x00, // P2 Parameter 2
0x00 // LE maximal number of bytes expected in result
};
ResponseAPDU resp = channel.transmit(new CommandAPDU(get_signed_message));
System.out.println(resp.toString());
byte[] sigToVerify = resp.getData();
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initVerify(publicKey);
sig.update(sigToVerify);
boolean verifies = sig.verify(sigToVerify);
UPDATE: Java applet signature method
byte[] testSig = new byte[256];
byte[] test = {0x01, 0x02, 0x04, 0x05, 0x06, 0x07};
// CREATE SIGNATURE OBJECT
Signature m_sign = Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1, false);
// INIT WITH PRIVATE KEY
m_sign.init(m_privateKey, Signature.MODE_SIGN);
short len = m_sign.sign(test, (short) 0, (short) test.length, testSig, (short) 0);
apdu.setOutgoing();
apdu.setOutgoingLength(len);
apdu.sendBytesLong(testSig, (short) 0, len);
The problem is in these two methods
getExponent()
andgetModulus()
. You are storing exponent and modulus intobuffer
's indexISO7816.OFFSET_CDATA
(index 5) but sent it outside frombuffer
's index0
.Compare the correct approachs with the wrong approach:
Wrong:
Correct 1 (appreciated):
Correct 2:
EDIT: In your host application, you need the followings:
To verify a Signature, you need