如何从Java中的文件生成PublicKey对象

时间:2015-08-20 11:30:40

标签: java encryption rsa bouncycastle public-key-encryption

我有一个包含公共RSA密钥的文件(使用ssh-keygen生成)。我想阅读该文件并生成PublicKey对象。

在此之前我转换了文件,因为阅读原始文件似乎是不可能的:

# http://unix.stackexchange.com/questions/220354/how-to-convert-public-key-from-pem-to-der-format/220356#220356
ssh-keygen -f ~/.ssh/id_rsa.pub -e -m PEM > ~/.ssh/id_rsa.pub.pem
openssl rsa -RSAPublicKey_in -in ~/.ssh/id_rsa.pub.pem -inform PEM -outform DER -out ~/.ssh/id_rsa.pub.der -RSAPublicKey_out

Java - Encrypt String with existing public key file我定义了函数readFileBytes

public static byte[] readFileBytes(String filename) throws IOException {
    Path path = Paths.get(System.getProperty("user.home") + filename);
    return Files.readAllBytes(path);
}

现在我想读取文件并生成PublicKey对象,但我找不到办法做到这一点; java.security.spec.RSAPublicKeySpec未提供适合的构造函数,而java.security.spec.X509EncodedKeySpec会引发错误java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: algid parse error, not a sequence

//RSAPublicKeySpec publicSpec = new RSAPublicKeySpec(readFileBytes("/.ssh/id_rsa.pub.der"));
// No fitting construktor

X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(readFileBytes("/.ssh/id_rsa.pub.der"));
// Gives: "algid parse error, not a sequence"

2 个答案:

答案 0 :(得分:5)

我有一个项目,其中需要(RSA)加密,这是我重建publicKey给定publicKey的{​​{1}}数组的方法,来自档案。

byte

然后你可以调用类似于此调用的过程public PublicKey reconstruct_public_key(String algorithm, byte[] pub_key) { PublicKey public_key = null; try { KeyFactory kf = KeyFactory.getInstance(algorithm); EncodedKeySpec pub_key_spec = new X509EncodedKeySpec(pub_key); public_key = kf.generatePublic(pub_key_spec); } catch(NoSuchAlgorithmException e) { System.out.println("Could not reconstruct the public key, the given algorithm oculd not be found."); } catch(InvalidKeySpecException e) { System.out.println("Could not reconstruct the public key"); } return public_key; }

编辑:我尝试自己做(将公钥写入文件,读取该文件并重新构建密钥)。这有效:

reconstruct_public_key("RSA", readFileBytes("path/to/your/publicKey/file"));

这是public static void main(String args[]) { String path = "./pub_key_test.txt"; // Generate a keypair to write to file KeyPair kp = generate_key(); PublicKey pub_key = kp.getPublic(); File file = new File(path); try { // Write to file file.createNewFile(); FileOutputStream out = new FileOutputStream(path); out.write(pub_key.getEncoded()); // Write public key to the file out.close(); // Read from file FileInputStream in = new FileInputStream(path); byte[] pub_key_arr = new byte[in.available()]; in.read(pub_key_arr, 0, in.available()); in.close(); // Reconstruct public key PublicKey reconstructed_pub_key = reconstruct_public_key("RSA", pub_key_arr); } catch(IOException e) { System.out.println("Could not open the file : " + e.getStackTrace()); } } 程序:

generate_key

如果您对此进行测试,您会看到public KeyPair generate_key() { while(true) { // Else the compiler will complain that this procedure does not always return a "KeyPair" try { final KeyPairGenerator key_generator = KeyPairGenerator.getInstance("RSA"); key_generator.initialize(2048); // Keys of 2048 bits (minimum key length for RSA keys) are safe enough (according to the slides 128bit keys > 16 years to brute force it) final KeyPair keys = key_generator.generateKeyPair(); return keys; } catch(NoSuchAlgorithmException e) { System.out.println("The given encryption algorithm (RSA) does not exist. -- generate_key() - Cryptography."); } } } 已成功重建。

编辑:我尝试使用publicKey工具自行完成。这就是我所做的:

  • 首先我生成了一个RSA私钥(ssh-keygen格式)
  • 将公钥部分输出为.PEM格式,因此Java可以使用它。

这就是我进行转换的方式,与你的转换有点不同:

.DER

我的文件读起来像here,与你的不同之处并不相同。我测试了这个并且Java成功地重建了公钥。

答案 1 :(得分:4)

创建RSA私钥

openssl genrsa -out rsaprivkey.pem 1024

以DER格式生成公钥。

openssl rsa -in rsaprivkey.pem -pubout -outform DER -out rsapubkey.der

我们使用此代码从X.509证书中提取公钥RSA或DSA。

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;

/**
 * This class is capable of extracting a public key from a X.509 certficate 
 * and returning the PublicKey representation from a referenced byte array.
 * 
 */
public class ExtractPublicKey {

  // Certificate Filename (Including Path Info)
  private static final String certFilename = "cacert.pem";

  // Public Key Filename (Including Path Info)
  private static final String pubKeyFilename = "rsapublic.key";

  public static PublicKey generatePublicKey(byte[] encodedKey)
      throws NoSuchAlgorithmException, InvalidKeySpecException {

    X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(encodedKey);
    boolean isSupportedKey = false;
    KeyFactory factory;
    PublicKey retKey = null;

    //first try the DSA alg
    try {
      factory = KeyFactory.getInstance("DSA");
      retKey = factory.generatePublic(pubSpec);
      isSupportedKey = true;
    } catch (InvalidKeySpecException e) {
      System.out.println("Could not create DSA Public Key: " + e.toString());      
    }

    //if DSA didnt work, then try RSA    
    if (!isSupportedKey) {
      try {
        factory = KeyFactory.getInstance("RSA");
        retKey = factory.generatePublic(pubSpec);
        isSupportedKey = true;
      } catch (InvalidKeySpecException e) {
        System.out.println("Could not create RSA Public Key: " + e.toString());
      }      
    }

    // if not DSA or RSA
    if (!isSupportedKey) {
      throw new InvalidKeySpecException("Unsupported key spec: Not RSA or DSA");
    }

    return retKey;
  }   

}