非对称加密及案例
Posted 小圣.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了非对称加密及案例相关的知识,希望对你有一定的参考价值。
1. 概述
对称加密算法在加密和解密时使用的是同一个密钥,为了解决信息公开传送和密钥管理的问题,于是提出了一种新的密钥交换协议,这种协议允许在不安全的媒体上的通讯双方交换信息、安全地达成一致的密钥系统,这就是非对称加密(公钥加密)。之所以称为非对称加密,是因为使用非对称加密算法时,加密和解密使用的是不同的密钥。这两个密钥分别是私钥(private key)和公钥(public key)。
常用的非对称加密算法有:RSA、ECC
2. 特点
- 使用公钥加密后,只有对应的私钥才能解密
- 使用私钥加密后,只有对应的公钥才能机密
- 算法强度高,不适合加密较大的数据
- 数据传输的安全性高于对称加密算法
3. RSA
RSA是一种非对称加密算法,它的名字是由它的三位开发者,即RonRivest、AdiShamir和LeonardAdleman 的姓氏的首字母组成的(Rivest-Shamir-Leonard)。RSA的密钥长度推荐为1024位。
RSA的基本原理是:根据数论,寻求两个大素数比较简单,而将它们的乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
3.1 加密流程
RSA的加密可以用下面这个公式来表示:
密文 = 明文^E mod N
RSA的加密就是对明文代表数字的E次方取模。其中E和N就是RSA加密的密钥,E和N组合就是公钥了。那么如何确定E和N呢?
N的求法:准备两个很大的质数P、Q,然后将这两个数相乘,其结果就是N。N = P * Q
E的求法:首先计算N的欧拉函数(小于N的正整数中与N互质的数的数目)得到L,L = (P-1) * (Q-1),然后在1和L之间选取一个和L互质的数,这个数就是E。
最后就可以得到公钥KU = (E, N)。
3.2 解密流程
RSA的解密可以用下面这个公式来表示:
明文 = 密文^D mod N
RSA的解密就是对密文代表数字的D次方进行取模。这里使用的数字N和加密时使用的N是相同的。所以只有求出D就可以得到私钥。数D和数N组合起来就是解密的密钥,也就是私钥。
D的求法:E对于L的模反元素就是D。可以用这个公式快速求得D:E * D mod L = 1。
最后可以得到私钥KR = (D, N)
3.3 生成公私钥案例
- 选择一堆不相等且足够大的质数:P = 3、Q = 11
- 计算P和Q的乘积N:N = P * Q = 33
- 根据定理计算N的欧拉函数L:L = (P - 1) * (Q - 1) = 20
- 从1到L中选取一个与L互质的整数E:1 < E < 10,选取E = 3
- 计算E对于L的模反元素D:E * D mod L = 1,D = 7
- 求得公钥为:KU = (E, N) = (3, 33)
- 求得私钥为:KR = (D, N) = (7, 33)
3.4 使用案例
3.4.1 生成公私钥
// 生成公私钥
func GenerateKeyPair(bits int) {
// 生成私钥
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
fmt.Println("generate private key err: ", err)
return
}
// 通过x509标准将得到的ras私钥序列化为ASN.1 的 DER编码字符串
privateKeyDer := x509.MarshalPKCS1PrivateKey(privateKey)
// 将私钥字符串设置到pem格式块中
block := pem.Block{
Type: "PRIVATE KEY",
Headers: nil,
Bytes: privateKeyDer,
}
// 写入文件
file1, err := os.Create(privateKeyFile)
if err != nil {
fmt.Println("open file err: ", err)
return
}
defer file1.Close()
// 开始写入
err = pem.Encode(file1, &block)
if err != nil {
fmt.Println("pem encode err: ", err)
return
}
// 从得到的私钥对象中将公钥信息取出
publicKey := privateKey.PublicKey
// 通过x509标准将得到的rsa公钥序列化为字符串
publicKeyDer := x509.MarshalPKCS1PublicKey(&publicKey)
// 将公钥字符串设置到pem格式块中
block2 := pem.Block{
Type: "PUBLIC KEY",
Headers: nil,
Bytes: publicKeyDer,
}
// 写入文件
file2, err := os.Create(publicKeyFile)
if err != nil {
fmt.Println("open file err: ", err)
return
}
err = pem.Encode(file2, &block2)
if err != nil {
fmt.Println("write public key err: ", err)
return
}
}
3.4.2 公钥加密
// 公钥加密
ffunc PublicKeyEncrypt(publicKeyFile string, plainText []byte) []byte {
// 读取私钥
publicKeyPem, err := ioutil.ReadFile(publicKeyFile)
if err != nil {
fmt.Println("read public key file err: ", err)
return []byte{}
}
// 解码成x509格式,rest是未解码完的数据存储在这里
block, _ := pem.Decode(publicKeyPem)
// 得到私钥
publicKey, err := x509.ParsePKCS1PublicKey(block.Bytes)
if err != nil {
fmt.Println("x509 parse public key err: ", err)
return nil
}
// 加密
cipherData, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, plainText)
if err != nil {
fmt.Println("public encrypt err: ", err)
return nil
}
return cipherData
}
3.4.3 私钥解密
func PrivateKeyDecrypt(privateKeyFile string, cipherData []byte) []byte {
// 读取私钥
privateKeyPem, err := ioutil.ReadFile(privateKeyFile)
if err != nil {
fmt.Println("read private file err: ", err)
return nil
}
// 从数据中查找到DER格式的块
privateKeyDer, _ := pem.Decode(privateKeyPem)
// 解析一个pem格式的私钥
privateKey, err := x509.ParsePKCS1PrivateKey(privateKeyDer.Bytes)
if err != nil {
fmt.Println("parse private key err: ", err)
return nil
}
// 解密
plaintData, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, cipherData)
if err != nil {
fmt.Println("private key decrypt err: ", err)
return nil
}
return plaintData
}
测试结果:
完整代码:https://github.com/bigzoro/cryptography/tree/main/asymmetricalCryption/rsa
以上是关于非对称加密及案例的主要内容,如果未能解决你的问题,请参考以下文章