IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> RSA非对称加密简介 -> 正文阅读

[网络协议]RSA非对称加密简介

RSA非对称加解密算法在实际开发中广泛使用,简单就目前前后端加解密常用方式小结一下。

RSA是什么:RSA公钥加密算法是1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的。RSA取名来自开发他们三者的名字。RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的所有密码攻击,已被ISO推荐为公钥数据加密标准。目前该加密方式广泛用于网上银行、数字签名等场合。RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

OpenSSL是什么:众多的密码算法、公钥基础设施标准以及SSL协议,或许这些有趣的功能会让你产生实现所有这些算法和标准的想法。果真如此,在对你表示敬佩的同时,还是忍不住提醒你:这是一个令人望而生畏的过程。这个工作不再是简单的读懂几本密码学专著和协议文档那么简单,而是要理解所有这些算法、标准和协议文档的每一个细节,并用你可能很熟悉的C语言字符一个一个去实现这些定义和过程。我们不知道你将需要多少时间来完成这项有趣而可怕的工作,但肯定不是一年两年的问题。OpenSSL就是由Eric A. Young和Tim J. Hudson两位绝世大好人自1995年就开始编写的集合众多安全算法的算法集合。通过命令或者开发库,我们可以轻松实现标准的公开算法应用。

生成密钥

1、生成ras私钥

$ openssl genrsa -out private_key.pem 1024

输出

Generating RSA private key, 1024 bit long modulus (2 primes)

…+++++

…+++++

e is 65537 (0x010001)

2、生成公钥

$ openssl rsa -in private_key.pem -pubout -out public_key.pem

输出

writing RSA key

3、把私钥转为PKCS#8编码,因为JDK的加密组件JCE中需要读取PKCS#8格式

openssl pkcs8 -topk8 -in private_key.pem -out pkcs8_private_key.pem -nocrypt

生成的证书pem文件内容(以下是私钥的):

-----BEGIN RSA PRIVATE KEY-----
 BASE64 ENCODED DATA
-----END RSA PRIVATE KEY-----

Java部分

使用JDK的JCE组件(Java Cryptography Extension)

 import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

public class RSAUtils {
		/**
     * 加密方法
     * @param publicKeyText 公钥文本串
     * @param source 源数据
     * @return
     * @throws Exception
     */
    public static String encrypt(String publicKeyText, String source) throws Exception {

        java.security.spec.X509EncodedKeySpec x509KeySpec = new java.security.spec.X509EncodedKeySpec(java.util.Base64.getDecoder().decode(publicKeyText));
        // RSA算法
        java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA");
        // 取公钥匙对象
        java.security.PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
        // 得到Cipher对象来实现对源数据的RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] b = source.getBytes();
        /** 执行加密操作 */
        byte[] b1 = cipher.doFinal(b);
        return Base64.getEncoder().encodeToString(b1);

    }

    /**
     * 解密算法
     * @param privateKeyText 私钥文本串
     * @param cryptoText 密文
     * @return
     * @throws Exception
     */
    public static String decrypt(String privateKeyText, String cryptoText) throws Exception {
        Base64.Decoder decoder = java.util.Base64.getDecoder();

        PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(decoder.decode(privateKeyText));
        KeyFactory keyf = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyf.generatePrivate(priPKCS8);

        /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] b1 = decoder.decode(cryptoText);

        /** 执行解密操作 */
        byte[] b = cipher.doFinal(b1);
        return new String(b);
    }

    public static void main(String[] args) throws Exception {
        //#priKeyText
        // 不需要头尾的注释行 -----BEGIN RSA PRIVATE KEY-----
        // 注意这里使用的是PCSK#8格式的私钥
        String priKeyText =
                "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAM+RE49WU9V/jnmg" +
                "z3Snhi2sqnwXyLmpv7gQ/VLQ66FgdJw+ONi//rXY0Y7tyOW7H5vgrhM6BBmixhBc" +
                "HoGaJwsOL6G0nIs9B9+sGMJQqupPOvGl51G/Svd5tBFT+pf8eawjhBCt2KXC5/9J" +
                "StgvrKriz6UP9Gxf9XCDAmKdHu9BAgMBAAECgYBiR8giK3cAdShJ8Nmp25SN1d7X" +
                "aQ+S0YxEpE6+Qsv/GkO8oz2Za7c39VSsP2zLUgHSdd0Wn3bHiKoNnwCWzx3CpKEx" +
                "UoQxXcAmVkZOksYsEDN6mb9cdDFHGxtNLsuA0HSE0VkvZwVSAU7O6W5v0mAt25Ei" +
                "eHywZqXapS/UYcmSXQJBAPTNrpIc+Ir90ulhzJUDhXB4ip60Mq8yU83DGng7A9Cd" +
                "Nwa/U5rLmdXPPzCg/X4iNvw4QDtpz5QiQKVI5PcJK38CQQDZD2cJ7zPGCFVKGvck" +
                "oGqAb02/sujIZB1LpWTC+gxni7sUhMeh6lCNGnbrI10brtUeYG7sQiOHhcsFIUkI" +
                "3EU/AkBqiDe4DjN7CQqH1a+aCXZAg7SPbAvCgjxGBum1+LioSEJyBUD01DWV/iKZ" +
                "nvWxtmIHUNNjB6D17hID270IZE0xAkAkGC2YN1Cys5wLMKS8UHilVtzk7clL2WoN" +
                "tDknOxFo/pFjfhj8UcyHSklQHJdVDSOfY4XOf8kMtjDmb3yHnqldAkEAjC3FHa/8" +
                "3uuRgH8QMk3hQWSCLcI/b7ccdE1xUU7SJ9PSkMx6zhe0n+pPIHsaPSdzk0Tk03w+" +
                "o6yDfIfIH6td4A==";

        //#pubKeyText
        String pubKeyText = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPkROPVlPVf455oM90p4YtrKp8" +
                "F8i5qb+4EP1S0OuhYHScPjjYv/612NGO7cjlux+b4K4TOgQZosYQXB6BmicLDi+h" +
                "tJyLPQffrBjCUKrqTzrxpedRv0r3ebQRU/qX/HmsI4QQrdilwuf/SUrYL6yq4s+l" +
                "D/RsX/VwgwJinR7vQQIDAQAB";
        String s = encrypt(pubKeyText, "1231");
        System.out.println(s);
        String a = decrypt(priKeyText, s);
        System.out.println(a);
    }
}

需要注意的是很多示例中还是使用sun.misc.BASE64Decoder 工具,尽量使用最新的java.util.Base64 ,并且注意去掉头尾的"-----BEGIN ……" 行,中间的Base64编码部分的字符去掉回车换行部分。或者需要改用java.util.Base64#getMimeDecoder进行解码。

公钥的格式都是X.509格式的,但私钥默认存储的格式为PKCS#1,可以借助Bouncy Castle转化PCS#1格式为PKCS#8格式,从而获取私钥。

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.70</version>
</dependency>
// 使用PCSK#1格式的私钥
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);

Javascript部分

目前多数使用的组件是 jsencrypt ,注意的是改组件对私钥的格式PKCS#1和PKCS#8都支持,本示例的私钥是PKCS#1的,与Java部分的示例为同一对公死钥,可以互相加解密。

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>test</title>
	<script src="https://cdn.bootcdn.net/ajax/libs/jsencrypt/3.2.1/jsencrypt.js"></script>
	<script type="text/javascript">
		var encrypt = new JSEncrypt();
		var pubKey = `
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPkROPVlPVf455oM90p4YtrKp8
F8i5qb+4EP1S0OuhYHScPjjYv/612NGO7cjlux+b4K4TOgQZosYQXB6BmicLDi+h
tJyLPQffrBjCUKrqTzrxpedRv0r3ebQRU/qX/HmsI4QQrdilwuf/SUrYL6yq4s+l
D/RsX/VwgwJinR7vQQIDAQAB
-----END PUBLIC KEY-----`
		var priKey = `
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDPkROPVlPVf455oM90p4YtrKp8F8i5qb+4EP1S0OuhYHScPjjY
v/612NGO7cjlux+b4K4TOgQZosYQXB6BmicLDi+htJyLPQffrBjCUKrqTzrxpedR
v0r3ebQRU/qX/HmsI4QQrdilwuf/SUrYL6yq4s+lD/RsX/VwgwJinR7vQQIDAQAB
AoGAYkfIIit3AHUoSfDZqduUjdXe12kPktGMRKROvkLL/xpDvKM9mWu3N/VUrD9s
y1IB0nXdFp92x4iqDZ8Als8dwqShMVKEMV3AJlZGTpLGLBAzepm/XHQxRxsbTS7L
gNB0hNFZL2cFUgFOzulub9JgLduRInh8sGal2qUv1GHJkl0CQQD0za6SHPiK/dLp
YcyVA4VweIqetDKvMlPNwxp4OwPQnTcGv1Oay5nVzz8woP1+Ijb8OEA7ac+UIkCl
SOT3CSt/AkEA2Q9nCe8zxghVShr3JKBqgG9Nv7LoyGQdS6VkwvoMZ4u7FITHoepQ
jRp26yNdG67VHmBu7EIjh4XLBSFJCNxFPwJAaog3uA4zewkKh9Wvmgl2QIO0j2wL
woI8Rgbptfi4qEhCcgVA9NQ1lf4imZ71sbZiB1DTYweg9e4SA9u9CGRNMQJAJBgt
mDdQsrOcCzCkvFB4pVbc5O3JS9lqDbQ5JzsRaP6RY34Y/FHMh0pJUByXVQ0jn2OF
zn/JDLYw5m98h56pXQJBAIwtxR2v/N7rkYB/EDJN4UFkgi3CP2+3HHRNcVFO0ifT
0pDMes4XtJ/qTyB7Gj0nc5NE5NN8PqOsg3yHyB+rXeA=
-----END RSA PRIVATE KEY-----`
			// 加密
			encrypt.setPublicKey(pubKey)
			s = encrypt.encrypt('1231231312')
			console.log( s)
			// 解密
			encrypt.setPrivateKey(priKey)
			console.log(encrypt.decrypt(s))
	</script>
</head>
<body>
</body>
</html>

在前端的工程中可能会使用npm安装

npm install jsencrypt 

使用时

import JSEncrypt from 'jsencrypt'

// 加密
function encrypt(pubKey, srcText) {
  let encryptor = new JSEncrypt() // 新建JSEncrypt对象
	encryptor.setPublicKey(publicKey) // 设置公钥
	// 对需要加密的数据进行加密
	return encryptor.encrypt(srcText)
}

// 解密
function decrypt(priKey, cryptoText){
  let decrypt = new JSEncrypt();
	// 设置私钥
	decrypt.setPrivateKey(privateKey);
	return decrypt.decrypt(cryptoText);
}

补充知识

.PEM:用ASCLL(BASE64)编码的证书;

? PEM格式通常用于数字证书认证机构(Certificate Authorities,CA),扩展名为**.pem, .crt, .cer, and .key**。内容为Base64编码的ASCII码文件,有类似"-----BEGIN CERTIFICATE-----" 和 "-----END CERTIFICATE-----"的头尾标记。服务器认证证书,中级认证证书和私钥都可以储存为PEM格式(认证证书其实就是公钥)。Apache和类似的服务器使用PEM格式证书。

.DER

DER格式与PEM不同之处在于其使用二进制而不是Base64编码的ASCII。扩展名为**.der**,但也经常使用**.cer**用作扩展名,所有类型的认证证书和私钥都可以存储为DER格式。Java使其典型使用平台。

转换方式

? 可以使用OpenSSL命令行工具在不同证书格式之间的转换

PEM to DER

 openssl x509 -outform der -in certificate.pem -out certificate.der

DER to PEM

  openssl x509 -inform der -in certificate.cer -out certificate.pem

.CER:存放公钥,没有私钥;

.CER文件就是一个X.509证书,可以直接查看

openssl x509 -in test.cer -text

有些情况下,不支持直接查看.CER文件,需要先将其转换为.PEM文件

openssl x509 -in test.cer -out test.pem
openssl x509 -in test.pem -text

.PFX:存放公钥和私钥

.PFX文件是一个PKCS#12格式的文件,不支持直接 查看,需要先将其转换为.PEM格式的文件

openssl x509 -in test.pfx -out test.pem -nodes
openssl x509 -in test.pem -text

PEM to PFX

  openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt -certfile CACert.crt

(pem 后缀的证书都是base64编码;der 后缀的证书都是二进制格式;crt .cer 后缀的文件都是证书文件(编码方式不一定,有可能是.pem,也有可能是.der);.pfx 主要用于windows平台,浏览器可以使用,也是包含证书和私钥,获取私钥需要密码才可以)

PFX to PEM

  openssl pkcs12 -in certificate.pfx -out certificate.cer -nodes

(PFX转PEM后certificate.cer文件包含认证证书和私钥,需要把它们分开存储才能使用。)

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-12-26 22:36:04  更:2021-12-26 22:37:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年10日历 -2024/10/6 11:02:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码