【问题标题】:Javacard - Signining and verifyingJavacard - 签名和验证
【发布时间】:2015-06-29 01:58:37
【问题描述】:

我正在尝试在卡上签署消息并在卡外验证它。

结果总是假的。

我可能会错误地获取模数和指数。 有什么想法吗?

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

创建公钥的代码:

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

【问题讨论】:

    标签: java cryptography javacard jcop


    【解决方案1】:

    问题在于getExponent()getModulus() 这两种方法。您将 exponentmodulus 存储到 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)
    • 纯文本(从中生成签名)
    • 签名

    【讨论】:

    • 你是对的。我又进了一步。 EXP: -776978591.... MOD: 65537 ResponseAPDU: 130 bytes, SW=9000 Length:128 签名验证: false 但是它仍然是 false
    • 您没有显示您的小程序侧面 sign 生成代码。
    • 我以为我做到了,我刚刚更新了问题。感谢您指出这一点
    • 您在宿主应用程序中使用的明文消息在哪里?
    • 我确实错过了明文,感谢您对更新的简要说明,但验证仍然是错误的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-04
    • 2021-06-19
    • 2012-07-23
    • 1970-01-01
    • 1970-01-01
    • 2012-01-16
    相关资源
    最近更新 更多