Javacard - 签名和验证
Javacard - Signining and verifying
我正在尝试在卡上签署消息并在卡外验证。
结果总是错误的。
我可能获取的模数和指数不正确。
有什么想法吗?
Java小程序代码:
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主机代码:
/*************** 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();
创建 public 密钥的代码:
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(new BigInteger(1, modulus), new BigInteger(1, exponent));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
publicKey = keyFactory.generatePublic(keySpec);
验证消息的代码:
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);
更新:Java小程序签名方法
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);
问题出在getExponent()
和getModulus()
这两个方法上。您正在将 exponent 和 modulus 存储到 buffer
的索引 ISO7816.OFFSET_CDATA
(索引 5)中,但是从 buffer
的索引0
.
比较正确的方法和错误的方法:
错误:
private void getExponent(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getExponent(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend((short) 0, length); // not the valid public exp
}
private void getModulus(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getModulus(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend((short) 0, length); // not the valid mod
}
正确 1(赞赏):
private void getExponent(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getExponent(buffer, (short) 0);
apdu.setOutgoingAndSend((short) 0, length);
}
private void getModulus(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getModulus(buffer, (short) 0);
apdu.setOutgoingAndSend((short) 0, length);
}
正确2:
private void getExponent(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getExponent(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, length);
}
private void getModulus(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getModulus(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, length);
}
编辑: 在您的主机应用程序中,您需要以下内容:
byte[] test = {0x01, 0x02, 0x04, 0x05, 0x06, 0x07};
sig.update(test);
boolean verifies = sig.verify(sigToVerify);
要验证签名,您需要
- 一个Public键
- 验证机制(比如 SHA1withRSA)
- 纯文本(从中生成签名)
- 签名
我正在尝试在卡上签署消息并在卡外验证。
结果总是错误的。
我可能获取的模数和指数不正确。 有什么想法吗?
Java小程序代码:
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主机代码:
/*************** 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();
创建 public 密钥的代码:
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(new BigInteger(1, modulus), new BigInteger(1, exponent));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
publicKey = keyFactory.generatePublic(keySpec);
验证消息的代码:
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);
更新:Java小程序签名方法
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);
问题出在getExponent()
和getModulus()
这两个方法上。您正在将 exponent 和 modulus 存储到 buffer
的索引 ISO7816.OFFSET_CDATA
(索引 5)中,但是从 buffer
的索引0
.
比较正确的方法和错误的方法:
错误:
private void getExponent(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getExponent(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend((short) 0, length); // not the valid public exp
}
private void getModulus(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getModulus(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend((short) 0, length); // not the valid mod
}
正确 1(赞赏):
private void getExponent(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getExponent(buffer, (short) 0);
apdu.setOutgoingAndSend((short) 0, length);
}
private void getModulus(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getModulus(buffer, (short) 0);
apdu.setOutgoingAndSend((short) 0, length);
}
正确2:
private void getExponent(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getExponent(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, length);
}
private void getModulus(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getModulus(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, length);
}
编辑: 在您的主机应用程序中,您需要以下内容:
byte[] test = {0x01, 0x02, 0x04, 0x05, 0x06, 0x07};
sig.update(test);
boolean verifies = sig.verify(sigToVerify);
要验证签名,您需要
- 一个Public键
- 验证机制(比如 SHA1withRSA)
- 纯文本(从中生成签名)
- 签名