2015-01-02 15 views
7

Ứng dụng của tôi lưu trữ khóa riêng ở định dạng PEM, mã hiện có hoạt động cho khóa RSA nhưng tôi đang cố chuyển sang khóa EC và có sự cố. Việc khôi phục khóa dường như hoạt động, và phương thức equals trên khóa khôi phục trả về true cho khóa ban đầu, nhưng getAlgorithm() trên khóa gốc trả về "EC" và trên khóa khôi phục "ECDSA". Sự khác biệt trong thuật toán sau đó gây ra vấn đề bởi vì nó không khớp với thuật toán cho khóa công khai tương ứng.Khôi phục khóa riêng EC từ định dạng PEM với BouncyCastle

Tôi có làm gì sai hoặc đây có phải là lỗi trong trình phân tích cú pháp PEM không?

Đây là một chương trình thử nghiệm mà chứng tỏ vấn đề:

import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.OutputStreamWriter; 
import java.io.StringReader; 
import java.security.KeyPair; 
import java.security.KeyPairGenerator; 
import java.security.PrivateKey; 
import java.security.SecureRandom; 
import java.security.spec.ECGenParameterSpec; 

import org.bouncycastle.openssl.PEMKeyPair; 
import org.bouncycastle.openssl.PEMParser; 
import org.bouncycastle.openssl.PEMWriter; 
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; 
import org.immutify.janus.keytool.KeyToolUtils; 

public class TestPrivateKeyRecovery 
{ 
    private static final String KEY_ALGORITHM   = "EC"; 
    private static final String SIGNATURE_ALGORITHM  = "SHA512withECDSA"; 
    private static final String PROVIDER    = "BC"; 
    private static final String CURVE_NAME    = "secp521r1"; 
    private static final String WRAPPING_CIPHER_SPEC = "ECIESwithAES"; 

    private ECGenParameterSpec ecGenSpec; 
    private KeyPairGenerator keyGen_; 
    private SecureRandom  rand_; 

    public void run() 
    { 
     try 
     { 
      rand_  = new SecureRandom(); 
      ecGenSpec = new ECGenParameterSpec(CURVE_NAME); 
      keyGen_  = KeyPairGenerator.getInstance(KEY_ALGORITHM, PROVIDER); 

      keyGen_.initialize(ecGenSpec, rand_); 


      PrivateKey privateKey = keyGen_.generateKeyPair().getPrivate(); 





      String der = privateKeyToDER(privateKey); 

      PrivateKey recoveredKey = privateKeyFromDER(der); 

      System.out.println("privateKey=" + privateKey); 
      System.out.println("privateKey.getAlgorithm()=" + privateKey.getAlgorithm()); 
      System.out.println("der=" + der); 
      System.out.println("recoveredKey=" + privateKey); 
      System.out.println("recoveredKey.getAlgorithm()=" + recoveredKey.getAlgorithm()); 
      System.out.println(); 

      if(privateKey.equals(recoveredKey)) 
       System.out.println("Key recovery ok"); 
      else 
       System.err.println("Private key recovery failed"); 

      if(privateKey.getAlgorithm().equals(recoveredKey.getAlgorithm())) 
       System.out.println("Key algorithm ok"); 
      else 
       System.err.println("Key algorithms do not match"); 
     } 
     catch(Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 

    public static String  privateKeyToDER(PrivateKey key) throws IOException 
    { 
     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
     PEMWriter    pemWriter = new PEMWriter(new OutputStreamWriter(bos)); 

     pemWriter.writeObject(key); 

     pemWriter.close(); 

     return new String(bos.toByteArray()); 
    } 

    public static PrivateKey  privateKeyFromDER(String der) throws IOException 
    { 
     StringReader   reader = new StringReader(der); 
     PEMParser    pemParser = new PEMParser(reader); 

     try 
     { 
      Object o = pemParser.readObject(); 

      if (o == null || !(o instanceof PEMKeyPair)) 
      { 
       throw new IOException("Not an OpenSSL key"); 
      } 

      KeyPair kp = new JcaPEMKeyConverter().setProvider("BC").getKeyPair((PEMKeyPair)o); 
      return kp.getPrivate(); 
     } 
     finally 
     { 
      pemParser.close(); 
     } 
    } 
} 

Kết quả từ chương trình thử nghiệm là:

 
privateKey=EC Private Key 
      S: 13d19928468d14fabb9235a81fc1ec706ff5413a70a760b63e07d45a5d04a2f18425ef735500190291aacaf58c92306acd87fa01a47d907d5d3fc01531180353146 

privateKey.getAlgorithm()=EC 
der=-----BEGIN EC PRIVATE KEY----- 
MIHcAgEBBEIBPRmShGjRT6u5I1qB/B7HBv9UE6cKdgtj4H1FpdBKLxhCXvc1UAGQ 
KRqsr1jJIwas2H+gGkfZB9XT/AFTEYA1MUagBwYFK4EEACOhgYkDgYYABAFN5ZcE 
zg9fV13u57ffwyN9bm9Wa9Pe0MtL2cd5CW2ku4mWzgS5m8IfNMAw2QMah5Z9fuXW 
1fGJgUx1RsC09R6legFTgymlbqt+CaPhNsJkr12cjyzhT1NxR6uEzMUtBcYxqLHy 
ANkhHmvAk221//YIRIWix7ZlRsRrs+iYrpWw4bMt9A== 
-----END EC PRIVATE KEY----- 

recoveredKey=EC Private Key 
      S: 13d19928468d14fabb9235a81fc1ec706ff5413a70a760b63e07d45a5d04a2f18425ef735500190291aacaf58c92306acd87fa01a47d907d5d3fc01531180353146 

recoveredKey.getAlgorithm()=ECDSA 

Key recovery ok 
Key algorithms do not match 

Trả lời

5

Vấn đề không phải là PEMParser nhưng JcaPEMKeyConverter mà đối xử với phím EC như phím cho ECDSA:

algorithms.put(X9ObjectIdentifiers.id_ecPublicKey, "ECDSA"); 
... 
private KeyFactory getKeyFactory(AlgorithmIdentifier algId) 
throws NoSuchAlgorithmException, NoSuchProviderException 
{ 
    ASN1ObjectIdentifier algorithm = algId.getAlgorithm(); 
    String algName = (String)algorithms.get(algorithm); 
... 

Mã định danh thuật toán là id-ecPublicKey, cũng được sử dụng cho các khóa ECDSA, do đó lựa chọn thuật toán không phải là duy nhất ở đây và có lẽ các nhà phát triển BC đã chọn ECDSA là sự lựa chọn phù hợp nhất. Bạn có thể làm một cái gì đó tương tự như JcaPEMKeyConverter với bạn sở hữu KeyFactory nhưng chọn thuật toán chính xác của bạn cho các phím EC.

Các vấn đề liên quan