【问题标题】:Constructing EC Public Key from EC Point and ECParameterSpec gives invalid x value从 EC 点和 ECParameterSpec 构造 EC 公钥会给出无效的 x 值
【发布时间】:2020-02-12 22:32:54
【问题描述】:

我有一个未压缩的prime256v1 曲线的 EC 点,我正在尝试使用 BouncyCastle 提供程序使用以下代码(引用自 here)从中构造一个 PublicKey 对象:

public static void main(String[] args) throws Exception
{
    // Using BC as SunEC (java8) doesn't support prime256v1.
    Security.addProvider(new BouncyCastleProvider());

    // Input values -----------------

    // Complete EC Point (with uncompressed prefix 04 and the length [41])
    // 0441044ef454741576ed945005ea87f114bf8045bcff84155914246aaef43bc35804c9537201ea2387f7edabf76e85b9a7fc341001ddda3272a9685d9aa36ff96526d9

    // EC Point value w/o the tag and length
    final String ecPointHex = "044ef454741576ed945005ea87f114bf8045bcff84155914246aaef43bc35804c9537201ea2387f7edabf76e85b9a7fc341001ddda3272a9685d9aa36ff96526d9";
    // final String ecParamsHex = "06082a8648ce3d030107"; // prime256v1; OID: 1.2.840.10045.3.1.7

    final String curveName = "prime256v1";
    // ------------------------------

    // EC Parameter Spec ------------

    AlgorithmParameters params = AlgorithmParameters.getInstance("EC", "BC");
    params.init(new ECGenParameterSpec(curveName));

    ECParameterSpec ecParameterSpec = params.getParameterSpec(ECParameterSpec.class);

    // ------------------------------

    // EC Point ---------------------

    byte[] ecPointBinary = Hex.decode(ecPointHex);

    byte[] x = Arrays.copyOfRange(ecPointBinary, 0, ecPointBinary.length / 2);
    byte[] y = Arrays.copyOfRange(ecPointBinary, ecPointBinary.length / 2, ecPointBinary.length);

    ECPoint ecPoint = new ECPoint(new BigInteger(1, x), new BigInteger(1, y));

    // ------------------------------

    // Construct Public Key ---------

    KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC"); // Tried ECDSA as well

    ECPublicKey ecPublicKey = (ECPublicKey) keyFactory.generatePublic(new ECPublicKeySpec(ecPoint, ecParameterSpec)); // <-- exception here

    System.out.println(ecPublicKey);

    // ------------------------------
}

但我得到了这个例外:

Exception in thread "main" java.lang.IllegalArgumentException: x value invalid for SecP256R1FieldElement
    at org.bouncycastle.math.ec.custom.sec.SecP256R1FieldElement.<init>(Unknown Source)
    at org.bouncycastle.math.ec.custom.sec.SecP256R1Curve.fromBigInteger(Unknown Source)
    at org.bouncycastle.math.ec.ECCurve.createPoint(Unknown Source)
    at org.bouncycastle.math.ec.ECCurve.createPoint(Unknown Source)
    at org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util.convertPoint(Unknown Source)
    at org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util.convertPoint(Unknown Source)
    at org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey.<init>(Unknown Source)
    at org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi.engineGeneratePublic(Unknown Source)
    at java.security.KeyFactory.generatePublic(KeyFactory.java:328)
    at com.test.ECStackOverflow.main(ECStackOverflow.java:70)

我做错了什么?

P.S:此 PublicKey 是在 SafeNet HSM 中生成的,EC Point 和 Params 值是从 PublicKey 对象中检索的。

【问题讨论】:

    标签: java cryptography bouncycastle elliptic-curve hsm


    【解决方案1】:

    您在 X 值中包含未压缩的点指示符 04,因此您的 X 和 Y 值都已移动。

    所以直接的答案是跳过指标。但是,为了确定起见,我不会使用您收到的点的大小,而是使用曲线的大小将其复制出来。这样,该方法将在读取较小或较大曲线的点之前失败。

    当然,在这种情况下,您还可以创建支票。

    int primeSizeBytes = (ecParameterSpec.getCurve().getField().getFieldSize() + Byte.SIZE - 1) / Byte.SIZE;
    
    if (ecPointBinary.length != 1 + 2 * primeSizeBytes) {
        // or think of your own exception
        throw new InvalidKeyException("EC point size invalid");
    }
    
    if (ecPointBinary[0] != 04) {
        throw new InvalidKeyException("EC uncompressed point indicator with byte value 04 missing");
    }
    
    byte[] x = Arrays.copyOfRange(ecPointBinary, 1, 1 + primeSizeBytes);
    byte[] y = Arrays.copyOfRange(ecPointBinary, 1 + primeSizeBytes, 1 + 2 * primeSizeBytes);
    

    【讨论】:

    • 哎呀,又用了顺序而不是素数。
    • 你是对的。我在解释04 标签时犯了一个错误。第一个04 显然是八位组字符串的ASN.1 标记,我把它误认为是未压缩的指示符。我需要考虑的字节是值的第一个字节,而不是 asn1 字符串本身的第一个字节。
    • 是的,04 指标中的 04 指标只是要求这样的错误。去过那里,做到了:)
    • 我知道.. 你的回答让我重新思考。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多