1. RSA
私钥:使用随机数按照一定的规则生成。
公钥:由私钥推导。
私钥只有自己持有,公钥任何人都可以持有。
利用数学难题,大素数(乘积)因式分解。
1. RSA加密
下面我们终于可以讲一讲非对称加密的代表—RSA的加密过程了。在RSA中,明文、密钥和密文都是数字。RSA的加密过程可以用下列公式来表达,如下。
$$
密文=明文 ^ E mod N(RSA加密)
$$
也就是说,RSA的密文是对代表明文的数字的E次方求modN的结果。换句话说,就是将明文自己做E次乘法,然后将其结果除以N求余数,这个余数就是密文。
咦,就这么简单?
对,就这么简单。仅仅对明文进行乘方运算并求mod即可,这就是整个加密的过程。在对称密码中,出现了很多复杂的函数和操作,就像做炒鸡蛋一样将比特序列挪来挪去,还要进行XOR(按位异或)等运算才能完成,但RSA却不同,它非常简洁。
对了,加密公式中出现的两个数一一一E和N,到底都是什么数呢?RSA的加密是求明文的E次方modN,因此只要知道E和N这两个数,任何人都可以完成加密的运算。
所以说,E和N是RSA加密的密钥,也就是说,==E和N的组合就是公钥==。
不过,E和N并不是随便什么数都可以的,它们是经过严密计算得出的。顺便说一句,E是加密(Encryption)的首字母,N是数字(Number)的首字母。
有一个很容易引起误解的地方需要大家注意一一E和N这两个数并不是密钥对(公钥和私钥的密钥对)。E和N两个数才组成了一个公钥,因此我们一般会写成 “公钥是(E,N)” 或者 “公钥是{E, N}" 这样的形式,将E和N用括号括起来。
现在大家应该已经知道,==RSA的加密就是 “求E次方的modN"==,接下来我们来看看RSA的解密。
2. RSA解密
RSA的解密和加密一样简单,可以用下面的公式来表达:
$$
明文=密文^DmodN(RSA解密)
$$
也就是说,对表示密文的数字的D次方求modN就可以得到明文。换句话说,将密文自己做D次乘法,再对其结果除以N求余数,就可以得到明文。
这里所使用的数字N和加密时使用的数字N是相同的。==数D和数N组合起来就是RSA的解密密钥==,因此D和N的组合就是私钥。只有知道D和N两个数的人才能够完成解密的运算。
大家应该已经注意到,在RSA中,加密和解密的形式是相同的。加密是求 "E次方的mod N”,而解密则是求 "D次方的modN”,这真是太美妙了。
当然,D也并不是随便什么数都可以的,作为解密密钥的D,和数字E有着相当紧密的联系。否则,用E加密的结果可以用D来解密这样的机制是无法实现的。
顺便说一句,D是解密〈Decryption)的首字母,N是数字(Number)的首字母。
3. RSA算法原理
Go语言实现
1. 生成密钥对
package rsa
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"log"
"os"
)
// 私钥的地址
const privateKeyFile = "./privateRSAKey.pem"
// 公钥的地址
const publicKeyFile = "./publicRSAKey.pem"
// 生成密钥对
// priv.E = 65537 ,使用pkcs1推荐的65537
func GenerateKeyPair(bits int) (err error) {
var (
privateKey *rsa.PrivateKey
privDerText []byte
privPemBlock pem.Block
privFileHandle *os.File
pubDerText []byte
pubPemBLock pem.Block
pubFileHandle *os.File
)
log.Println("生成私钥...")
// 1. 使用随机数生成密钥对
if privateKey, err = rsa.GenerateKey(rand.Reader, bits); err != nil {
return
}
// 2. 编码处理
// MarshalPKCS1PrivateKey 将公钥转化为 ASN.1 DER 编码格式
privDerText = x509.MarshalPKCS1PrivateKey(privateKey)
log.Printf("私钥为:%s\n", base64.StdEncoding.EncodeToString(privDerText))
// 3. 生成pem格式的block
privPemBlock = pem.Block{
Type: "RSA PRIVATE KEY",
Headers: nil,
Bytes: privDerText,
}
// 4. 写入到指定文件
if privFileHandle, err = os.OpenFile(privateKeyFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755); err != nil {
return
}
defer privFileHandle.Close()
if err = pem.Encode(privFileHandle, &privPemBlock); err != nil {
return
}
log.Println("生成公钥...")
// 5. 编码处理
pubDerText = x509.MarshalPKCS1PublicKey(&privateKey.PublicKey)
log.Printf("公钥为:%s\n", base64.StdEncoding.EncodeToString(pubDerText))
// 6. 生成pem格式的block
pubPemBLock = pem.Block{
Type: "RSA PUBLIC KEY",
Headers: nil,
Bytes: pubDerText,
}
// 7. 写入到指定文件
if pubFileHandle, err = os.OpenFile(publicKeyFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755); err != nil {
return
}
defer pubFileHandle.Close()
err = pem.Encode(pubFileHandle, &pubPemBLock)
return
}
2. 加密
// 公钥加密
func RSAEncript(src []byte) (dst []byte, err error) {
var (
fileContent []byte
block *pem.Block
derText []byte
publicKey *rsa.PublicKey
)
// 1. 读取公钥
if fileContent, err = ioutil.ReadFile(publicKeyFile); err != nil {
return
}
block, _ = pem.Decode(fileContent)
if block.Type != "RSA PUBLIC KEY" {
return nil, errors.New("公钥类型错误")
}
// 2. 获取x509编码的格式der
derText = block.Bytes
// 3. 解码公钥
if publicKey, err = x509.ParsePKCS1PublicKey(derText); err != nil {
return
}
// 4. 加密
dst = make([]byte, 0)
dst, err = rsa.EncryptPKCS1v15(rand.Reader, publicKey, src)
return
}
3. 解密
// 私钥解密
func RSADecript(src []byte) (dst []byte, err error) {
var (
fileContent []byte
block *pem.Block
derText []byte
privateKey *rsa.PrivateKey
)
// 1. 读取私钥文件信息
if fileContent, err = ioutil.ReadFile(privateKeyFile); err != nil {
return
}
// 2. 获取pem格式结构体block
block, _ = pem.Decode(fileContent)
// 3. 获取x509编码格式derText
derText = block.Bytes
// 4. 获取私钥
if privateKey, err = x509.ParsePKCS1PrivateKey(derText); err != nil {
return
}
// 5. 解密
dst, err = rsa.DecryptPKCS1v15(rand.Reader, privateKey, src)
return
}