Java&keytool生成RSA密钥

   工作中需要使用非对称加密RSA来进行消息摘要生产和验证,但无法通过keytool工具来提取私钥。

        那怎么获得私钥、公钥?

        以Java为例:通过KeyStore类getEntry() 或者getKey()来提取私钥;通过Certificate类getPublicKey()获取公钥。

一.Keytool生成KeyStore文件

Cmd代码 

 收藏代码

  1. --  生成密码仓库test.store  
  2. eytool -genkey -v -alias test -dname "CN=test,OU=HE,O=CUI,L=SHENGZHEN,ST=GUANGDONG,C=CN" -keyalg RSA -keysize 2048 -keypass 5201314 -keystore test.store -storepass 5201314 -validity 10000 -storetype JCEKS  
  3. --  导出证书test.crt  
  4. eytool -exportcert -alias test -file test.crt -keystore test.store -storepass 5201314 -rfc -storetype JCEKS  

        运行后在F盘的Key目录下将产生如下两个文件。

 

二.生成私钥、公钥

KeyStoreHelper.java

Java代码 

 收藏代码

  1. package com.bijian.keystore;  
  2.   
  3. import java.io.FileInputStream;  
  4. import java.io.FileNotFoundException;  
  5. import java.io.FileOutputStream;  
  6. import java.io.InputStream;  
  7. import java.io.ObjectOutputStream;  
  8. import java.security.KeyStore;  
  9. import java.security.PrivateKey;  
  10. import java.security.PublicKey;  
  11. import java.security.cert.Certificate;  
  12. import java.security.cert.CertificateException;  
  13. import java.security.cert.CertificateFactory;  
  14.   
  15. import sun.misc.BASE64Encoder;  
  16.   
  17. public class KeyStoreHelper {  
  18.       
  19.     public static void main(String[] args) throws Exception {  
  20.           
  21.         String privatePath = "F:/Key/testPri.key"; // 准备导出的私钥  
  22.         String publicPath = "F:/Key/testPub.key"; // 准备导出的公钥  
  23.         PrivateKey privateKey = getPrivateKeyFromStore();  
  24.         createKeyFile(privateKey, privatePath);  
  25.         PublicKey publicKey = getPublicKeyFromCrt();  
  26.         createKeyFile(publicKey, publicPath);  
  27.           
  28.         byte[] publicKeyBytes = publicKey.getEncoded();  
  29.         byte[] privateKeyBytes = privateKey.getEncoded();  
  30.   
  31.         String publicKeyBase64 = new BASE64Encoder().encode(publicKeyBytes);  
  32.         String privateKeyBase64 = new BASE64Encoder().encode(privateKeyBytes);  
  33.   
  34.         System.out.println("publicKeyBase64.length():" + publicKeyBase64.length());  
  35.         System.out.println("publicKeyBase64:" + publicKeyBase64);  
  36.   
  37.         System.out.println("privateKeyBase64.length():" + privateKeyBase64.length());  
  38.         System.out.println("privateKeyBase64:" + privateKeyBase64);  
  39.     }  
  40.   
  41.     private static PrivateKey getPrivateKeyFromStore() throws Exception {  
  42.         String alias = "test"; // KeyTool中生成KeyStore时设置的alias  
  43.         String storeType = "JCEKS"; // KeyTool中生成KeyStore时设置的storetype  
  44.         char[] pw = "5201314".toCharArray(); // KeyTool中生成KeyStore时设置的storepass  
  45.         String storePath = "F:/Key/test.store"; // KeyTool中已生成的KeyStore文件  
  46.         storeType = null == storeType ? KeyStore.getDefaultType() : storeType;  
  47.         KeyStore keyStore = KeyStore.getInstance(storeType);  
  48.         InputStream is = new FileInputStream(storePath);  
  49.         keyStore.load(is, pw);  
  50.         // 由密钥库获取密钥的两种方式  
  51.         // KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias, new KeyStore.PasswordProtection(pw));  
  52.         // return pkEntry.getPrivateKey();  
  53.         return (PrivateKey) keyStore.getKey(alias, pw);  
  54.     }  
  55.   
  56.     private static PublicKey getPublicKeyFromCrt() throws CertificateException, FileNotFoundException {  
  57.         String crtPath = "F:/Key/test.crt"; // KeyTool中已生成的证书文件  
  58.         CertificateFactory cf = CertificateFactory.getInstance("X.509");  
  59.         FileInputStream in = new FileInputStream(crtPath);  
  60.         Certificate crt = cf.generateCertificate(in);  
  61.         PublicKey publicKey = crt.getPublicKey();  
  62.         return publicKey;  
  63.     }  
  64.   
  65.     private static void createKeyFile(Object key, String filePath) throws Exception {  
  66.         FileOutputStream fos = new FileOutputStream(filePath);  
  67.         ObjectOutputStream oos = new ObjectOutputStream(fos);  
  68.         oos.writeObject(key);  
  69.         oos.flush();  
  70.         oos.close();  
  71.     }  
  72. }  

        运行上面的代码后,将在F盘的Key目录下新产生testPub.key、testPri.key公私钥文件。


        并在控制台输出如下内容:


        到此为止,公私钥已生成。

 

三.验证上面生成的公私钥

1.私钥加签公钥验签,进行验证

DigestUtil.java

Java代码 

 收藏代码

  1. package com.bijian.keystore;  
  2.   
  3. public class DigestUtil {  
  4.   
  5.     /** 
  6.      * 字节转为十六进制字符串 
  7.      * @param字节 
  8.      * @return 十六进制字符串 
  9.      */  
  10.     public static String byte2hex(byte[] b) {  
  11.         String hs = "";  
  12.         String stmp = "";  
  13.         for (int n = 0; b != null && n < b.length; n++) {  
  14.             stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));  
  15.             if (stmp.length() == 1)  
  16.                 hs = hs + "0" + stmp;  
  17.             else  
  18.                 hs = hs + stmp;  
  19.         }  
  20.         return hs;  
  21.     }  
  22.   
  23.     /** 
  24.      * 十六进制字符转为字节 
  25.      * @param 十六进制字符 
  26.      * @return  字节 
  27.      */  
  28.     public static byte[] hex2byte(byte[] b) {  
  29.         if ((b.length % 2) != 0)  
  30.             throw new IllegalArgumentException("byte length is not correct");  
  31.         byte[] b2 = new byte[b.length / 2];  
  32.         for (int n = 0; n < b.length; n += 2) {  
  33.             String item = new String(b, n, 2);  
  34.             b2[n / 2] = (byte) Integer.parseInt(item, 16);  
  35.         }  
  36.         return b2;  
  37.     }  
  38.   
  39.     /** 
  40.      * 字符串转换成十六进制值 
  41.      * @param bin String 我们看到的要转换成十六进制的字符串 
  42.      * @return 
  43.     */  
  44.     public static String bin2hex(String bin) {  
  45.         char[] digital = "0123456789ABCDEF".toCharArray();  
  46.         StringBuffer sb = new StringBuffer("");  
  47.         byte[] bs = bin.getBytes();  
  48.         int bit;  
  49.         for (int i = 0; i < bs.length; i++) {  
  50.             bit = (bs[i] & 0x0f0) >> 4;  
  51.             sb.append(digital[bit]);  
  52.             bit = bs[i] & 0x0f;  
  53.             sb.append(digital[bit]);  
  54.         }  
  55.         return sb.toString();  
  56.     }  
  57. }  

SignUtil.java

Java代码 

 收藏代码

  1. package com.bijian.keystore;  
  2.   
  3. import java.security.KeyFactory;  
  4. import java.security.PrivateKey;  
  5. import java.security.spec.PKCS8EncodedKeySpec;  
  6.   
  7. import org.apache.commons.codec.binary.Base64;  
  8.   
  9. public class SignUtil {  
  10.       
  11.     //#priKeyText  
  12.     private final static String priKeyText = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQChXmxaPt6Qg+XTiqaCG1cZEKwGPbKy/Qs5xGNx4HotngGUM2n/5FdZtSHZofJWsNUUKpZa+BynhNg0E0Qn4Xrp0WSi+Z5LgDewT7DeA0b5Cky386MEWwc11Asa+SuMiR5XFUjXdWrMQX5E7wVRcbuoq7A8QBfm3i8F4PdMokhlMviwhLngKOrWVKobE8cyA25Jv2FZgxv1NzVZ7zyGaO60a49X/NaA2poe5OB9zXBfsa8kfHl0b+sMQMd38uVrtCIqs2KABW6EGTToezk55i+hHg7nqMLum7Xtw8z/T1fpEtKgsnKANph7eqRHVHmjUDpHidx3BiTAArw07MVIq1LhAgMBAAECggEADJPDdjU4O6NMInTIDZP78eQuxD3C09iNK293IMUSQMPz840eUeeGN2O6w6+vp7oYoX3AQk7cTOI5x7VItqMIZXkAkwNJpzDTJlbPvj4bJgX7fMrshcZihXuFchDBqC53wunRx5lLPahNIypOC88FhVv8XHXSZxgiKh8ip0JuyhRS38TDVCcrIzKclsSY9CT3kYhVdPkfWEEGSb0qj7J4VxK7evE6yQD0/UJqB9j54Ts418DsEHNOZPDf6PFgNgl585AQZ3KpEUrfsx3rygLhUG+GQD+bkkDExA7vJlw5v1CF7Kr1T/XK9gjqRbRBjtzLy0MUe11ips3OM5LYkNv/EQKBgQDuWD+i64alAdXeReJAHWU8sQjZgmZYhlMhxfq8rsalJ490br3joZ2+KHXD7yDmvTUj0IFre99BcB7hi9Sx0joOjyS8+Rz7Bw02bdnwJbva5SYg3XojqdEoKGl5nFN67rL762jGsDG2Y5/hVEe/vxmH9sWB/OvQZ10If3p5OJ/jcwKBgQCtUnl1IWn57xHzqDqQEIMlCskGRXElMYdU/jtADLTt27DgSjzbgW5GgGMectvDDxYADYb93VUuTvz4EvHXAwo3CepDUjs4JtkGZeaAnMCER6doIyXPfRsxHMXRN4NgG70yEA5u7IfYFA1DuGLDwjddg4rU122ftqUM2UcwaaBjWwKBgQC9R9wRuFXPiOudf4Y0QKP7VOSgSAybVOGEOsPrQCmFUyt73c5zjg/Fyj/sAGXymGQxMw70mwUr5KzBldit9zQgB9G3OWaofGsjxI2FR5IuPjjPdNPgqqXt7FoHN/yb7iC6K7Ojxp1UKT35JoNsZYkTDwi/OGrVsKCTdRmAV1WyvQKBgBZD6Qxt/XI5DwJREyzcoixJBWgD1bQkd7Eoc64Xs8p2lXNKtiSwrNzrs0//C1I0huv80OGd5EptpTutG1o2rsJBSNHbJ3ZgLzMONh1Bhc24cr4C/eF4vdyCSLtGuV7IUXaz71a6lfzhHo8bibyCH6CovFX5UsDYsr1C0E1c1FjPAoGAXQ4hZ7/APQ/V1wmkZnplGchbXefqixvhDZWUvIAy6sAmypaRe3fRjd3SFLGXhOg48CQ59A0P3dQjKja8U7eQA6c6qw9Ci4F/cceHcdgnH6fOkqiHMdN6Sr0/SinbVP0kqU25y+AbRdJjwYZGTmWeqMdFUra+MVK9befn+hA3zAk=";  
  13.       
  14.     //#pubKeyText  
  15.     private final static String pubKeyText = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoV5sWj7ekIPl04qmghtXGRCsBj2ysv0LOcRjceB6LZ4BlDNp/+RXWbUh2aHyVrDVFCqWWvgcp4TYNBNEJ+F66dFkovmeS4A3sE+w3gNG+QpMt/OjBFsHNdQLGvkrjIkeVxVI13VqzEF+RO8FUXG7qKuwPEAX5t4vBeD3TKJIZTL4sIS54Cjq1lSqGxPHMgNuSb9hWYMb9Tc1We88hmjutGuPV/zWgNqaHuTgfc1wX7GvJHx5dG/rDEDHd/Lla7QiKrNigAVuhBk06Hs5OeYvoR4O56jC7pu17cPM/09X6RLSoLJygDaYe3qkR1R5o1A6R4ncdwYkwAK8NOzFSKtS4QIDAQAB";  
  16.       
  17.     private final static String CHARACTER_ENCODING_UTF_8 = "UTF-8";  
  18.       
  19.     public static void main(String[] args) {  
  20.           
  21.         String signString = "bijian 您好!";  
  22.         try {  
  23.             // 加签  
  24.             String localSignature = SignUtil.sign(priKeyText.getBytes(CHARACTER_ENCODING_UTF_8), signString);  
  25.             System.out.println(localSignature);  
  26.             //验签  
  27.             boolean verifyResult = SignUtil.verify(pubKeyText.getBytes(CHARACTER_ENCODING_UTF_8), signString, localSignature);  
  28.             System.out.println("verifyResult:" + verifyResult);  
  29.         } catch (Exception e) {  
  30.             // TODO Auto-generated catch block  
  31.             e.printStackTrace();  
  32.         }  
  33.     }  
  34.       
  35.     /** 
  36.      * RSA私钥加签 
  37.      * @param priKeyText经过base64处理后的私钥 
  38.      * @param plainText明文内容 
  39.      * @return 十六进制的签名字符串 
  40.      * @throws Exception  
  41.      */  
  42.     public static String sign(byte[] priKeyText, String plainText) throws Exception {  
  43.         try {  
  44.             PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(priKeyText));  
  45.             KeyFactory keyf = KeyFactory.getInstance("RSA");  
  46.             PrivateKey prikey = keyf.generatePrivate(priPKCS8);  
  47.   
  48.             // 用私钥对信息生成数字签名  
  49.             java.security.Signature signet = java.security.Signature.getInstance("SHA256withRSA");  
  50.             signet.initSign(prikey);  
  51.             signet.update(plainText.getBytes("UTF-8"));  
  52.             return DigestUtil.byte2hex(signet.sign());  
  53.         } catch (Exception e) {  
  54.             throw e;   
  55.         }  
  56.     }  
  57.       
  58.     /** 
  59.      * 公钥验签 
  60.      * @param pubKeyText经过base64处理后的公钥 
  61.      * @param plainText明文内容 
  62.      * @param signText十六进制的签名字符串 
  63.      * @return 验签结果 true验证一致 false验证不一致 
  64.      */  
  65.     public static boolean verify(byte[] pubKeyText, String plainText, String signText) {  
  66.         try {  
  67.             // 解密由base64编码的公钥,并构造X509EncodedKeySpec对象  
  68.             java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec(  
  69.                     Base64.decodeBase64(pubKeyText));  
  70.             // RSA算法  
  71.             java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA");  
  72.             // 取公钥匙对象  
  73.             java.security.PublicKey pubKey = keyFactory.generatePublic(bobPubKeySpec);  
  74.             // 十六进制数字签名转为字节  
  75.             byte[] signed = DigestUtil.hex2byte(signText.getBytes("UTF-8"));  
  76.             java.security.Signature signatureChecker = java.security.Signature.getInstance("SHA256withRSA");  
  77.             signatureChecker.initVerify(pubKey);  
  78.             signatureChecker.update(plainText.getBytes("UTF-8"));  
  79.             // 验证签名是否正常  
  80.             return signatureChecker.verify(signed);  
  81.         } catch (Throwable e) {  
  82.             return false;  
  83.         }  
  84.     }  
  85. }  

        运行结果如下,验签通过。

 

2.将F:\Key下生成公私钥验证加解密

        将F:\Key下的testPub.key、testPri.key拷贝至工程中

        运行如下代码

Java代码 

 收藏代码

  1. package com.bijian.keystore;  
  2.   
  3. import java.io.FileInputStream;  
  4. import java.io.IOException;  
  5. import java.io.ObjectInputStream;  
  6. import java.security.Key;  
  7.   
  8. import javax.crypto.Cipher;  
  9.   
  10. import sun.misc.BASE64Decoder;  
  11. import sun.misc.BASE64Encoder;  
  12.   
  13. public class RSAUtil2 {  
  14.       
  15.     /** 指定加密算法为RSA */  
  16.     private static final String ALGORITHM = "RSA";  
  17.     /** 指定公钥存放文件 */  
  18.     private static String PUBLIC_KEY_FILE = "testPub.key";  
  19.     /** 指定私钥存放文件 */  
  20.     private static String PRIVATE_KEY_FILE = "testPri.key";  
  21.   
  22.     public static void main(String[] args) throws Exception {  
  23.           
  24.         String source = "深圳,你好!";// 要加密的字符串  
  25.         System.out.println("准备用公钥加密的字符串为:" + source);  
  26.           
  27.         String cryptograph = encrypt(source);// 生成的密文  
  28.         System.out.print("用公钥加密后的结果为:" + cryptograph);  
  29.         System.out.println();  
  30.          
  31.         String target = decrypt(cryptograph);// 解密密文  
  32.         System.out.println("用私钥解密后的字符串为:" + target);  
  33.         System.out.println();     
  34.     }  
  35.       
  36.     /** 
  37.      * 加密方法 
  38.      * @param source 源数据 
  39.      * @return 
  40.      * @throws Exception 
  41.      */  
  42.     public static String encrypt(String source) throws Exception {  
  43.           
  44.         Key publicKey = getKey(PUBLIC_KEY_FILE);  
  45.   
  46.         /** 得到Cipher对象来实现对源数据的RSA加密 */  
  47.         Cipher cipher = Cipher.getInstance(ALGORITHM);  
  48.         cipher.init(Cipher.ENCRYPT_MODE, publicKey);  
  49.         byte[] b = source.getBytes();  
  50.         /** 执行加密操作 */  
  51.         byte[] b1 = cipher.doFinal(b);  
  52.         BASE64Encoder encoder = new BASE64Encoder();  
  53.         return encoder.encode(b1);  
  54.     }  
  55.   
  56.     /** 
  57.      * 解密算法 
  58.      * @param cryptograph    密文 
  59.      * @return 
  60.      * @throws Exception 
  61.      */  
  62.     public static String decrypt(String cryptograph) throws Exception {  
  63.           
  64.         Key privateKey = getKey(PRIVATE_KEY_FILE);  
  65.   
  66.         /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */  
  67.         Cipher cipher = Cipher.getInstance(ALGORITHM);  
  68.         cipher.init(Cipher.DECRYPT_MODE, privateKey);  
  69.         BASE64Decoder decoder = new BASE64Decoder();  
  70.         byte[] b1 = decoder.decodeBuffer(cryptograph);  
  71.   
  72.         /** 执行解密操作 */  
  73.         byte[] b = cipher.doFinal(b1);  
  74.         return new String(b);  
  75.     }  
  76.       
  77.     private static Key getKey(String fileName) throws Exception, IOException {  
  78.         Key key;  
  79.         ObjectInputStream ois = null;  
  80.         try {  
  81.             /** 将文件中的私钥对象读出 */  
  82.             ois = new ObjectInputStream(new FileInputStream(fileName));  
  83.             key = (Key) ois.readObject();  
  84.         } catch (Exception e) {  
  85.             throw e;  
  86.         } finally {  
  87.             ois.close();  
  88.         }  
  89.         return key;  
  90.     }  
  91. }  

        运行结果:


 

附:sun.misc.BASE64Encoder找不到jar包的解决方法

        在MyEclipse中编写Java代码时,用到了BASE64Decoder,import sun.misc.BASE64Decoder;可是Eclipse提示: 

Access restriction: The type BASE64Decoder is not accessible due to restriction on required library C:\Program 

files\java\jre6\lib\rt.jar 

Access restriction : The constructor BASE64Decoder() is not accessible due to restriction on required library C:\Program files\java\jre6\lib\rt.jar


解决方案1(推荐): 

        只需要在project build path中先移除JRE System Library,再添加库JRE System Library,重新编译后就一切正常了。 

解决方案2:

        右键项目->属性->Java bulid path->jre System Library->access rules->resolution选择accessible,下面填上**,点击确定即可!!!

 

参考文章:http://jingyan.baidu.com/article/f3e34a12ad7acff5ea653569.html

附阿里生成公私钥的链接:https://docs.open.alipay.com/291/105971

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值