2015-06-28 72 views
1

我正试图在卡上签名并验证它是否为卡。Javacard - 签名和验证

结果总是错误的。

我可能会错误地获取模数和指数。 任何想法?

的Java applet代码:

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(); 

代码来创建公共密钥:

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); 

UPDATE: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); 

回答

3

的问题是在这两种方法getExponent()getModulus()。您将指数模数存储为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); 

要验证签名,你需要

  • 公钥
  • 验证机制(如SHA1withRSA)
  • 纯文本(从中生成签名)
  • 签名
+0

你说得对。我更进了一步。 EXP:-776978591 .... MOD:65537个 ResponseAPDU:130个字节,SW = 9000 长度:128 签名验证:假 但是它仍然是假 –

+0

你并没有显示你的applet双方_sign_生成代码。 –

+0

我以为我做了,我只是更新了问题。感谢您指出这一点 –