【问题标题】:Load RSA public key from file从文件加载 RSA 公钥
【发布时间】:2012-07-09 18:42:15
【问题描述】:

我已经生成了一个私钥:

openssl genrsa [-out file] –des3

在此之后,我生成了一个公钥:

openssl rsa –pubout -in private.key [-out file]

我想用我的私钥签署一些消息,并用我的公钥验证一些其他消息,使用如下代码:

public String sign(String message) throws SignatureException{
    try {
        Signature sign = Signature.getInstance("SHA1withRSA");
        sign.initSign(privateKey);
        sign.update(message.getBytes("UTF-8"));
        return new String(Base64.encodeBase64(sign.sign()),"UTF-8");
    } catch (Exception ex) {
        throw new SignatureException(ex);
    }
}

public boolean verify(String message, String signature) throws SignatureException{
    try {
        Signature sign = Signature.getInstance("SHA1withRSA");
        sign.initVerify(publicKey);
        sign.update(message.getBytes("UTF-8"));
        return sign.verify(Base64.decodeBase64(signature.getBytes("UTF-8")));
    } catch (Exception ex) {
        throw new SignatureException(ex);
    }
}

我找到了将我的私钥转换为 PKCS8 格式并加载它的解决方案。它适用于如下代码:

public PrivateKey getPrivateKey(String filename) throws Exception {

    File f = new File(filename);
    FileInputStream fis = new FileInputStream(f);
    DataInputStream dis = new DataInputStream(fis);
    byte[] keyBytes = new byte[(int) f.length()];
    dis.readFully(keyBytes);
    dis.close();
    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory kf =
            KeyFactory.getInstance("RSA");
    return kf.generatePrivate(spec);
}

最后我的问题是:如何从文件中加载我的 RSA 公钥?

我想也许我需要将我的公钥文件转换为 x509 格式,并使用X509EncodedKeySpec。但是我该怎么做呢?

【问题讨论】:

标签: java openssl rsa


【解决方案1】:

以下是the link提供的相关信息,Zaki提供。

生成 2048 位 RSA 私钥

$ openssl genrsa -out private_key.pem 2048

将私钥转换为 PKCS#8 格式(以便 Java 可以读取)

$ openssl pkcs8 -topk8 -inform PEM -outform DER -in private_key.pem -out private_key.der -nocrypt

以 DER 格式输出公钥部分(以便 Java 可以读取)

$ openssl rsa -in private_key.pem -pubout -outform DER -out public_key.der

私钥

import java.nio.file.*;
import java.security.*;
import java.security.spec.*;

public class PrivateKeyReader {

  public static PrivateKey get(String filename)
    throws Exception {

    byte[] keyBytes = Files.readAllBytes(Paths.get(filename));

    PKCS8EncodedKeySpec spec =
      new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    return kf.generatePrivate(spec);
  }
}

公钥

import java.nio.file.*;
import java.security.*;
import java.security.spec.*;

public class PublicKeyReader {

  public static PublicKey get(String filename)
    throws Exception {
    
    byte[] keyBytes = Files.readAllBytes(Paths.get(filename));

    X509EncodedKeySpec spec =
      new X509EncodedKeySpec(keyBytes);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    return kf.generatePublic(spec);
  }
}

【讨论】:

  • 我遇到了 InvalidKeyException: invalid key format,知道吗?谢谢!
  • 当我尝试使用ssh-keygen -t rsa -b 2048 命令生成的文件时,我也得到了InvalidKeyException。使用解决方案中的命令生成的文件可以正常工作。
  • 不错。您可以使用此答案将它们设为 5 行方法以从文件中获取字节:stackoverflow.com/a/21264593/3680466
  • 很棒的答案!请注意,如果您使用.pem 格式的公钥而不是.der,则可以使用BouncyCastle 的PemReader 类对其进行解析,然后再将其传递给X509EncodedKeySpec。请记住在创建 KeyFactory 实例时还要指定 BouncyCastle 提供程序。
  • 被一个不可读的密钥发疯了。你的 pem/pk8 转换线最后有“-nocrypt”,我从来没有想过,这解决了我的问题。 +1
【解决方案2】:

这个程序几乎用公钥和私钥做所有事情。 可以得到der格式但保存原始数据(不编码base64)。 我希望这对程序员有所帮助。

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import sun.security.pkcs.PKCS8Key;
import sun.security.pkcs10.PKCS10;
import sun.security.x509.X500Name;

import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;



/**
 * @author Desphilboy
 * DorOd bar shomA barobach
 *
 */
public class csrgenerator {

    private static PublicKey publickey= null;
    private static PrivateKey privateKey=null;
    //private static PKCS8Key privateKey=null;
    private static KeyPairGenerator kpg= null;
    private static ByteArrayOutputStream bs =null;
    private static csrgenerator thisinstance;
    private KeyPair keypair;
    private static PKCS10 pkcs10;
    private String signaturealgorithm= "MD5WithRSA";

    public String getSignaturealgorithm() {
        return signaturealgorithm;
    }



    public void setSignaturealgorithm(String signaturealgorithm) {
        this.signaturealgorithm = signaturealgorithm;
    }



    private csrgenerator() {
        try {
           kpg = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            System.out.print("No such algorithm RSA in constructor csrgenerator\n");
        }
        kpg.initialize(2048);
        keypair = kpg.generateKeyPair();
        publickey = keypair.getPublic();
        privateKey = keypair.getPrivate();
    }



    /** Generates a new key pair 
    *
    * @param int bits 
    *   this is the number of bits in modulus must be 512, 1024, 2048  or so on 
    */
    public KeyPair generateRSAkys(int bits)
    {
          kpg.initialize(bits);
            keypair = kpg.generateKeyPair();
            publickey = keypair.getPublic();
            privateKey = keypair.getPrivate();
            KeyPair dup= keypair;
     return dup;
    }

     public static csrgenerator getInstance() {
            if (thisinstance == null)
                thisinstance = new csrgenerator();
            return thisinstance;
        }


     /**
      *  Returns a CSR as string  
      * @param cn  Common Name
      * @param OU  Organizational Unit 
      * @param Org  Organization
      * @param LocName Location name
      * @param Statename  State/Territory/Province/Region
      * @param Country    Country
      * @return     returns  csr as string.
      * @throws Exception
      */
     public String getCSR(String commonname, String organizationunit, String organization,String localname, String statename, String country ) throws Exception {
            byte[] csr = generatePKCS10(commonname, organizationunit, organization, localname, statename, country,signaturealgorithm);
            return new String(csr);
        }

     /** This function generates a new Certificate 
      * Signing Request. 
     *
     * @param CN
     *            Common Name, is X.509 speak for the name that distinguishes
     *            the Certificate best, and ties it to your Organization
     * @param OU
     *            Organizational unit
     * @param O
     *            Organization NAME
     * @param L
     *            Location
     * @param S
     *            State
     * @param C
     *            Country
     * @return    byte stream of generated request
     * @throws Exception
     */
    private static byte[] generatePKCS10(String CN, String OU, String O,String L, String S, String C,String sigAlg) throws Exception {
        // generate PKCS10 certificate request

        pkcs10 = new PKCS10(publickey);
       Signature   signature = Signature.getInstance(sigAlg);
        signature.initSign(privateKey);
        // common, orgUnit, org, locality, state, country
        //X500Name(String commonName, String organizationUnit,String organizationName,Local,State, String country)
        X500Name x500Name = new X500Name(CN, OU, O, L, S, C);
        pkcs10.encodeAndSign(x500Name,signature);
        bs = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(bs);
        pkcs10.print(ps);
        byte[] c = bs.toByteArray();
        try {
            if (ps != null)
                ps.close();
            if (bs != null)
                bs.close();
        } catch (Throwable th) {
        }
        return c;
    }

    public  PublicKey getPublicKey() {
        return publickey;
    }




    /**
     * @return
     */
    public PrivateKey getPrivateKey() {
        return privateKey;
    }

    /**
     * saves private key to a file
     * @param filename
     */
    public  void SavePrivateKey(String filename)
    {
        PKCS8EncodedKeySpec pemcontents=null;
        pemcontents= new PKCS8EncodedKeySpec( privateKey.getEncoded());
        PKCS8Key pemprivatekey= new  PKCS8Key( );
        try {
            pemprivatekey.decode(pemcontents.getEncoded());
        } catch (InvalidKeyException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        File file=new File(filename);
        try {

            file.createNewFile();
            FileOutputStream fos=new FileOutputStream(file);
            fos.write(pemprivatekey.getEncoded());
            fos.flush();
            fos.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }



    }



    /**
     * Saves Certificate Signing Request to a file;
     * @param filename  is a String containing full path to the file which will be created containing the CSR.
     */
    public void SaveCSR(String filename)
    {
        FileOutputStream fos=null;
        PrintStream ps=null;
        File file;
        try {

            file = new File(filename);
            file.createNewFile();
            fos = new FileOutputStream(file);
            ps= new PrintStream(fos);
        }catch (IOException e)
        {
            System.out.print("\n could not open the file "+ filename);
        }

        try {
            try {
                pkcs10.print(ps);
            } catch (SignatureException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            ps.flush();
            ps.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            System.out.print("\n cannot write to the file "+ filename);
            e.printStackTrace();

        }

        }


    /**
     * Saves both public key and private  key to file names specified
     * @param fnpub  file name of public key
     * @param fnpri  file name of private key
     * @throws IOException
     */
    public static void SaveKeyPair(String fnpub,String fnpri) throws IOException { 

// Store Public Key.
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
publickey.getEncoded());
FileOutputStream fos = new FileOutputStream(fnpub);
fos.write(x509EncodedKeySpec.getEncoded());
fos.close();

// Store Private Key.
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
fos = new FileOutputStream(fnpri);
fos.write(pkcs8EncodedKeySpec.getEncoded());
fos.close();
}


    /**
     * Reads a Private Key from a pem base64 encoded file.
     * @param filename name of the file to read.
     * @param algorithm Algorithm is usually "RSA"
     * @return returns the privatekey which is read from the file;
     * @throws Exception
     */
    public  PrivateKey getPemPrivateKey(String filename, String algorithm) throws Exception {
          File f = new File(filename);
          FileInputStream fis = new FileInputStream(f);
          DataInputStream dis = new DataInputStream(fis);
          byte[] keyBytes = new byte[(int) f.length()];
          dis.readFully(keyBytes);
          dis.close();

          String temp = new String(keyBytes);
          String privKeyPEM = temp.replace("-----BEGIN PRIVATE KEY-----", "");
          privKeyPEM = privKeyPEM.replace("-----END PRIVATE KEY-----", "");
          //System.out.println("Private key\n"+privKeyPEM);

          BASE64Decoder b64=new BASE64Decoder();
          byte[] decoded = b64.decodeBuffer(privKeyPEM);

          PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);
          KeyFactory kf = KeyFactory.getInstance(algorithm);
          return kf.generatePrivate(spec);
          }



    /**
     * Saves the private key to a pem file.
     * @param filename  name of the file to write the key into 
     * @param key the Private key to save.
     * @return  String representation of the pkcs8 object.
     * @throws Exception
     */
    public  String  SavePemPrivateKey(String filename) throws Exception {
        PrivateKey key=this.privateKey;
          File f = new File(filename);
          FileOutputStream fos = new FileOutputStream(f);
          DataOutputStream dos = new DataOutputStream(fos);


          byte[] keyBytes = key.getEncoded();
          PKCS8Key pkcs8= new PKCS8Key();
          pkcs8.decode(keyBytes);
          byte[] b=pkcs8.encode();

          BASE64Encoder b64=new BASE64Encoder();
          String  encoded = b64.encodeBuffer(b);

          encoded= "-----BEGIN PRIVATE KEY-----\r\n" + encoded + "-----END PRIVATE KEY-----";

         dos.writeBytes(encoded);
         dos.flush();
         dos.close();

          //System.out.println("Private key\n"+privKeyPEM);
        return pkcs8.toString();

          }


    /**
     * Saves a public key to a base64 encoded pem file
     * @param filename  name of the file 
     * @param key public key to be saved 
     * @return string representation of the pkcs8 object.
     * @throws Exception
     */
    public  String  SavePemPublicKey(String filename) throws Exception {
        PublicKey key=this.publickey;  
        File f = new File(filename);
          FileOutputStream fos = new FileOutputStream(f);
          DataOutputStream dos = new DataOutputStream(fos);


          byte[] keyBytes = key.getEncoded();
          BASE64Encoder b64=new BASE64Encoder();
          String  encoded = b64.encodeBuffer(keyBytes);

          encoded= "-----BEGIN PUBLIC KEY-----\r\n" + encoded + "-----END PUBLIC KEY-----";

         dos.writeBytes(encoded);
         dos.flush();
         dos.close();

          //System.out.println("Private key\n"+privKeyPEM);
      return  encoded.toString();

          }





       /**
     * reads a public key from a file
     * @param filename name of the file to read
     * @param algorithm is usually RSA
     * @return the read public key
     * @throws Exception
     */
    public  PublicKey getPemPublicKey(String filename, String algorithm) throws Exception {
          File f = new File(filename);
          FileInputStream fis = new FileInputStream(f);
          DataInputStream dis = new DataInputStream(fis);
          byte[] keyBytes = new byte[(int) f.length()];
          dis.readFully(keyBytes);
          dis.close();

          String temp = new String(keyBytes);
          String publicKeyPEM = temp.replace("-----BEGIN PUBLIC KEY-----\n", "");
          publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", "");


          BASE64Decoder b64=new BASE64Decoder();
          byte[] decoded = b64.decodeBuffer(publicKeyPEM);

          X509EncodedKeySpec spec =
                new X509EncodedKeySpec(decoded);
          KeyFactory kf = KeyFactory.getInstance(algorithm);
          return kf.generatePublic(spec);
          }




    public static void main(String[] args) throws Exception {
        csrgenerator gcsr = csrgenerator.getInstance();
        gcsr.setSignaturealgorithm("SHA512WithRSA");
        System.out.println("Public Key:\n"+gcsr.getPublicKey().toString());

        System.out.println("Private Key:\nAlgorithm: "+gcsr.getPrivateKey().getAlgorithm().toString());
        System.out.println("Format:"+gcsr.getPrivateKey().getFormat().toString());
        System.out.println("To String :"+gcsr.getPrivateKey().toString());
        System.out.println("GetEncoded :"+gcsr.getPrivateKey().getEncoded().toString());
        BASE64Encoder encoder= new BASE64Encoder();
        String s=encoder.encodeBuffer(gcsr.getPrivateKey().getEncoded());
        System.out.println("Base64:"+s+"\n");

        String csr = gcsr.getCSR( "desphilboy@yahoo.com","baxshi az xodam", "Xodam","PointCook","VIC" ,"AU");
        System.out.println("CSR Request Generated!!");
        System.out.println(csr);
        gcsr.SaveCSR("c:\\testdir\\javacsr.csr");
        String p=gcsr.SavePemPrivateKey("c:\\testdir\\java_private.pem");
        System.out.print(p);
        p=gcsr.SavePemPublicKey("c:\\testdir\\java_public.pem");
        privateKey= gcsr.getPemPrivateKey("c:\\testdir\\java_private.pem", "RSA");
        BASE64Encoder encoder1= new BASE64Encoder();
        String s1=encoder1.encodeBuffer(gcsr.getPrivateKey().getEncoded());
        System.out.println("Private Key in Base64:"+s1+"\n");
        System.out.print(p);


    }

    }

【讨论】:

    【解决方案3】:

    将密钥存储在 PEM 文件中后,您可以使用 BouncyCastle 提供的 PemObject 和 PemReader 类轻松读取它,如 this tutorial 所示。

    创建一个封装文件处理的 PemFile 类:

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    import org.bouncycastle.util.io.pem.PemObject;
    import org.bouncycastle.util.io.pem.PemReader;
    
    public class PemFile {
    
        private PemObject pemObject;
    
        public PemFile(String filename) throws FileNotFoundException, IOException {
            PemReader pemReader = new PemReader(new InputStreamReader(
                    new FileInputStream(filename)));
            try {
                this.pemObject = pemReader.readPemObject();
            } finally {
                pemReader.close();
            }
        }
    
        public PemObject getPemObject() {
            return pemObject;
        }
    }
    

    然后像往常一样实例化私钥和公钥:

    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.security.KeyFactory;
    import java.security.NoSuchAlgorithmException;
    import java.security.NoSuchProviderException;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.Security;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    
    import org.apache.log4j.Logger;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    
    public class Main {
    
        protected final static Logger LOGGER = Logger.getLogger(Main.class);
    
        public final static String RESOURCES_DIR = "src/main/resources/rsa-sample/";
    
        public static void main(String[] args) throws FileNotFoundException,
                IOException, NoSuchAlgorithmException, NoSuchProviderException {
            Security.addProvider(new BouncyCastleProvider());
            LOGGER.info("BouncyCastle provider added.");
    
            KeyFactory factory = KeyFactory.getInstance("RSA", "BC");
            try {
                PrivateKey priv = generatePrivateKey(factory, RESOURCES_DIR
                        + "id_rsa");
                LOGGER.info(String.format("Instantiated private key: %s", priv));
    
                PublicKey pub = generatePublicKey(factory, RESOURCES_DIR
                        + "id_rsa.pub");
                LOGGER.info(String.format("Instantiated public key: %s", pub));
            } catch (InvalidKeySpecException e) {
                e.printStackTrace();
            }
        }
    
        private static PrivateKey generatePrivateKey(KeyFactory factory,
                String filename) throws InvalidKeySpecException,
                FileNotFoundException, IOException {
            PemFile pemFile = new PemFile(filename);
            byte[] content = pemFile.getPemObject().getContent();
            PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
            return factory.generatePrivate(privKeySpec);
        }
    
        private static PublicKey generatePublicKey(KeyFactory factory,
                String filename) throws InvalidKeySpecException,
                FileNotFoundException, IOException {
            PemFile pemFile = new PemFile(filename);
            byte[] content = pemFile.getPemObject().getContent();
            X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
            return factory.generatePublic(pubKeySpec);
        }
    }
    

    希望这会有所帮助。

    【讨论】:

    • 你将如何使用这个私钥来使用文件输入流?
    【解决方案4】:

    下面的代码对我来说绝对没问题并且可以正常工作。此代码将通过 java 代码读取 RSA 私钥和公钥。可以参考http://snipplr.com/view/18368/

    import java.io.DataInputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.security.KeyFactory;
    import java.security.NoSuchAlgorithmException;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
        
    public class Demo {
        public static final String PRIVATE_KEY="/home/user/private.der";
        public static final String PUBLIC_KEY="/home/user/public.der";
    
        public static void main(String[] args) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
            //get the private key
            File file = new File(PRIVATE_KEY);
            FileInputStream fis = new FileInputStream(file);
            DataInputStream dis = new DataInputStream(fis);
    
            byte[] keyBytes = new byte[(int) file.length()];
            dis.readFully(keyBytes);
            dis.close();
    
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            RSAPrivateKey privKey = (RSAPrivateKey) kf.generatePrivate(spec);
            System.out.println("Exponent :" + privKey.getPrivateExponent());
            System.out.println("Modulus" + privKey.getModulus());
    
            //get the public key
            File file1 = new File(PUBLIC_KEY);
            FileInputStream fis1 = new FileInputStream(file1);
            DataInputStream dis1 = new DataInputStream(fis1);
            byte[] keyBytes1 = new byte[(int) file1.length()];
            dis1.readFully(keyBytes1);
            dis1.close();
    
            X509EncodedKeySpec spec1 = new X509EncodedKeySpec(keyBytes1);
            KeyFactory kf1 = KeyFactory.getInstance("RSA");
            RSAPublicKey pubKey = (RSAPublicKey) kf1.generatePublic(spec1);
    
            System.out.println("Exponent :" + pubKey.getPublicExponent());
            System.out.println("Modulus" + pubKey.getModulus());
        }
    }
    

    【讨论】:

      【解决方案5】:
      @Value("${spring.security.oauth2.resourceserver.jwt.key-value}")
      RSAPublicKey key;
      

      key-value 可以是 uri(即“classpath:keys/pub.pcks8.pem”)或 pem 内容。

      您必须包括以下部门:

      compile project(':spring-security-config')
      compile project(':spring-security-oauth2-jose')
      compile project(':spring-security-oauth2-resource-server')
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-05-05
        • 2020-07-13
        • 1970-01-01
        • 2010-12-17
        • 2012-07-15
        • 2013-07-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多