什么是RSA
RSA是1977年由羅納德·李維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)一起提出的甲雅。當(dāng)時他們?nèi)硕荚诼槭±砉W(xué)院工作。RSA就是他們?nèi)诵帐祥_頭字母拼在一起組成的。
RSA可以被用于公鑰密碼和數(shù)字簽名。
RSA加密解密
公鑰加密->私鑰解密 (接收者密鑰對)
公鑰與密鑰的產(chǎn)生
假設(shè)Alice想要通過一個不可靠的媒體接收Bob的一條私人訊息宏所。她可以用以下的方式來產(chǎn)生一個公鑰和一個私鑰:
- 隨意選擇兩個大的質(zhì)數(shù)p和q,p不等于q叽掘,計(jì)算N=pq楣铁。
- 根據(jù)歐拉函數(shù),求得r = (p-1)(q-1)
- 選擇一個小于 r 的整數(shù)* e*更扁,求得 e 關(guān)于模 r 的模反元素盖腕,命名為d赫冬。(模反元素存在,當(dāng)且僅當(dāng)e與r互質(zhì))
- 將* p 和 q *的記錄銷毀溃列。
(N,e)是公鑰劲厌,(N,d)是私鑰。Alice將她的公鑰(N,e)傳給Bob听隐,而將她的私鑰(N,d)藏起來补鼻。
加密消息
假設(shè)Bob想給Alice送一個消息m,他知道Alice產(chǎn)生的N和e雅任。他使用起先與Alice約好的格式將m轉(zhuǎn)換為一個小于N的整數(shù)n风范,比如他可以將每一個字轉(zhuǎn)換為這個字的Unicode碼,然后將這些數(shù)字連在一起組成一個數(shù)字沪么。假如他的信息非常長的話硼婿,他可以將這個信息分為幾段,然后將每一段轉(zhuǎn)換為n禽车。用下面這個公式他可以將n加密為c:
ne ≡ c (mod N)
計(jì)算c并不復(fù)雜寇漫。Bob算出c后就可以將它傳遞給Alice。
解密消息
Alice得到Bob的消息c后就可以利用她的密鑰d來解碼殉摔。她可以用以下這個公式來將c轉(zhuǎn)換為n:
cd ≡ n (mod N)
得到n后州胳,她可以將原來的信息m重新復(fù)原。
解碼的原理是:
cd ≡ n e·d(mod N)
以及ed ≡ 1 (mod p-1)和ed ≡ 1 (mod q-1)逸月。由費(fèi)馬小定理可證明(因?yàn)?em>p和q是質(zhì)數(shù))
n e·d ≡ n (mod p) 和 n e·d ≡ n (mod q)
這說明(因?yàn)?em>p和q是不同的質(zhì)數(shù)栓撞,所以p和q互質(zhì))
n e·d ≡ n (mod pq)
簽名消息
私鑰加密->公鑰解密過程 (發(fā)送者密鑰對)
作用
1、數(shù)據(jù)完整性2彻采、數(shù)據(jù)來源的安全性
RSA也可以用來為一個消息署名腐缤。假如甲想給乙傳遞一個署名的消息的話捌归,那么她可以為她的消息計(jì)算一個散列值(Message digest)肛响,然后用她的密鑰(private key)加密這個散列值并將這個“署名”加在消息的后面。這個消息只有用她的公鑰才能被解密惜索。乙獲得這個消息后可以用甲的公鑰解密這個散列值特笋,然后將這個數(shù)據(jù)與他自己為這個消息計(jì)算的散列值相比較。假如兩者相符的話巾兆,那么他就可以知道發(fā)信人持有甲的密鑰猎物,以及這個消息在傳播路徑上沒有被篡改過。
圖解:
方式一:使用RSA完成簽名驗(yàn)簽過程
代碼實(shí)現(xiàn) :
package main
import (
"crypto"
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"fmt"
)
//rsa加密解密 簽名驗(yàn)簽
func main() {
//生成私鑰
priv, e := rsa.GenerateKey(rand.Reader, 1024)
if e != nil {
fmt.Println(e)
}
//根據(jù)私鑰產(chǎn)生公鑰
pub := &priv.PublicKey
//明文
plaintext := []byte("Hello world")
//加密生成密文
fmt.Printf("%q\n加密:\n", plaintext)
ciphertext, e := rsa.EncryptOAEP(md5.New(), rand.Reader, pub, plaintext, nil)
if e != nil {
fmt.Println(e)
}
fmt.Printf("\t%x\n", ciphertext)
//解密得到明文
fmt.Printf("解密:\n")
plaintext, e = rsa.DecryptOAEP(md5.New(), rand.Reader, priv, ciphertext, nil)
if e != nil {
fmt.Println(e)
}
fmt.Printf("\t%q\n", plaintext)
//消息先進(jìn)行Hash處理
h := md5.New()
h.Write(plaintext)
hashed := h.Sum(nil)
fmt.Printf("%q MD5 Hashed:\n\t%x\n", plaintext, hashed)
//簽名
opts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthAuto, Hash: crypto.MD5}
sig, e := rsa.SignPSS(rand.Reader, priv, crypto.MD5, hashed, opts)
if e != nil {
fmt.Println(e)
}
fmt.Printf("簽名:\n\t%x\n", sig)
//認(rèn)證
fmt.Printf("驗(yàn)證結(jié)果:")
if e := rsa.VerifyPSS(pub, crypto.MD5, hashed, sig, opts); e != nil {
fmt.Println("失敗:", e)
} else {
fmt.Println("成功.")
}
}
簽名方式二:使用DSA完成簽名驗(yàn)簽過程
DSA是基于整數(shù)有限域離散對數(shù)難題的角塑,其安全性與RSA相比差不多蔫磨。DSA的一個重要特點(diǎn)是兩個素數(shù)公開,這樣圃伶,當(dāng)使用別人的p和q時堤如,即使不知道私鑰蒲列,你也能確認(rèn)它們是否是隨機(jī)產(chǎn)生的,還是作了手腳搀罢。RSA算法卻做不到蝗岖。
DSA是Schnorr算法與ElGammal方式的變體,只能被用于數(shù)字簽名榔至。
代碼實(shí)現(xiàn):
package main
import (
"crypto/dsa"
"crypto/rand"
"fmt"
)
/*
DSA只能做簽名 驗(yàn)簽 無法做加密
*/
func main() {
var params dsa.Parameters
//生成參數(shù)
dsa.GenerateParameters(¶ms,rand.Reader,dsa.L1024N160)
//生成私鑰
var priv dsa.PrivateKey
priv.Parameters = params
dsa.GenerateKey(&priv,rand.Reader)
//根據(jù)私鑰生成公鑰
pub := priv.PublicKey
//利用私鑰簽名數(shù)據(jù)
msg := []byte("hello world")
r,s,_ :=dsa.Sign(rand.Reader,&priv,msg)
//公鑰驗(yàn)簽
b := dsa.Verify(&pub,msg,r,s)
if b == true {
fmt.Println("驗(yàn)證成功")
}
}