# RSA加解密和签名算法的技术原理及其在Go语言中的实现
在对称加密中,加密和解密使用相同的密钥,所以必须将密钥分发给解密者,即密钥分发问题。
在非对称加密中,由于公钥和私钥分别用于加密和解密,而且公钥是公开的,所以可以避免密钥分配的问题。
非对称加密算法,又称公钥加密算法。
1977 年,Ron Rivest、Adi Shamir 和 Leonard Adleman 在美国发表了一种公钥加密算法,即 RSA 公钥加密算法。
RSA是目前最有影响力和最常用的公钥加密算法,可以说是公钥加密算法的事实标准。
### RSA加密原理
分别用M和C表示明文和密文,RSA加解密过程如下:
e和n(e,n)的组合是公钥,d和n(d,n)的组合是私钥。
当然,e、d、n不是任意值,需要满足一定的条件。下面是e、d、n的求解过程。
### 生成密钥对
e、d、n的求解过程就是生成密钥对的过程。涉及以下步骤:
* 1、取两个大素数(也叫素数)p,q,n = pq。
* 2、 取正整数e和d,使得ed mod (p-1)(q-1) = 1,即:ed ≡ 1 mod (p-1)@ > (q-1).
e 和 d 是模 (p-1)(q-1), 仅当 e 与 (p-1)(q-1), d 存在.
示例验证:
* 1、 取 p 和 q 为 13、17,n = pq = 221。
* 2、和 (p-1)(q-1) = 12×16 = 192, 取 e 和 d 为 13、133, 13×133 mod 192 = 1
取明文M=60,公钥加密私钥解密,加解密过程如下:
### RSA加密原理证明过程
### 手动求解密钥对中的d
ed mod (p-1)(q-1) = 1,给定e和(p-1)(q-1))求d,即求e模数 ( p-1)(q-1).
在上面的例子中,p和q是13、17,(p-1)(q-1)=192,取e=13,求d在13d mod 192 = 1.
13d ≡ 1 (mod 192), 将 192 的倍数加到右边使结果可以被 13 整除。
13d ≡ 1 + 192×9 ≡ 13×133 (mod 192), 所以 d = 133
其他计算方法有:费马小定律、扩展欧几里得算法、欧拉定理。
### RSA 安全性
由于公钥是公开的,即 e 和 n 是公开的。
所以破解RSA私钥就是在已知e和n的情况下求d。
由于 ed mod (p-1)(q-1) = 1, and n=pq, 问题演变为:求 p 和 q 进行 n 素数分解。
目前已经证明已知的e,n求d和n的素数分解求p,q是等价的。
在实际中,n的长度超过2048位,当n>200位时,n的分解是非常困难的,所以还是认为RSA算法是安全实用的。
### RSA定时攻击与预防
RSA解密的本质是模幂运算,即:
其中,C为密文,(d,n)为私钥,都是对1024位以上的大数的运算,直接计算是不可行的。因此,最经典的算法是蒙哥马利算法。
这种计算比较耗时,因此攻击者可以观察不同输入对应的解密时间,通过分析推断出私钥,称为定时攻击。
防止RSA定时攻击的方法是在解密时加入随机因素,使攻击者无法准确获取解密时间。
具体实施步骤如下:
### go标准库中的RSA加解密实现
go标准库中的解密实现了对定时攻击的防范。代码如下:
““去
//加密
//m是明文
//(pub.E, pub.N) 是公钥
//c是密文
func encrypt(c *big.Int, pub *, m *big.Int) *big.Int {
e := big.NewInt(int64(pub.E))
c.Exp(m, e, pub.N)
返回 c
}
//解密
//传入随机数支持防止定时攻击
func 解密(随机 io.Reader,priv *,c *big.Int)(m *big.Int,err 错误){
如果 c.Cmp(priv.N) > 0 {
错误 =
返回
}
如果 priv.N.Sign() == 0 {
返回零,
}
var ir *big.Int
如果随机!= nil {
var r *big.Int
为了 {
//第一步生成一个0到n-1之间的随机数r
r, err = rand.Int(random, priv.N)
如果错误!= nil {
返回
}
如果 r.Cmp(bigZero) == 0 {
r = bigOne
}
var ok 布尔值
//r 的乘法逆 ir 模 n区块链公钥生成,用于第 4 步
ir, ok = (r, priv.N)
如果可以{
休息
}
}
bigE := big.NewInt(int64(priv.E))
//计算第2步中的C’
rpowe := new(big.Int).Exp(r, bigE, priv.N) // N != 0
cCopy := new(big.Int).Set(c)
cCopy.Mul(cCopy, rpowe)
cCopy.Mod(cCopy, priv.N)
c = c复制
}
如果 priv..Dp == nil {
//第3步,用C’计算对应的M’
m = new(big.Int).Exp(c, priv.D, priv.N)
} 别的 {
//轻微地
}
如果 ir != nil {
//第4步计算实际M
m.Mul(m, ir)
m.Mod(m, priv.N)
}
返回
}
““
### RSA签名和验证的原理
非对称加密算法,除了支持加密外,还可以实现签名。原理如下:
符号:
* 1、 提取消息摘要,用发送者的私钥加密消息摘要,生成消息签名。
* 2、消息签名和消息与接收者的公钥一起加密区块链公钥生成,得到密文。
签名验证:
* 1、使用接收者的私钥对密文进行解密,得到消息和消息签名。
* 2、使用发送者的公钥解密消息签名,得到消息摘要。
* 3、用同样的方法再次提取消息摘要,并与上一步的消息摘要进行比较。如果相同,则签名验证成功。
附图如下:
1)0@>
### Go 标准库中的 RSA 签名和验证实现
代码显示如下:
““去
//符号
func (rand io.Reader, priv *, hash crypto.Hash, hashed []byte) ([]byte, error) {
//哈希提取消息摘要
hashLen, 前缀, err := (hash, len(hashed))
如果错误!= nil {
返回零,错误
}
tLen := len(前缀) + hashLen
k := (priv.N.BitLen() + 1)1@> / 8
如果 k < tLen+11 {
返回零,
}
// EM = 0x00 || 0x01 || PS || 0x00 || 吨
em := make([]byte, k)
em[1] = 1
对于 i := 2; 我 < k-tLen-1; 我++ {
em[i] = 0xff
}
//整合消息摘要和消息正文
复制(em[k-tLen:k-hashLen],前缀)
复制(em[k-hashLen:k],散列)
m := new(big.Int).(em)
//使用发送者的私钥对消息摘要和消息体进行加密,即签名
c, err := (rand, priv, m)
如果错误!= nil {
返回零,错误
}
(em, c.Bytes())
返回 em,无
}
//验证签名
func (pub *, hash crypto.Hash, hashed []byte, sig []byte) 错误 {
//哈希提取消息摘要
hashLen, 前缀, err := (hash, len(hashed))
如果错误!= nil {
返回错误
}
tLen := len(前缀) + hashLen
k := (pub.N.BitLen() + 1)1@> / 8
如果 k < tLen+11 {
返回
}
c := new(big.Int).(sig)
//使用发送者的公钥解密,提取消息体和消息签名
m := 加密(new(big.Int), pub, c)
em := leftPad(m.Bytes(), k)
// EM = 0x00 || 0x01 || PS || 0x00 || 吨
//比较发送者和接收者的消息体,以及消息签名
好的 := 微妙的。(em[0], 1)3@>
好的 &= 微妙的。(em[1], 1)
好的 &= 微妙的。(em[k-hashLen:k],散列)
好的 &= 微妙的。(em[k-tLen:k-hashLen],前缀)
好的 &= 微妙的。(em[k-tLen-1], 1)3@>
对于 i := 2; 我 < k-tLen-1; 我++ {
好的 &= 微妙的。(em[i], 0xff)
}
如果没问题!= 1 {
返回
}
返回零
}
//代码位置 src/crypto/rsa/.go
““
### 后记
RSA算法中用到了很多数论知识,而数论方面的知识还有待学习。
未完待续。
1)6@>
1)7@>
1)8@>
网址:
1)9@>
领取造币技术及全套虚拟机资料
区块链技术交流QQ群: 备注:CSDN
挖矿网Ethos中文站简单易用的挖矿系统,为挖矿产业提供教程软件以及矿机测评交易信息等,挖矿网各种数字货币挖矿收益对比计算,挖矿网介绍挖矿的工具,以及矿场的最新消息等。http://www.ethospool.com/