相关术语解释:

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. odex vdex art区别

    一.vdexpackage 直接转化的 可执行二进制码 文件:1.第一次开机就会生成在/system/app/<packagename>/oat/下:2.在系统运行过程中,虚拟机将其 从 ...

  2. sizeof()计算

    本节包含sizeof()计算结构体,位域,数组,字符串,指针,c++中的class等类型的大小,sizeof()计算的大小都是以字节为单位. 一 计算基本类型的长度 sizeof(char): 1 s ...

  3. OCR3:tesseract script

    通过命令:tesseract -h 可查看 OCR操作脚本参数: 其中参数说明: –-oem:指定使用的算法,0:代表老的算法:1:代表LSTM算法:2:代表两者的结合:3:代表系统自己选择. –-p ...

  4. AI的自学题库-竞赛-基础知识

    阿里云(天池): https://tianchi.aliyun.com/course?spm=5176.12281897.0.0.209439a9UwObn3 天池竞赛:https://tianchi ...

  5. HTTP/2和Python的支持现状-2019-10

    背景: 大概2019年9月份,天猫全面升级了HTTP/2的支持,并且加强了HTTP/1的访问限制,也可能很早前就这么做了, 但之前一直没限制HTTP/1的访问.之所以发现这个问题,是因为写的爬虫突然失 ...

  6. 打造好用的C++ IDE环境

    https://www.jianshu.com/p/1aa989808e15 这哥们说的也是极好,也可以这部分直接看他的示例! mingw-w64应该可以算是mingw的改进版本吧,mingw系列编译 ...

  7. django项目后台权限管理功能。

    对后台管理员进行分角色,分类别管理,每个管理员登录账号后只显示自己负责的权限范围. 创建后台管理数据库 models.py文件内 # 管理员表 class Superuser(models.Model ...

  8. 修改mysql 8.0.16 root 密码--mac

    https://blog.csdn.net/HECTOR_1368391900/article/details/90732097 https://my.oschina.net/u/3251146/bl ...

  9. js 对小数进行格式化(保留小数,去除小数后的0)

    // 如果去零时需要保留位数: (比如 19.520100 --> 19.52) parseFloat(Number(19.520100).toFixed(2)) // 如果只想去除小数点后多余 ...

  10. 11.07图论水题Test

    11.07图论水题Test 题目 描述 做法 \(BSOJ6378\) 在\(i\)位置可以到\(i+a_i\)或\(i+b_i\)求\(1\rightarrow n\)字典序最小路径 判可达性后贪心 ...