• Java中使用OpenSSL生成的RSA公私钥进行数据加解密


    当前使用的是Linux系统,已经按装使用OpenSSL软件包,

    一、使用OpenSSL来生成私钥和公钥

    1、执行命令openssl version -a 验证机器上已经安装openssl 

    1
    openssl version -a

    运行结果:

    2、生成私钥:这条命令让openssl随机生成了一份私钥,加密长度是1024位。加密长度是指理论上最大允许”被加密的信息“长度的限制,也就是明文的长度限制。随着这个参数的增大(比方说2048),允许的明文长度也会增加,但同时也会造成计算复杂度的极速增长。一般推荐的长度就是2048位

    1
    openssl genrsa -out rsa_private_key.pem 2048

     运行结果:

    生产私钥文件:rsa_private_key.pem,内容都是标准的ASCII字符,开头一行和结尾一行有明显的标记,真正的私钥数据是中间的不规则字符

      

    3、根据私钥生产公钥:rsa_public_key.pem

    1
    openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout

    运行结果:

    公钥内容:

    注意:此时的私钥还不能直接被使用,需要进行PKCS#8编码:

     4、PKCS#8编码:指明输入私钥文件为rsa_private_key.pem,输出私钥文件为pkcs8_rsa_private_key.pem,不采用任何二次加密(-nocrypt)

    1
    openssl pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt

    至此:可用的密钥对已经生成好了,私钥使用pkcs8_rsa_private_key.pem,公钥采用rsa_public_key.pem

    至此,可用的密钥对已经生成好了,私钥使用pkcs8_rsa_private_key.pem,公钥采用rsa_public_key.pem。

    最近又遇到RSA加密的需求了,而且对方要求只能使用第一步生成的未经过PKCS#8编码的私钥文件。后来查看相关文献得知第一步生成的私钥文件编码是PKCS#1格式,这种格式Java其实是支持的,只不过多写两行代码而已:

    复制代码
    RSAPrivateKeyStructure asn1PrivKey = new RSAPrivateKeyStructure((ASN1Sequence) ASN1Sequence.fromByteArray(priKeyData));  
    RSAPrivateKeySpec rsaPrivKeySpec = new RSAPrivateKeySpec(asn1PrivKey.getModulus(), asn1PrivKey.getPrivateExponent());  
    KeyFactory keyFactory= KeyFactory.getInstance("RSA");  
    PrivateKey priKey= keyFactory.generatePrivate(rsaPrivKeySpec); 
    复制代码

    首先将PKCS#1的私钥文件读取出来(注意去掉减号开头的注释内容),然后使用Base64解码读出的字符串,便得到priKeyData,也就是第一行代码中的参数。最后一行得到了私钥。接下来的用法就没什么区别了。

    二、编写Java代码实际测试

    RSA加密解密类:

    复制代码
      1 import java.io.BufferedReader;
      2 import java.io.BufferedWriter;
      3 import java.io.FileReader;
      4 import java.io.FileWriter;
      5 import java.io.IOException;
      6 import java.security.InvalidKeyException;
      7 import java.security.KeyFactory;
      8 import java.security.KeyPair;
      9 import java.security.KeyPairGenerator;
     10 import java.security.NoSuchAlgorithmException;
     11 import java.security.SecureRandom;
     12 
     13 import java.security.interfaces.RSAPrivateKey;
     14 import java.security.interfaces.RSAPublicKey;
     15 import java.security.spec.InvalidKeySpecException;
     16 import java.security.spec.PKCS8EncodedKeySpec;
     17 import java.security.spec.X509EncodedKeySpec;
     18 
     19 import javax.crypto.BadPaddingException;
     20 import javax.crypto.Cipher;
     21 import javax.crypto.IllegalBlockSizeException;
     22 import javax.crypto.NoSuchPaddingException;
     23 
     24 import org.apache.commons.codec.binary.Base64;
     25 
     26 public class RSAEncrypt {
     27     /**
     28      * 字节数据转字符串专用集合
     29      */
     30     private static final char[] HEX_CHAR = { '0', '1', '2', '3', '4', '5', '6',
     31             '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
     32 
     33     /**
     34      * 随机生成密钥对
     35      */
     36     public static void genKeyPair(String filePath) {
     37         // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
     38         KeyPairGenerator keyPairGen = null;
     39         try {
     40             keyPairGen = KeyPairGenerator.getInstance("RSA");
     41         } catch (NoSuchAlgorithmException e) {
     42             e.printStackTrace();
     43         }
     44         // 初始化密钥对生成器,密钥大小为96-1024位
     45         keyPairGen.initialize(1024,new SecureRandom());
     46         // 生成一个密钥对,保存在keyPair中
     47         KeyPair keyPair = keyPairGen.generateKeyPair();
     48         // 得到私钥
     49         RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
     50         // 得到公钥
     51         RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
     52         try {
     53             // 得到公钥字符串
     54             Base64 base64 = new Base64();
     55             String publicKeyString = new String(base64.encode(publicKey.getEncoded()));
     56             // 得到私钥字符串
     57             String privateKeyString = new String(base64.encode(privateKey.getEncoded()));
     58             // 将密钥对写入到文件
     59             FileWriter pubfw = new FileWriter(filePath + "/publicKey.keystore");
     60             FileWriter prifw = new FileWriter(filePath + "/privateKey.keystore");
     61             BufferedWriter pubbw = new BufferedWriter(pubfw);
     62             BufferedWriter pribw = new BufferedWriter(prifw);
     63             pubbw.write(publicKeyString);
     64             pribw.write(privateKeyString);
     65             pubbw.flush();
     66             pubbw.close();
     67             pubfw.close();
     68             pribw.flush();
     69             pribw.close();
     70             prifw.close();
     71         } catch (Exception e) {
     72             e.printStackTrace();
     73         }
     74     }
     75 
     76     /**
     77      * 从文件中输入流中加载公钥
     78      * 
     79      * @param in
     80      *            公钥输入流
     81      * @throws Exception
     82      *             加载公钥时产生的异常
     83      */
     84     public static String loadPublicKeyByFile(String path) throws Exception {
     85         try {
     86             BufferedReader br = new BufferedReader(new FileReader(path
     87                     + "/publicKey.keystore"));
     88             String readLine = null;
     89             StringBuilder sb = new StringBuilder();
     90             while ((readLine = br.readLine()) != null) {
     91                 sb.append(readLine);
     92             }
     93             br.close();
     94             return sb.toString();
     95         } catch (IOException e) {
     96             throw new Exception("公钥数据流读取错误");
     97         } catch (NullPointerException e) {
     98             throw new Exception("公钥输入流为空");
     99         }
    100     }
    101 
    102     /**
    103      * 从字符串中加载公钥
    104      * 
    105      * @param publicKeyStr
    106      *            公钥数据字符串
    107      * @throws Exception
    108      *             加载公钥时产生的异常
    109      */
    110     public static RSAPublicKey loadPublicKeyByStr(String publicKeyStr)
    111             throws Exception {
    112         try {
    113             Base64 base64 = new Base64();
    114             byte[] buffer = base64.decode(publicKeyStr);
    115             KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    116             X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
    117             return (RSAPublicKey) keyFactory.generatePublic(keySpec);
    118         } catch (NoSuchAlgorithmException e) {
    119             throw new Exception("无此算法");
    120         } catch (InvalidKeySpecException e) {
    121             throw new Exception("公钥非法");
    122         } catch (NullPointerException e) {
    123             throw new Exception("公钥数据为空");
    124         }
    125     }
    126 
    127     /**
    128      * 从文件中加载私钥
    129      * 
    130      * @param keyFileName
    131      *            私钥文件名
    132      * @return 是否成功
    133      * @throws Exception
    134      */
    135     public static String loadPrivateKeyByFile(String path) throws Exception {
    136         try {
    137             BufferedReader br = new BufferedReader(new FileReader(path
    138                     + "/privateKey.keystore"));
    139             String readLine = null;
    140             StringBuilder sb = new StringBuilder();
    141             while ((readLine = br.readLine()) != null) {
    142                 sb.append(readLine);
    143             }
    144             br.close();
    145             return sb.toString();
    146         } catch (IOException e) {
    147             throw new Exception("私钥数据读取错误");
    148         } catch (NullPointerException e) {
    149             throw new Exception("私钥输入流为空");
    150         }
    151     }
    152 
    153     public static RSAPrivateKey loadPrivateKeyByStr(String privateKeyStr)
    154             throws Exception {
    155         try {
    156             Base64 base64 = new Base64();
    157             byte[] buffer = base64.decode(privateKeyStr);
    158             PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
    159             KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    160             return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
    161         } catch (NoSuchAlgorithmException e) {
    162             throw new Exception("无此算法");
    163         } catch (InvalidKeySpecException e) {
    164             throw new Exception("私钥非法");
    165         } catch (NullPointerException e) {
    166             throw new Exception("私钥数据为空");
    167         }
    168     }
    169 
    170     /**
    171      * 公钥加密过程
    172      * 
    173      * @param publicKey
    174      *            公钥
    175      * @param plainTextData
    176      *            明文数据
    177      * @return
    178      * @throws Exception
    179      *             加密过程中的异常信息
    180      */
    181     public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData)
    182             throws Exception {
    183         if (publicKey == null) {
    184             throw new Exception("加密公钥为空, 请设置");
    185         }
    186         Cipher cipher = null;
    187         try {
    188             // 使用默认RSA
    189             cipher = Cipher.getInstance("RSA");
    190             // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
    191             cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    192             byte[] output = cipher.doFinal(plainTextData);
    193             return output;
    194         } catch (NoSuchAlgorithmException e) {
    195             throw new Exception("无此加密算法");
    196         } catch (NoSuchPaddingException e) {
    197             e.printStackTrace();
    198             return null;
    199         } catch (InvalidKeyException e) {
    200             throw new Exception("加密公钥非法,请检查");
    201         } catch (IllegalBlockSizeException e) {
    202             throw new Exception("明文长度非法");
    203         } catch (BadPaddingException e) {
    204             throw new Exception("明文数据已损坏");
    205         }
    206     }
    207 
    208     /**
    209      * 私钥加密过程
    210      * 
    211      * @param privateKey
    212      *            私钥
    213      * @param plainTextData
    214      *            明文数据
    215      * @return
    216      * @throws Exception
    217      *             加密过程中的异常信息
    218      */
    219     public static byte[] encrypt(RSAPrivateKey privateKey, byte[] plainTextData)
    220             throws Exception {
    221         if (privateKey == null) {
    222             throw new Exception("加密私钥为空, 请设置");
    223         }
    224         Cipher cipher = null;
    225         try {
    226             // 使用默认RSA
    227             cipher = Cipher.getInstance("RSA");
    228             cipher.init(Cipher.ENCRYPT_MODE, privateKey);
    229             byte[] output = cipher.doFinal(plainTextData);
    230             return output;
    231         } catch (NoSuchAlgorithmException e) {
    232             throw new Exception("无此加密算法");
    233         } catch (NoSuchPaddingException e) {
    234             e.printStackTrace();
    235             return null;
    236         } catch (InvalidKeyException e) {
    237             throw new Exception("加密私钥非法,请检查");
    238         } catch (IllegalBlockSizeException e) {
    239             throw new Exception("明文长度非法");
    240         } catch (BadPaddingException e) {
    241             throw new Exception("明文数据已损坏");
    242         }
    243     }
    244 
    245     /**
    246      * 私钥解密过程
    247      * 
    248      * @param privateKey
    249      *            私钥
    250      * @param cipherData
    251      *            密文数据
    252      * @return 明文
    253      * @throws Exception
    254      *             解密过程中的异常信息
    255      */
    256     public static byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData)
    257             throws Exception {
    258         if (privateKey == null) {
    259             throw new Exception("解密私钥为空, 请设置");
    260         }
    261         Cipher cipher = null;
    262         try {
    263             // 使用默认RSA
    264             cipher = Cipher.getInstance("RSA");
    265             // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
    266             cipher.init(Cipher.DECRYPT_MODE, privateKey);
    267             byte[] output = cipher.doFinal(cipherData);
    268             return output;
    269         } catch (NoSuchAlgorithmException e) {
    270             throw new Exception("无此解密算法");
    271         } catch (NoSuchPaddingException e) {
    272             e.printStackTrace();
    273             return null;
    274         } catch (InvalidKeyException e) {
    275             throw new Exception("解密私钥非法,请检查");
    276         } catch (IllegalBlockSizeException e) {
    277             throw new Exception("密文长度非法");
    278         } catch (BadPaddingException e) {
    279             throw new Exception("密文数据已损坏");
    280         }
    281     }
    282 
    283     /**
    284      * 公钥解密过程
    285      * 
    286      * @param publicKey
    287      *            公钥
    288      * @param cipherData
    289      *            密文数据
    290      * @return 明文
    291      * @throws Exception
    292      *             解密过程中的异常信息
    293      */
    294     public static byte[] decrypt(RSAPublicKey publicKey, byte[] cipherData)
    295             throws Exception {
    296         if (publicKey == null) {
    297             throw new Exception("解密公钥为空, 请设置");
    298         }
    299         Cipher cipher = null;
    300         try {
    301             // 使用默认RSA
    302             cipher = Cipher.getInstance("RSA");
    303             // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
    304             cipher.init(Cipher.DECRYPT_MODE, publicKey);
    305             byte[] output = cipher.doFinal(cipherData);
    306             return output;
    307         } catch (NoSuchAlgorithmException e) {
    308             throw new Exception("无此解密算法");
    309         } catch (NoSuchPaddingException e) {
    310             e.printStackTrace();
    311             return null;
    312         } catch (InvalidKeyException e) {
    313             throw new Exception("解密公钥非法,请检查");
    314         } catch (IllegalBlockSizeException e) {
    315             throw new Exception("密文长度非法");
    316         } catch (BadPaddingException e) {
    317             throw new Exception("密文数据已损坏");
    318         }
    319     }
    320 
    321     /**
    322      * 字节数据转十六进制字符串
    323      * 
    324      * @param data
    325      *            输入数据
    326      * @return 十六进制内容
    327      */
    328     public static String byteArrayToString(byte[] data) {
    329         StringBuilder stringBuilder = new StringBuilder();
    330         for (int i = 0; i < data.length; i++) {
    331             // 取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移
    332             stringBuilder.append(HEX_CHAR[(data[i] & 0xf0) >>> 4]);
    333             // 取出字节的低四位 作为索引得到相应的十六进制标识符
    334             stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);
    335             if (i < data.length - 1) {
    336                 stringBuilder.append(' ');
    337             }
    338         }
    339         return stringBuilder.toString();
    340     }
    341 }
    复制代码

    签名及校验类:

    复制代码
      1 import java.security.KeyFactory;
      2 import java.security.PrivateKey;
      3 import java.security.PublicKey;
      4 import java.security.spec.PKCS8EncodedKeySpec;
      5 import java.security.spec.X509EncodedKeySpec;
      6 
      7 import org.apache.commons.codec.binary.Base64;
      8 
      9 /**
     10  * RSA签名验签类
     11  */
     12 public class RSASignature {
     13 
     14     /**
     15      * 签名算法
     16      */
     17     public static final String SIGN_ALGORITHMS = "SHA1WithRSA";
     18 
     19     /**
     20      * RSA签名
     21      * 
     22      * @param content
     23      *            待签名数据
     24      * @param privateKey
     25      *            商户私钥
     26      * @param encode
     27      *            字符集编码
     28      * @return 签名值
     29      */
     30     public static String sign(String content, String privateKey, String encode) {
     31         try {
     32             Base64 base64 = new Base64();
     33             PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(base64.decode(privateKey));
     34 
     35             KeyFactory keyf = KeyFactory.getInstance("RSA");
     36             PrivateKey priKey = keyf.generatePrivate(priPKCS8);
     37 
     38             java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
     39 
     40             signature.initSign(priKey);
     41             signature.update(content.getBytes(encode));
     42 
     43             byte[] signed = signature.sign();
     44 
     45             return new String(base64.encode(signed));
     46         } catch (Exception e) {
     47             e.printStackTrace();
     48         }
     49 
     50         return null;
     51     }
     52 
     53     public static String sign(String content, String privateKey) {
     54         try {
     55             Base64 base64 = new Base64();
     56             PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(base64.decode(privateKey));
     57             KeyFactory keyf = KeyFactory.getInstance("RSA");
     58             PrivateKey priKey = keyf.generatePrivate(priPKCS8);
     59             java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
     60             signature.initSign(priKey);
     61             signature.update(content.getBytes());
     62             byte[] signed = signature.sign();
     63             return new String(base64.encode(signed));
     64         } catch (Exception e) {
     65             e.printStackTrace();
     66         }
     67         return null;
     68     }
     69 
     70     /**
     71      * RSA验签名检查
     72      * 
     73      * @param content
     74      *            待签名数据
     75      * @param sign
     76      *            签名值
     77      * @param publicKey
     78      *            分配给开发商公钥
     79      * @param encode
     80      *            字符集编码
     81      * @return 布尔值
     82      */
     83     public static boolean doCheck(String content, String sign, String publicKey, String encode) {
     84         try {
     85             KeyFactory keyFactory = KeyFactory.getInstance("RSA");
     86             Base64 base64 = new Base64();
     87             byte[] encodedKey = base64.decode(publicKey);
     88             PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
     89 
     90             java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
     91 
     92             signature.initVerify(pubKey);
     93             signature.update(content.getBytes(encode));
     94 
     95             boolean bverify = signature.verify(base64.decode(sign));
     96             return bverify;
     97 
     98         } catch (Exception e) {
     99             e.printStackTrace();
    100         }
    101 
    102         return false;
    103     }
    104 
    105     public static boolean doCheck(String content, String sign, String publicKey) {
    106         try {
    107             KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    108             Base64 base64 = new Base64();
    109             byte[] encodedKey = base64.decode(publicKey);
    110             PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
    111 
    112             java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
    113 
    114             signature.initVerify(pubKey);
    115             signature.update(content.getBytes());
    116 
    117             boolean bverify = signature.verify(base64.decode(sign));
    118             return bverify;
    119 
    120         } catch (Exception e) {
    121             e.printStackTrace();
    122         }
    123 
    124         return false;
    125     }
    126 
    127 }
    复制代码

    最后是一个MainTest:

    复制代码
     1 import org.apache.commons.codec.binary.Base64;
     2 
     3 public class MainTest {
     4 
     5     public static void main(String[] args) throws Exception {
     6         String filepath = "G:/tmp/";
     7 
     8         // RSAEncrypt.genKeyPair(filepath);
     9 
    10         Base64 base64 = new Base64();
    11 
    12         System.out.println("--------------公钥加密私钥解密过程-------------------");
    13         String plainText = "ihep_公钥加密私钥解密";
    14         // 公钥加密过程
    15         byte[] cipherData = RSAEncrypt.encrypt(RSAEncrypt.loadPublicKeyByStr(RSAEncrypt.loadPublicKeyByFile(filepath)),
    16                 plainText.getBytes());
    17         String cipher = new String(base64.encode(cipherData));
    18         // 私钥解密过程
    19         byte[] res = RSAEncrypt.decrypt(RSAEncrypt.loadPrivateKeyByStr(RSAEncrypt.loadPrivateKeyByFile(filepath)),
    20                 base64.decode(cipher));
    21         String restr = new String(res);
    22         System.out.println("原文:" + plainText);
    23         System.out.println("加密:" + cipher);
    24         System.out.println("解密:" + restr);
    25         System.out.println();
    26 
    27         System.out.println("--------------私钥加密公钥解密过程-------------------");
    28         plainText = "ihep_私钥加密公钥解密";
    29         // 私钥加密过程
    30         cipherData = RSAEncrypt.encrypt(RSAEncrypt.loadPrivateKeyByStr(RSAEncrypt.loadPrivateKeyByFile(filepath)),
    31                 plainText.getBytes());
    32         cipher = new String(base64.encode(cipherData));
    33         // 公钥解密过程
    34         res = RSAEncrypt.decrypt(RSAEncrypt.loadPublicKeyByStr(RSAEncrypt.loadPublicKeyByFile(filepath)),
    35                 base64.decode(cipher));
    36         restr = new String(res);
    37         System.out.println("原文:" + plainText);
    38         System.out.println("加密:" + cipher);
    39         System.out.println("解密:" + restr);
    40         System.out.println();
    41 
    42         System.out.println("---------------私钥签名过程------------------");
    43         String content = "ihep_这是用于签名的原始数据";
    44         String signstr = RSASignature.sign(content, RSAEncrypt.loadPrivateKeyByFile(filepath));
    45         System.out.println("签名原串:" + content);
    46         System.out.println("签名串:" + signstr);
    47         System.out.println();
    48 
    49         System.out.println("---------------公钥校验签名------------------");
    50         System.out.println("签名原串:" + content);
    51         System.out.println("签名串:" + signstr);
    52 
    53         System.out.println("验签结果:" + RSASignature.doCheck(content, signstr, RSAEncrypt.loadPublicKeyByFile(filepath)));
    54         System.out.println();
    55 
    56     }
    57 }
    复制代码

    参考:

    http://blog.csdn.net/chaijunkun/article/details/7275632

    http://blog.csdn.net/wangqiuyun/article/details/42143957

  • 相关阅读:
    (七)linux 学习 -- 键盘高级操作技巧
    (六)linux 学习 -- 从 shell 眼中看世界
    (五)linux 学习 --重定向
    (四)linux 学习 --使用命令
    (三)linux 学习 --操作文件和目录
    JavaScript封装好的方法
    覆盖Html5默认样式
    CSS的布局整理
    Vue学习笔记
    博客园添加和隐藏导航菜单
  • 原文地址:https://www.cnblogs.com/yaowen/p/9226566.html
Copyright © 2020-2023  润新知