2015-01-02 29 views
7

Moja aplikacja przechowuje klucze prywatne w formacie PEM, istniejący kod działa dla kluczy RSA, ale próbuję przełączać się na klucze EC i wystąpił problem. Wydaje się, że odzyskiwanie klucza działa, a metoda equals na odzyskanym kluczu zwraca wartość true dla oryginalnego klucza, ale funkcja getAlgorithm() na oryginalnym kluczu zwraca "EC" i odzyskany klucz "ECDSA". Rozbieżność w algorytmie później powoduje problemy, ponieważ nie pasuje do algorytmu dla odpowiedniego klucza publicznego.Odzyskiwanie klucza prywatnego WE z formatu PEM z BouncyCastle

Czy robię coś nie tak, czy jest to błąd w parserze PEM?

Oto program testowy, który demonstruje problem:

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

Wyjście z programu testowego jest:

 
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 

Odpowiedz

5

Problemem nie jest PEMParser ale JcaPEMKeyConverter który traktuje klucze WE jako klucze dla 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); 
... 

Identyfikator algorytmu jest id-ecPublicKey, który jest również używany dla kluczy ECDSA, więc wybór algorytmu nie jest tutaj unikalny i prawdopodobnie twórcy BC wybrali ECDSA jako najbardziej odpowiedni wybór. Możesz zrobić coś podobnego, jak JcaPEMKeyConverter z własnym KeyFactory, ale wybierz prawidłowy algorytm dla kluczy EC.