相关术语解释:

1、私钥(PrivateKey)的生成

1.1、加载 PKCS #8 标准的PEM编码的字符串,并生成私钥(RSAPrivateKey)

关于PKCS #8: In cryptography, PKCS #8 is a standard syntax for storing private key information. PKCS #8 is one of the family of standards called Public-Key Cryptography Standards (PKCS) created by RSA Laboratories。PKCS #8 private keys are typically exchanged in the PEM base64-encoded format

  如和生成RSA PEM 格式的私钥文件以及如何转换成 PKCS #8,参考: 《通过OpenSSL来生成PEM格式的私钥、PKCS8格式的私钥、公钥|pfx格式的私钥、cer格式的公钥

私钥 PEM 内容样例如下:

-----BEGIN PRIVATE KEY-----
MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAq7BFUpkGp3+LQmlQ
Yx2eqzDV+xeG8kx/sQFV18S5JhzGeIJNA72wSeukEPojtqUyX2J0CciPBh7eqclQ
2zpAswIDAQABAkAgisq4+zRdrzkwH1ITV1vpytnkO/NiHcnePQiOW0VUybPyHoGM
/jf75C5xET7ZQpBe5kx5VHsPZj0CBb3b+wSRAiEA2mPWCBytosIU/ODRfq6EiV04
lt6waE7I2uSPqIC20LcCIQDJQYIHQII+3YaPqyhGgqMexuuuGx+lDKD6/Fu/JwPb
5QIhAKthiYcYKlL9h8bjDsQhZDUACPasjzdsDEdq8inDyLOFAiEAmCr/tZwA3qeA
ZoBzI10DGPIuoKXBd3nk/eBxPkaxlEECIQCNymjsoI7GldtujVnr1qT+3yedLfHK
srDVjIT3LsvTqw==
-----END PRIVATE KEY-----

使用下面的方法来生成私钥(RSAPrivateKey)需要删除上面的“-----BEGIN PRIVATE KEY-----” 和“-----END PRIVATE KEY-----”

Java 代码:

package rsa;

import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import org.apache.commons.codec.binary.Base64; @UtilityClass
public class PrivateKeyGen { /**
* 加载 PKCS8 私钥证书(PEM base64-encoded format)
* <br/> PKCS #8 is a standard syntax for storing private key information.
* <br/> PKCS #8 is one of the family of standards called Public-Key Cryptography Standards (PKCS) created by RSA Laboratories.
*
* @param privateKeyPem 私钥文件内容(PEM Base64编码)
*/
@SneakyThrows
public static RSAPrivateKey getPrivateKey(String privateKeyPem){
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyPem));
return (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
} }

1.2、加载 PFX(PKCS #12 标准)文件并生成私钥(PrivateKey)

java代码:

package rsa;

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import lombok.Cleanup;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass; @UtilityClass
public class PrivateKeyGen { /**
* 读取 PFX 格式的证书文件并生成 {@link PrivateKey} 类型实例
*
* @param keyStorePath PFX 格式的证书文件路径
* @param keyStorePasswd KeyStroe 的 password
*/
@SneakyThrows
public static PrivateKey getPrivateKey(String keyStorePath, String keyStorePasswd) {
@Cleanup FileInputStream fis = new FileInputStream(keyStorePath);
KeyStore store = KeyStore.getInstance("PKCS12");
store.load(fis, keyStorePasswd.toCharArray());
String alia = store.aliases().nextElement();
return (PrivateKey) store.getKey(alia, keyStorePasswd.toCharArray());
} }

1.3、根据证书的模(Modulus)和指数(Exponent)来生成私钥(PrivateKey)

import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.RSAPrivateKeySpec;
import lombok.SneakyThrows; /**
* @author xfyou
*/
public class RsaPrivateKey { @SneakyThrows
private Key generatePrivateKey(byte[] keyModulus, byte[] keyExponent) {
return KeyFactory.getInstance("RSA").generatePrivate(new RSAPrivateKeySpec(newBigInteger(keyModulus), newBigInteger(keyExponent)));
} private static BigInteger newBigInteger(byte[] keyInfo) {
return new BigInteger(1, keyInfo);
} }

2、公钥(PublicKey)的生成

2.1、加载 PFX(PKCS #12 标准)文件并生成(导出)公钥(PublicKey)

Java代码:

package rsa;

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PublicKey;
import lombok.Cleanup;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass; /**
* KeyGen
*/
@UtilityClass
public class KeyGen { /**
* 读取 PFX 格式的证书文件并生成 {@link PublicKey} 类型实例
*
* @param keyStorePath PFX 格式的证书文件路径
* @param keyStorePasswd KeyStroe 的 password
*/
@SneakyThrows
public static PublicKey getPublicKey(String keyStorePath, String keyStorePasswd) {
@Cleanup FileInputStream fis = new FileInputStream(keyStorePath);
KeyStore store = KeyStore.getInstance("PKCS12");
store.load(fis, keyStorePasswd.toCharArray());
String alia = store.aliases().nextElement();
return store.getCertificate(alia).getPublicKey();
} }

2.2、加载 符合 X.509 国际标准 PEM base64-encoded format 的证书内容,并生成公钥(RSAPublicKey)

需要删除证书内容(字符串)中的 “-----BEGIN CERTIFICATE-----” 和 “-----END CERTIFICATE-----”

公钥 PEM 证书内容样例如下:

-----BEGIN CERTIFICATE-----

MIIC6DCCAlGgAwIBAgIUI2ZSO2i7FA4iBKUOvjsZRzCQj8YwDQYJKoZIhvcNAQEL
BQAwgYUxCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhTaGFuZ0hhaTERMA8GA1UEBwwI
mu1GI8mCpMYVGyUnJVNHqb3PG5uECbcKk8SfVg==
-----END CERTIFICATE-----

Java代码:

package rsa;

import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import org.apache.commons.codec.binary.Base64; @UtilityClass
public class KeyGen { /**
* 加载 PEM base64-encoded format 的公钥证书内容,并生成 {@link RSAPublicKey} 类型实例
*
* @param pemContent PEM base64-encoded format 的公钥证书内容,此公钥证书符合 X.509 国际标准
* @return {@link RSAPublicKey} 类型实例
*/
@SneakyThrows
private RSAPublicKey getPublicKey(String pemContent) {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(pemContent));
return (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
} }

2.3、加载 符合 X.509 国际标准的CER(*.cer)格式的证书文件,并生成公钥(PublicKey)

Java代码:

package rsa;

import java.io.FileInputStream;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import lombok.Cleanup;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass; @UtilityClass
public class KeyGen { /**
* 读取符合 X.509 国际标准的 CER 格式的公钥证书文件,并生成 {@link PublicKey} 类型的实例
*
* @param cerPath 公钥证书文件(*.cer)的路径
*/
@SneakyThrows
public static PublicKey getPublicKey(String cerPath) {
@Cleanup FileInputStream bais = new FileInputStream(cerPath);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(bais);
return cert.getPublicKey();
} }

如果通过读取完整的 PEM 证书内容(字符串)来生成公钥证书(PublicKey)则通过以下方式。

Java代码

package rsa;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import lombok.Cleanup;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass; @UtilityClass
public class KeyGen { /**
* 读取符合 X.509 国际标准的公钥证书的 PEM base64-encoded 内容字符串 ,并生成 {@link PublicKey} 类型的实例
*
* @param pubKeyCertPem 公钥证书 PEM base64-encoded 内容字符串
*/
@SneakyThrows
public static PublicKey getPublicKey(String pubKeyCertPem) {
@Cleanup InputStream is = new ByteArrayInputStream(pubKeyCertPem.getBytes(StandardCharsets.UTF_8));
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
return cert.getPublicKey();
} }

2.4、根据证书的模(Modulus)和指数(Exponent)来生成公钥(PublicKey)

import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.RSAPublicKeySpec;
import lombok.SneakyThrows; public class RsaPublicKey { @SneakyThrows
private Key generatePublicKey(byte[] keyModulus, byte[] keyExponent) {
return KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(newBigInteger(keyModulus), newBigInteger(keyExponent)));
} private static BigInteger newBigInteger(byte[] keyInfo) {
return new BigInteger(1, keyInfo);
} }

3、RSA非对称-加密

公钥加密,私钥解密 或 私钥加密,公钥解密

Java代码:

package rsa;

import javax.crypto.Cipher;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import org.apache.commons.codec.binary.Base64; @UtilityClass
public class CryptTool { /**
* RSA 公钥加密
*
* @param data 待加密的数据
* @return 加密后的字节数组
*/
@SneakyThrows
public byte[] encrypt(byte[] data) {
Cipher cipher = Cipher.getInstance("RSA");
// The key is the {@link java.security.PublicKey} instance
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
} /**
* RSA 公钥加密
*
* @param data 待加密的数据
* @return 加密后并Base64的字符串
*/
@SneakyThrows
public String encrypt(byte[] data) {
Cipher cipher = Cipher.getInstance("RSA");
// The key is the {@link java.security.PublicKey} instance
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.encodeBase64String(cipher.doFinal(data));
} }

4、RSA非对称-解密

Java代码:

package rsa;

import java.nio.charset.StandardCharsets;
import javax.crypto.Cipher;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass; @UtilityClass
public class CryptTool { /**
* RSA 私钥解密
*
* @param data 待解密的数据
* @return 解密后的字节数组
*/
@SneakyThrows
public byte[] decrypt(byte[] data) {
Cipher cipher = Cipher.getInstance("RSA");
// The key is the {@link java.security.PrivateKey} instance
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
} /**
* RSA 私钥解密
*
* @param data 待解密的数据
* @return 解密后的字符串
*/
@SneakyThrows
public String decrypt(String data) {
Cipher cipher = Cipher.getInstance("RSA");
// The key is the {@link java.security.PrivateKey} instance
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
} }

4、RSA非对称-签名

Java代码:

package rsa;

import java.security.Signature;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import org.apache.commons.codec.binary.Base64; @UtilityClass
public class CryptTool { /**
* RSA 使用私钥进行签名,可能的 Signature Algrithom: </br>
* <ol>
* <li>SHA1withRSA</li>
* <li>SHA256withRSA</li>
* <li>SHA384withRSA</li>
* <li>SHA512withRSA</li></li>
* </ol>
* @param data 待签名的数据
* @return 签名后的数据
*/
@SneakyThrows
public byte[] sign(byte[] data) {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
} /**
* RSA 使用私钥进行签名,可能的 Signature Algrithom: </br>
* <ol>
* <li>SHA1withRSA</li>
* <li>SHA256withRSA</li>
* <li>SHA384withRSA</li>
* <li>SHA512withRSA</li></li>
* </ol>
* @param data 待签名的数据
* @return 签名后的数据
*/
@SneakyThrows
public String sign(byte[] data) {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data);
return Base64.encodeBase64String(signature.sign());
} }

4、RSA非对称-验签

Java代码:

package rsa;

import java.security.Signature;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import org.apache.commons.codec.binary.Base64; @UtilityClass
public class CryptTool { /**
* RSA 公钥验签
*
* @param data 待验签的数据
* @param sign 对方已签名的数据
* @return 验证结果
*/
@SneakyThrows
public boolean verify(byte[] data, String sign) {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(publicKey);
signature.update(data);
return signature.verify(Base64.decodeBase64(sign));
} }

附:SignatureAlgorithms

The algorithm names in this section can be specified when generating an instance of Signature.

Alg. Name Description

NONEwithRSA

The RSA signature algorithm which does not use a digesting algorithm (e.g. MD5/SHA1) before performing the RSA operation. For more information about the RSA Signature algorithms, please see PKCS1.

MD2withRSA

MD5withRSA

The MD2/MD5 with RSA Encryption signature algorithm which uses the MD2/MD5 digest algorithm and RSA to create and verify RSA digital signatures as defined in PKCS1.

SHA1withRSA

SHA256withRSA
SHA384withRSA
SHA512withRSA

The signature algorithm with SHA-* and the RSA encryption algorithm as defined in the OSI Interoperability Workshop, using the padding conventions described in PKCS1.

NONEwithDSA

The Digital Signature Algorithm as defined in FIPS PUB 186-2. The data must be exactly 20 bytes in length. This algorithms is also known under the alias name of rawDSA.

SHA1withDSA

The DSA with SHA-1 signature algorithm which uses the SHA-1 digest algorithm and DSA to create and verify DSA digital signatures as defined in FIPS PUB 186.

NONEwithECDSA

SHA1withECDSA

SHA256withECDSA

SHA384withECDSA

SHA512withECDSA

(ECDSA)

The ECDSA signature algorithms as defined in ANSI X9.62.

Note:"ECDSA" is an ambiguous name for the "SHA1withECDSA" algorithm and should not be used. The formal name "SHA1withECDSA" should be used instead.

<digest>with<encryption>

Use this to form a name for a signature algorithm with a particular message digest (such as MD2 or MD5) and algorithm (such as RSA or DSA), just as was done for the explicitly-defined standard names in this section (MD2withRSA, etc.).

For the new signature schemes defined in PKCS1 v 2.0, for which the <digest>with<encryption> form is insufficient, <digest>with<encryption>and<mgf> can be used to form a name. Here, <mgf> should be replaced by a mask generation function such as MGF1. Example: MD5withRSAandMGF1.

RSA加密和数字签名在Java中常见应用【原创】的更多相关文章

  1. Java中常见的5种WEB服务器介绍

    这篇文章主要介绍了Java中常见的5种WEB服务器介绍,它们分别是Tomcat.Resin.JBoss.WebSphere.WebLogic,需要的朋友可以参考下 Web服务器是运行及发布Web应用的 ...

  2. Java中常见的Exception种类

    Java中常见的Exception种类 1.ClassNotFoundException 2.IOException 3.NoSuchFieldException 4.NoSuchMethodExce ...

  3. Java基础-JAVA中常见的数据结构介绍

    Java基础-JAVA中常见的数据结构介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是数据结构 答:数据结构是指数据存储的组织方式.大致上分为线性表.栈(Stack) ...

  4. Java中常见的注解

    Java中常见的注解 1.JDK自带的注解@Override  @Deprecated  @Suppvisewarnings 常见第三方注解 Spring:@Autowired  @Service  ...

  5. Java中常见的异常类型

    一. Java中常见的异常类 异常类 说明 ClassCastException 类型准换异常 ClassNotFoundException 未找到相应类异常 ArithmeticException ...

  6. Java 中常见的 final 类

    Java 中常见的 final 类 java.lang 包 public final class Boolean extends Object implements Serializable, Com ...

  7. java中常见的六种线程池详解

    之前我们介绍了线程池的四种拒绝策略,了解了线程池参数的含义,那么今天我们来聊聊Java 中常见的几种线程池,以及在jdk7 加入的 ForkJoin 新型线程池 首先我们列出Java 中的六种线程池如 ...

  8. RSA加密常用的填充方式 以及 常见错误

    一.RSA加密常用的填充方式 1.RSA_PKCS1_PADDING 输入:比 RSA modulus 短至少11个字节.如果输入的明文过长,必须切割,然后填充 输出:和modulus一样长 根据这个 ...

  9. java 中常见异常

    1. Java.lang.NullPointerException  这个异常大家肯定都经常遇到,异常的解释是"程序遇上了空指针",简单地说就是调用了未经初始化的对象或者是不存在的 ...

随机推荐

  1. 老大难的GC原理及调优,这下全说清楚了

    概述 本文介绍GC基础原理和理论,GC调优方法思路和方法,基于Hotspot jdk1.8,学习之后将了解如何对生产系统出现的GC问题进行排查解决 阅读时长约30分钟,内容主要如下: GC基础原理,涉 ...

  2. php+js实现极验,拖动滑块验证码验证表单

    现在很多网站,比如淘宝,京东等都改用使用极验拖动验证码实现登录,这种方式比传统的验证码方式有更好的体验,减少用户输入的错误,也同样能起到防盗刷的功能.现在很多极验都是第三方的,也很多都是收费的.今天在 ...

  3. Hive安装部署与配置

    Hive安装部署与配置 1.1 Hive安装地址 1)Hive官网地址: http://hive.apache.org/ 2)文档查看地址: https://cwiki.apache.org/conf ...

  4. Django之form主键

    Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否 ...

  5. Linux操作系统-CentOS7启动流程和服务管理

    Linux操作系统-CentOS7启动流程和服务管理 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.systemd POST --> Boot Sequence --&g ...

  6. loadrunner中web_submit_data与web_submit_form区别

    以loadrunner自带的订票系统为例 当选择红框选中的模式时,所录脚本如下:回放时可以正常回放,登录成功 选另一种所录脚本如下:回放时登录不成功,session失效, 其中web_submit_f ...

  7. 201671010446姚良实验十四团队项目评审&课程总结

    实验十四 团队项目评审&课程学习总结 项目 内容 这个作业属于哪个课程 http://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cn ...

  8. 项目Beta冲刺(3/7)(追光的人)(2019.5.25)

    所属课程 软件工程1916 作业要求 Beta冲刺博客汇总 团队名称 追光的人 作业目标 描述Beta冲刺每日的scrum和PM报告两部分 队员学号 队员博客 221600219 小墨 https:/ ...

  9. LeetCode 865. Smallest Subtree with all the Deepest Nodes

    原题链接在这里:https://leetcode.com/problems/smallest-subtree-with-all-the-deepest-nodes/ 题目: Given a binar ...

  10. Hibernate的事务

    1.数据库的封锁(https://www.cnblogs.com/zhai1997/p/11710082.html): 封锁是实现并发控制的重要技术. read uncommitted : 读取尚未提 ...