You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaCard 3.2生成EC密钥对异常及签名验证失败求助

Oracle JavaCard 3.2模拟器EC密钥对生成与验证问题

我正在使用Oracle JavaCard模拟器最新版本3.2,在生成EC密钥对并导出公钥时遇到异常,同时签名验证环节抛出加密异常。

1. 初始代码与异常公钥输出

尝试生成P-256(secp256r1)EC密钥对并通过ECPublicKey.getW()导出公钥,代码如下:

// Create ECC key pair (P-256 / secp256r1)
KeyPair eccKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256);
eccKeyPair.genKeyPair();
ECPublicKey eccPublicKey = (ECPublicKey)eccKeyPair.getPublic();
short wLength = eccPublicKey.getW(buffer, (short)2);
    
apdu.setOutgoing();
apdu.setOutgoingLength((short)(2 + wLength));
buffer[0] = (byte)((wLength >> 8) & 0xFF);
buffer[1] = (byte)(wLength & 0xFF);
        
apdu.sendBytes((short) 0, (short)(2 + wLength));

得到的输出为00210424603E79077F33047A46079DABB6155E0F9A46B70D570E52B61831AFB9AAAAF4,公钥长度为33字节。33字节是压缩EC公钥的有效长度,但前缀应为02或03,而非04——04是非压缩公钥的前缀,对应长度应为65字节。

2. 设置曲线参数后的尝试

了解到生成密钥对前需设置EC公私钥参数,于是修改代码如下:

ECPrivateKey eccPrivateKey = (ECPrivateKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, KeyBuilder.LENGTH_EC_FP_256, false /* keyEncryption */);
setCurveParameters(eccPrivateKey); // Set SecP256r1 parameters
ECPublicKey eccPublicKey = (ECPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC, KeyBuilder.LENGTH_EC_FP_256, false /* keyEncryption */);
setCurveParameters(eccPublicKey); // Set SecP256r1 parameters
KeyPair eccKeyPair = new KeyPair(eccPublicKey, eccPrivateKey);
eccKeyPair.genKeyPair();
short wLength = eccPublicKey.getW(buffer, (short)2);

结果仍类似:002104B792239DBD35FC129592F258E8231232B30D2FA8907E984788290BC0B7100049,问题未解决。

3. 签名验证时的加密异常

忽略公钥异常进行签名测试,代码如下:

try {
    ECPrivateKey eccPrivateKey = (ECPrivateKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, KeyBuilder.LENGTH_EC_FP_256, false /* keyEncryption */);
    setCurveParameters(eccPrivateKey);
    ECPublicKey eccPublicKey = (ECPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC, KeyBuilder.LENGTH_EC_FP_256, false /* keyEncryption */);
    setCurveParameters(eccPublicKey);
    KeyPair eccKeyPair = new KeyPair(eccPublicKey, eccPrivateKey);
    eccKeyPair.genKeyPair();
    
    byte[] messageBytes = new byte[]{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B};
    
    Signature eccSignature = Signature.getInstance(Signature.ALG_ECDSA_SHA_256, false);
    eccSignature.init(eccPrivateKey, Signature.MODE_SIGN);
    short signatureLength = eccSignature.sign(
            messageBytes, (short)0, (short)messageBytes.length,  // input
            buffer, (short)0           // output (reuse buffer)
        );

    Signature eccVerificationSignature = Signature.getInstance(Signature.ALG_ECDSA_SHA_256, false);
    eccVerificationSignature.init(eccPublicKey, Signature.MODE_VERIFY); // <<<<<<<<< CryptoException here: 'javacard.security.CryptoException (reason=0x0001)' - EC_POINT not created: error:08000066:elliptic curve routines::invalid encoding

    apdu.setOutgoing();
    apdu.setOutgoingLength(signatureLength);
    apdu.sendBytes((short) 0, signatureLength);
} catch (CryptoException e) {
    ISOException.throwIt((short)0x6F01);
}

调用eccSignature.init(eccPublicKey, Signature.MODE_VERIFY);时抛出异常:javacard.security.CryptoException (reason=0x0001)。

Oracle JavaCard模拟器日志如下:

SEVERE |msg|000598|grp:hal | EC_POINT not created: error:08000066:elliptic curve routines::invalid encoding
WARNING|msg|000599|grp:jcre| Exception:
WARNING|msg|000599|grp:jcre| javacard.security.CryptoException (reason=0x0001)
WARNING|msg|000599|grp:jcre|     at javacard.security.CryptoException.throwIt_S (pc=@0x63c02b92)
WARNING|msg|000599|grp:jcre|     at javacard.security.<anonymous> (pc=@0x63c035ee)
WARNING|msg|000599|grp:jcre|     at <unknown> (pc=@0x63c2b09b)
WARNING|msg|000599|grp:jcre|     at <unknown> (pc=@(nil))
WARNING|msg|000600|grp:jcre| Exception:
WARNING|msg|000600|grp:jcre| javacard.framework.ISOException (reason=0x6F01)
WARNING|msg|000600|grp:jcre|     at javacard.framework.ISOException.throwIt_S (pc=@0x63c00e5e)
WARNING|msg|000600|grp:jcre|     at <unknown> (pc=@0x63c2b0b7)
WARNING|msg|000600|grp:jcre|     at <unknown> (pc=@(nil))

日志证实EC密钥对未正确初始化。

4. setCurveParameters方法定义

以下是设置SecP256r1曲线参数的代码:

private final static byte[] p = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00, 0x00,
        0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff,
        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };

private final static byte[] a = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00, 0x00,
        0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff,
        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xfc
    };

private final static byte[] b = { 0x5a, (byte) 0xc6, 0x35, (byte) 0xd8, (byte) 0xaa, 0x3a,
        (byte) 0x93, (byte) 0xe7, (byte) 0xb3, (byte) 0xeb, (byte) 0xbd, 0x55, 0x76, (byte) 0x98,
        (byte) 0x86, (byte) 0xbc, 0x65, 0x1d, 0x06, (byte) 0xb0, (byte) 0xcc, 0x53, (byte) 0xb0,
        (byte) 0xf6, 0x3b, (byte) 0xce, 0x3c, 0x3e, 0x27, (byte) 0xd2, 0x60, 0x4b };

private final static byte[] G = { 0x04, 0x6b, 0x17, (byte) 0xd1, (byte) 0xf2, (byte) 0xe1, 0x2c,
        0x42, 0x47, (byte) 0xf8, (byte) 0xbc, (byte) 0xe6, (byte) 0xe5, 0x63, (byte) 0xa4, 0x40,
        (byte) 0xf2, 0x77, 0x03, 0x7d, (byte) 0x81, 0x2d, (byte) 0xeb, 0x33, (byte) 0xa0, (byte) 0xf4,
        (byte) 0xa1, 0x39, 0x45, (byte) 0xd8, (byte) 0x98, (byte) 0xc2, (byte) 0x96, 0x4f, (byte) 0xe3,
        0x42, (byte) 0xe2, (byte) 0xfe, 0x1a, 0x7f, (byte) 0x9b, (byte) 0x8e, (byte) 0xe7, (byte) 0xeb,
        0x4a, 0x7c, 0x0f, (byte) 0x9e, 0x16, 0x2b, (byte) 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e,
        (byte) 0xce, (byte) 0xcb, (byte) 0xb6, 0x40, 0x68, 0x37, (byte) 0xbf, 0x51, (byte) 0xf5 };

private final static byte[] r = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x00,
        0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
        (byte) 0xff, (byte) 0xbc, (byte) 0xe6, (byte) 0xfa, (byte) 0xad, (byte) 0xa7, 0x17, (byte) 0x9e,
        (byte) 0x84, (byte) 0xf3, (byte) 0xb9, (byte) 0xca, (byte) 0xc2, (byte) 0xfc, 0x63, 0x25, 0x51 };

private final static byte k = 0x01;

public static void setCurveParameters(ECKey key) {
    key.setFieldFP(p, (short) 0, (short) p.length);
    key.setA(a, (short) 0, (short) a.length);
    key.setB(b, (short) 0, (short) b.length);
    key.setG(G, (short) 0, (short) G.length);
    key.setR(r, (short) 0, (short) r.length);
    key.setK(k);
}

内容的提问来源于stack exchange,提问作者OlivierM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 14:05:54