4

Android で SpongyCastle を使用して ECDSA キー ペアを生成しようとしています。これはコードです:

static {
    Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
}

public static KeyPair generate() {
        ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("prime256v1");
        KeyPairGenerator generator = KeyPairGenerator.getInstance("ECDSA", "SC");
        generator.initialize(ecSpec, new SecureRandom());
        KeyPair keyPair = g.generateKeyPair();
        Log.i(TAG, "EC Pub Key generated: " + utils.bytesToHex(keyPair.getPublic().getEncoded()));
        Log.i(TAG, "EC Private Key generated: " + utils.bytesToHex(keyPair.getPrivate().getEncoded()));            
       return generator.generateKeyPair();
}

公開鍵の例のようなものを常に取得するため、何かが間違っています。

3059301306072A8648CE3D020106082A8648CE3D03010703420004483ABA9F322240010ECF00E818C041A60FE71A2BD64C64CD5A60519985F110AEDE6308027D2730303F5E2478F083C7F5BB683DCAC22BFEB62F3A48BD01009F40

および秘密鍵:

308193020100301306072A8648CE3D020106082A8648CE3D030107047930770201010420219AB4B3701630973A4B2917D53F69A4BE6DAD61F48016BFEF147B2999575CB2A00A06082A8648CE3D030107A14403420004483ABA9F322240010ECF00E818C041A60FE71A2BD64C64CD5A60519985F110AEDE6308027D2730303F5E2478F083C7F5BB683DCAC22BFEB62F3A48BD01009F40

サイトのECDSA サンプルで「無効な ECDSA 署名メッセージ」が表示されますが、同じサイトで生成されたより小さな秘密鍵とは常に「04」の公開鍵で始まるものとは非常に異なっているようです。

また、バックエンド検証で「無効なポイント エンコーディング 0x30」というエラーが表示されます。

バックエンド Java メソッド チェックは次のとおりです。

public ECPublicKey getPublicKeyFromHex(String publicKeyHex)
        throws NoSuchAlgorithmException, DecoderException, ApplicationGenericException {
    byte[] rawPublicKey = Hex.decodeHex(publicKeyHex.toCharArray());
    ECPublicKey ecPublicKey = null;
    KeyFactory kf = null;

    ECNamedCurveParameterSpec ecNamedCurveParameterSpec = ECNamedCurveTable.getParameterSpec("prime256v1");
    ECCurve curve = ecNamedCurveParameterSpec.getCurve();
    EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, ecNamedCurveParameterSpec.getSeed());
    java.security.spec.ECPoint ecPoint = ECPointUtil.decodePoint(ellipticCurve, rawPublicKey);
    java.security.spec.ECParameterSpec ecParameterSpec = EC5Util.convertSpec(ellipticCurve,
            ecNamedCurveParameterSpec);
    java.security.spec.ECPublicKeySpec publicKeySpec = new java.security.spec.ECPublicKeySpec(ecPoint,
            ecParameterSpec);

    kf = KeyFactory.getInstance("ECDSA", new BouncyCastleProvider());

    try {
        ecPublicKey = (ECPublicKey) kf.generatePublic(publicKeySpec);
    } catch (Exception e) {
        throw new ApplicationGenericException(e.getMessage(), e.getCause());
    }

    return ecPublicKey;
}
4

2 に答える 2

7

a の Java のデフォルト エンコーディングは、単なる EC ポイントではありませんPublicKey"X.509"これは、アルゴリズム (EC) とパラメーター (ここでは prime256v1) を識別する ASN.1 構造であり、さらにポイントをラップするビット文字列です。rfc5280 セクション 4.2.1.7およびrfc3279 セクション 2.3.5を参照してください。

同様に、 のデフォルトのエンコーディングPrivateKey"PKCS#8"(暗号化されていない) です。これは、AlgorithmIdentifier と、この場合は秘密鍵の値と公開鍵のコピーの両方を含むデータをラップする OCTET STRING を含む構造ですhttp://www.secg.orgの文書 SEC 1 で、タグは[0]省略されていますが、タグは[1]存在します。

それら (どちらかまたは両方) を Java に読み戻すには、 a を取得して、またはそれぞれKeyFactory.getInstance("EC")で使用します。ECDSA と ECDH (および ECMQV など) は、同じ数学的構造 ($Z_p^*$) を使用するがわずかに異なる表現を使用する従来の整数 DSA と DH とは異なり、同じキー構造を使用します。generate{Public,Private}X509EncodedKeySpecPKCS8EncodedKeySpec

PS: のjavadoc はjava.security.Key、これのほとんどを教えてくれます。

于 2016-10-20T03:36:59.087 に答える
2

より実用的な例。生成された公開鍵をデコードされたバイト配列または 16 進文字列に変換します。

public String getPublicKeyAsHex(PublicKey publicKey){

    ECPublicKey ecPublicKey = (ECPublicKey)publicKey;
    ECPoint ecPoint = ecPublicKey.getW();

    byte[] publicKeyBytes = new byte[PUBLIC_KEY_LENGTH];
    writeToStream(publicKeyBytes, 0, ecPoint.getAffineX(), PRIVATE_KEY_LENGTH);
    writeToStream(publicKeyBytes, PRIVATE_KEY_LENGTH, ecPoint.getAffineY(), PRIVATE_KEY_LENGTH);

    String hex = Hex.toHexString(publicKeyBytes);

    logger.debug("Public key bytes: " + Arrays.toString(publicKeyBytes));
    logger.debug("Public key hex: " + hex);

    return hex;
}

private void writeToStream(byte[] stream, int start, BigInteger value, int size) {
    byte[] data = value.toByteArray();
    int length = Math.min(size, data.length);
    int writeStart = start + size - length;
    int readStart = data.length - length;
    System.arraycopy(data, readStart, stream, writeStart, length);
}

デコードされたバイト配列を次のように変換しますPublicKey:

KeyFactory factory = KeyFactory.getInstance(ALGORITHM, ALGORITHM_PROVIDER);

ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(CURVE);

ECNamedCurveSpec params = new ECNamedCurveSpec(CURVE, spec.getCurve(), spec.getG(), spec.getN());

BigInteger xCoordinate = new BigInteger(1, Arrays.copyOfRange(decodedPublicKey, 0, PRIVATE_KEY_LENGTH));
BigInteger yCoordinate = new BigInteger(1, Arrays.copyOfRange(decodedPublicKey, PRIVATE_KEY_LENGTH, PUBLIC_KEY_LENGTH));
java.security.spec.ECPoint w = new java.security.spec.ECPoint(xCoordinate, yCoordinate);

PublicKey encodedPublicKey = factory.generatePublic(new java.security.spec.ECPublicKeySpec(w, params));
于 2016-10-24T08:07:29.363 に答える