您好,登錄后才能下訂單哦!
對稱加密中,加密和解密使用相同的密鑰,因此必須向解密者配送密鑰,即密鑰配送問題。而非對稱加密中,由于加密和解密分別使用公鑰和私鑰,而公鑰是公開的,因此可以規避密鑰配送問題。非對稱加密算法,也稱公鑰加密算法。
?
1977年,Ron Rivest、Adi Shamir、Leonard Adleman三人在美國公布了一種公鑰加密算法,即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) = 12x16 = 192,取e、d分別為13、133,有13x133 mod 192 = 1
取明文M = 60,公鑰加密、私鑰解密,加密和解密過程分別如下:
?
?
?
?
?
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,求13d mod 192 = 1中的d。
?
13d ≡ 1 (mod 192),在右側添加192的倍數,使計算結果可以被13整除。
13d ≡ 1 + 192x9 ≡ 13x133 (mod 192),因此d = 133
?
其他計算方法有:費馬小定律、擴展歐幾里得算法、歐拉定理。
?
?
由于公鑰公開,即e、n公開。
因此破解RSA私鑰,即為已知e、n情況下求d。
因ed mod (p-1)(q-1) = 1,且n=pq,因此該問題演變為:對n質因數分解求p、q。
?
目前已被證明,已知e、n求d和對n質因數分解求p、q兩者是等價的。實際中n長度為2048位以上,而當n>200位時分解n是非常困難的,因此RSA算法目前仍被認為是安全實用的。
?
?
RSA解密的本質是模冪運算,即:
?
?
其中C為密文,(d,n)為私鑰,均為超過1024位的大數運算,直接計算并不可行,因此最經典的算法為蒙哥馬利算法。而這種計算是比較是耗時的,因此***者可以觀察不同的輸入對應的解密時間,通過分析推斷私鑰,稱為計時***。而防范RSA計時***的辦法,即在解密時加入隨機因素,使得***者無法準確獲取解密時間。
?
具體實現步驟如下:
?
?
?
go標準庫中解密即實現了對計時***的防范,代碼如下:
?
//加密
//m為明文
//(pub.E, pub.N)為公鑰
//c為密文
func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {
e := big.NewInt(int64(pub.E))
c.Exp(m, e, pub.N)
return c
}
//解密
//傳入random支持防范計時***
func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err error) {
if c.Cmp(priv.N) > 0 {
err = ErrDecryption
return
}
if priv.N.Sign() == 0 {
return nil, ErrDecryption
}
var ir *big.Int
if random != nil {
var r *big.Int
for {
//步驟1產生0至n-1之間隨機數r
r, err = rand.Int(random, priv.N)
if err != nil {
return
}
if r.Cmp(bigZero) == 0 {
r = bigOne
}
var ok bool
//r的模n的乘法逆元ir,步驟4中使用
ir, ok = modInverse(r, priv.N)
if ok {
break
}
}
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 = cCopy
}
if priv.Precomputed.Dp == nil {
//步驟3,使用C'計算對應的M'
m = new(big.Int).Exp(c, priv.D, priv.N)
} else {
//略
}
if ir != nil {
//步驟4計算實際的M
m.Mul(m, ir)
m.Mod(m, priv.N)
}
return
}
//代碼位置src/crypto/rsa/rsa.go
?
非對稱加密算法,除支持加密外,還可以實現簽名。原理如下:
?
簽名:
1、提取消息摘要,使用發送方私鑰對消息摘要加密,生成消息簽名。
2、將消息簽名和消息一起,使用接收方公鑰加密,獲得密文。
?
驗簽:
1、使用接收方私鑰對密文解密,獲得消息和消息簽名。
2、使用發送方公鑰解密消息簽名,獲得消息摘要。
3、使用相同辦法重新提取消息摘要,與上一步中消息摘要對比,如相同則驗簽成功。
?
附示意圖如下:
?
?
?
//簽名
func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) {
//哈希提取消息摘要
hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
if err != nil {
return nil, err
}
tLen := len(prefix) + hashLen
k := (priv.N.BitLen() + 7) / 8
if k < tLen+11 {
return nil, ErrMessageTooLong
}
// EM = 0x00 || 0x01 || PS || 0x00 || T
em := make([]byte, k)
em[1] = 1
for i := 2; i < k-tLen-1; i++ {
em[i] = 0xff
}
//整合消息摘要和消息體
copy(em[k-tLen:k-hashLen], prefix)
copy(em[k-hashLen:k], hashed)
m := new(big.Int).SetBytes(em)
//使用發送方私鑰加密消息摘要和消息體,即為簽名
c, err := decryptAndCheck(rand, priv, m)
if err != nil {
return nil, err
}
copyWithLeftPad(em, c.Bytes())
return em, nil
}
//驗證簽名
func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error {
//哈希提取消息摘要
hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
if err != nil {
return err
}
tLen := len(prefix) + hashLen
k := (pub.N.BitLen() + 7) / 8
if k < tLen+11 {
return ErrVerification
}
c := new(big.Int).SetBytes(sig)
//使用發送方公鑰解密,提取消息體和消息簽名
m := encrypt(new(big.Int), pub, c)
em := leftPad(m.Bytes(), k)
// EM = 0x00 || 0x01 || PS || 0x00 || T
//對比發送方和接收方消息體、以及消息簽名
ok := subtle.ConstantTimeByteEq(em[0], 0)
ok &= subtle.ConstantTimeByteEq(em[1], 1)
ok &= subtle.ConstantTimeCompare(em[k-hashLen:k], hashed)
ok &= subtle.ConstantTimeCompare(em[k-tLen:k-hashLen], prefix)
ok &= subtle.ConstantTimeByteEq(em[k-tLen-1], 0)
for i := 2; i < k-tLen-1; i++ {
ok &= subtle.ConstantTimeByteEq(em[i], 0xff)
}
if ok != 1 {
return ErrVerification
}
return nil
}
//代碼位置src/crypto/rsa/pkcs1v15.go
?
?
RSA算法中使用了大量數論知識,有關數論知識還有待學習。待續。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。