web-dev-qa-db-ja.com

DER形式の文字列base64エンコーディングから秘密鍵と公開鍵を作成する

ANS1 DERを使用してエンコードされたbase64の文字列に秘密鍵と公開鍵があります。 Java PrivateKeyPublicKeyのインスタンスを作成してみました:

_byte [] llave2 = DatatypeConverter.parseBase64Binary(key);
PKCS8Key pkcs8 = new PKCS8Key( llave2, password.toCharArray()); //line 2
llave2 = pkcs8.getDecryptedBytes();                             //line 3
certificado = DatatypeConverter.parseBase64Binary(cer);

KeyFactory kf = KeyFactory.getInstance("RSA");  
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(llave2);
PrivateKey privateKey = kf.generatePrivate(ks);
X509EncodedKeySpec x = new X509EncodedKeySpec(certificado);
PublicKey publicKey = kf.generatePublic(x);
_

PublicKey publicKey = kf.generatePublic(x)で次のエラーが発生します。

_    Java.security.spec.InvalidKeySpecException: Java.security.InvalidKeyException:     IOException: ObjectIdentifier() -- data isn't an object ID (tag = -96)
    at Sun.security.rsa.RSAKeyFactory.engineGeneratePublic(Unknown Source)
    at Java.security.KeyFactory.generatePublic(Unknown Source)
    at vital.cancelaciones.GeneraXMLCancelacion.main(GeneraXMLCancelacion.Java:118)
Caused by: Java.security.InvalidKeyException: IOException: ObjectIdentifier() -- data isn't an object ID (tag = -96)
    at Sun.security.x509.X509Key.decode(Unknown Source)
    at Sun.security.x509.X509Key.decode(Unknown Source)
    at Sun.security.rsa.RSAPublicKeyImpl.<init>(Unknown Source)
    at Sun.security.rsa.RSAKeyFactory.generatePublic(Unknown Source)
    ... 3 more
_

証明書も暗号化されているため、2行目と3行目の秘密キーを使用した場合と同様に、公開キーを使用して何かを実行する必要があると思います。助言がありますか?

14
user1084509

シナリオをテストするために、opensslを使用してRSA秘密鍵を作成しました。

_openssl genrsa -out private.pem 1024
_

次に、このキーをPKCS#8 DER形式に変換しました。

_openssl pkcs8 -topk8 -inform PEM -in private.pem -outform DER -out private.der -nocrypt
_

opensslのマニュアルでは、PKCS#8とDERの両方をformatsとして参照しているため、私に関する限り、次のことが起こります。

  • _pkcs8_は、PKCS#8形式の秘密鍵を使用することをopensslに伝えます。
  • _-topk8_は、PKCS#8では_-in_で指定する秘密鍵がnotであることを示します(それ以外の場合は、そうだと思います)。
  • _-inform_および_-in_は、(PEM)秘密鍵をPKCS#8に変換することを指定します(_-topk8_を使用しない場合、PKCS#8形式の鍵をに変換しようとします標準キー形式)。
  • _-outform_および_-out_は、出力としてDER形式のキーが必要であることを示しています。
  • _-nocrypt_は、キーを暗号化しないことを通知します。

次に、RSAキー(標準形式)を使用して証明書を作成しました。

_openssl req -new -x509 -keyform PEM -key private.pem -outform DER -out public.der
_

証明書には、私の秘密鍵に対応する公開鍵が含まれています。

これらすべての後、私は秘密鍵と証明書の両方をBase64でエンコードしました。

_base64 private.der > private.der.b64
base64 public.der > public.der.b64
_

次のファイルが生成されました。

_private.pem      # standard
private.der      # pkcs8/DER
private.der.b64 
public.der       # x509/DER
public.der.b64   
_
_public static void main(String[] args) throws IOException, GeneralSecurityException {
  // get a handle on the base64 encoded key and certificate
  File privateKeyFile = new File("private.der.b64");
  File publicKeyFile = new File("public.der.b64");

  // pull them into arrays
  byte[] privateKeyBytes = toByteArray(privateKeyFile);
  byte[] publicKeyBytes = toByteArray(publicKeyFile);

  // decode them
  privateKeyBytes = toDecodedBase64ByteArray(privateKeyBytes);
  publicKeyBytes = toDecodedBase64ByteArray(publicKeyBytes);

  // get the private key
  KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  KeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
  PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

  // get the public key
  CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
  Certificate certificate = certificateFactory.generateCertificate(new ByteArrayInputStream(publicKeyBytes));
  PublicKey publicKey = certificate.getPublicKey();
}

private static byte[] toByteArray(File file) throws IOException {
  // Java 7's try-with-resources statement
  try (FileInputStream in = new FileInputStream(file);
      FileChannel channel = in.getChannel()) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    channel.transferTo(0, channel.size(), Channels.newChannel(out));
    return out.toByteArray();
  }
}

private static byte[] toDecodedBase64ByteArray(byte[] base64EncodedByteArray) {
  return DatatypeConverter.parseBase64Binary(
      new String(base64EncodedByteArray, Charset.forName("UTF-8")));
}
_

主な問題は、公開鍵の代わりに証明書があったことです。証明書には公開鍵が含まれていますが、X509EncodedKeySpec(...)でロードできないため、代わりにCertificateFactoryを使用する必要があります。

(ちなみに ここopensslとJava暗号化の使用法についての素晴らしい記事/チュートリアルです。そこから一部の情報を取得しています。)

34