2016-10-20 5 views
1

Android에서 SpongyCastle을 사용하여 ECDSA 키 쌍을 생성하려고합니다.올바른 ECDSA EC 키 쌍을 생성하려면 어떻게해야합니까?

3059301306072A8648CE3D020106082A8648CE3D03010703420004483ABA9F322240010ECF00E818C041A60FE71A2BD64C64CD5A60519985F110AEDE6308027D2730303F5E2478F083C7F5BB683DCAC22BFEB62F3A48BD01009F40

및 개인 키 : 난 항상 공개 키의 예처럼 뭔가를 얻을 수 있기 때문에

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

뭔가 잘못 :

이 코드입니다 0

308193020100301306072A8648CE3D020106082A8648CE3D030107047930770201010420219AB4B3701630973A4B2917D53F69A4BE6DAD61F48016BFEF147B2999575CB2A00A06082A8648CE3D030107A14403420004483ABA9F322240010ECF00E818C041A60FE71A2BD64C64CD5A60519985F110AEDE6308027D2730303F5E2478F083C7F5BB683DCAC22BFEB62F3A48BD01009F40

사이트 ECDSA sample은 나에게 "잘못된 ECDSA 서명 메시지"를주고, 그들은 작은 개인 키에서 정말 다른 항상 같은 사이트에서 생성 된 "04"공개 키로 시작하는 것 같다.

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

PublicKey에 대한 자바의 기본 인코딩 그냥하지 않은 "X.509"입니다 : 또한

, 내 백엔드 검증 "잘못된 점 인코딩 0x30에"

백엔드 Java 메소드 검사는 나에게 오류를 제공 EC 포인트; 이것은 알고리즘 (EC)과 매개 변수 (여기서는 prime256v1)를 식별하는 ASN.1 구조이며, 점을 배치하는 비트 문자열을 더한 것입니다. rfc5280 section 4.2.1.7rfc3279 section 2.3.5을 참조하십시오.

유사하게 PrivateKey 대한 기본 인코딩은 AlgorithmIdentifier 더하여,이 경우에는 개인 키 값 및 상기 공개 키의 카피 모두에 포함 된 데이터를 배치 옥텟 스트링을 포함하는 구조이다 (암호화) "PKCS#8"rfc5208 section 5 참조하며 SEC의 [0] 태그가 생략되었지만 [1] 태그가있는 SEC 1 문서 C.4.

읽기 (하나 또는 둘 다) 그들이 다시 자바에서는, KeyFactory.getInstance("EC")을 얻을 각각 X509EncodedKeySpec 또는 PKCS8EncodedKeySpecgenerate{Public,Private}을 사용합니다. ECDSA와 ECDH (및 ECMQV 등)는 동일한 수학적 구조 ($ Z_p^* $)를 사용하지만 약간 다른 표현을 사용하는 고전적인 정수 DSA 및 DH와는 달리 동일한 키 구조를 사용합니다.

추 신 : javadoc for java.security.Key이 대부분을 설명합니다.

1

더욱 실제적인 예. 디코딩 바이트의 배열 또는 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)); 
관련 문제