堅(jiān)持原創(chuàng),如有錯(cuò)誤請(qǐng)指正
非對(duì)稱加密是區(qū)塊鏈常用的一類加密方式,比如說(shuō)有下面幾種:
RSA
secp256k1 (橢圓曲線)
ElGamal等等
接下來(lái)我會(huì)嘗試用明白易懂的語(yǔ)言講解
講解RSA之前,很多同學(xué)可能跟比特幣的簽名方式搞混,所以我就先簡(jiǎn)單的說(shuō)下比特幣轉(zhuǎn)賬簽名.比特幣采用UTXO模型(例子,我有5btc,我要給你轉(zhuǎn)1btc. 實(shí)際操作是5個(gè)btc全轉(zhuǎn)出,1btc給你,剩下4個(gè)btc再轉(zhuǎn)給我自己,每次交易等式都要配平),扯遠(yuǎn)了.
每次的轉(zhuǎn)賬記錄可以簡(jiǎn)單地看為
{
"付款地址":A
"收款地址":B
"轉(zhuǎn)賬數(shù)量":1btc
} ==>計(jì)算其hash為H
接下來(lái)我要把該交易發(fā)送到其他節(jié)點(diǎn),其他節(jié)點(diǎn)接收到廣播信息,會(huì)首先進(jìn)行驗(yàn)證,如果驗(yàn)證通過(guò)則會(huì)再次轉(zhuǎn)發(fā)到其他節(jié)點(diǎn)中, 最終交易池會(huì)選取該交易,等待礦工打包入?yún)^(qū)塊中(等待時(shí)間由網(wǎng)絡(luò)擁堵?tīng)顩r和手續(xù)費(fèi)等因素決定).
轉(zhuǎn)賬第一步,對(duì)這筆交易進(jìn)行消息摘要,也就是計(jì)算其hash,唯一的交易交易記錄有唯一的hash值,碰撞的概率接近于零.假設(shè)hash為H.
第二步,對(duì)這個(gè)hash進(jìn)行簽名,其實(shí)這里就是一個(gè)非對(duì)稱加密了.
使用我的賬戶的私鑰對(duì) H 進(jìn)行加密,得到一段密文.其他節(jié)點(diǎn)使用我的公鑰對(duì)其解密,得到一段代碼H2 . 如果H2與通過(guò)轉(zhuǎn)賬記錄計(jì)算得到的H相等,驗(yàn)證通過(guò).
簽名過(guò)程即為用私鑰對(duì)交易摘要的加密過(guò)程苛吱,驗(yàn)證過(guò)程為用公鑰解密的過(guò)程(實(shí)際上規(guī)則要更復(fù)雜一些,這里只是方便大家理解).
接下來(lái)初步的講下RSA
RSA也分為公鑰和私鑰
密文=明文(待加密) ^E(E次方) 再取N的余數(shù) ==>加密
明文(待加密)=密文 ^D(D次方) 再取N的余數(shù) ==>解密
與比特幣簽名不同的是,這里是公鑰加密,私鑰解密(加密快,解密慢)
比特幣簽名(加密)慢,驗(yàn)證(解密)快.
D 21616157824859089947467865763905877208766194802261304393547211764767872553922733033101317695599363434608856645166753
N 26861170560633109174956418630434195575102580750015151802056322369493708310600722979313108414200817132792257978619899
E 65537
將公鑰私鑰進(jìn)行打印,發(fā)現(xiàn)
公鑰格式{N E}
私鑰格式{{N E} D [..........]}
可以發(fā)現(xiàn),公鑰長(zhǎng)度較短, 私鑰長(zhǎng)度較長(zhǎng),私鑰中包含了 公鑰
接下來(lái)計(jì)算創(chuàng)建私鑰花費(fèi)的時(shí)間,直觀的讓你明白R(shí)SA的效率
func main() {
var timeSum time.Duration
i := 0
bits := 2304//創(chuàng)造自定義位數(shù)的key
for ; i < 60; {
now1 := time.Now()
test.GenerateRsaKey(bits)//調(diào)用test包下的方法
now2 := time.Now()
timeSub := now2.Sub(now1)
timeSum += timeSub
i++
fmt.Println("第", i, "次任務(wù),耗時(shí)毫秒數(shù)", timeSub.Nanoseconds()/1000000)
}
fmt.Println("平均毫秒數(shù)為", int64(timeSum.Nanoseconds())/int64(1000000)/int64(i), ",運(yùn)行次數(shù)為", i, ",位數(shù)為", bits)
}
func GenerateRsaKey(bits int) {
privateKey, _ := rsa.GenerateKey(rand.Reader, bits)
fmt.Println("D",privateKey.D)
fmt.Println("N",privateKey.N)
fmt.Println("E",privateKey.E)
}
不同長(zhǎng)度密鑰(單位bit),創(chuàng)建私鑰任務(wù)耗時(shí)如下
平均毫秒數(shù)為 1699 ,運(yùn)行次數(shù)為 60 ,位數(shù)為 2304
平均毫秒數(shù)為 885 ,運(yùn)行次數(shù)為 60 ,位數(shù)為 2048
平均毫秒數(shù)為 581 ,運(yùn)行次數(shù)為 60 ,位數(shù)為 1792
平均毫秒數(shù)為 79 ,運(yùn)行次數(shù)為 60 ,位數(shù)為 1024
平均毫秒數(shù)為 35 ,運(yùn)行次數(shù)為 60 ,位數(shù)為 768
平均毫秒數(shù)為 11 ,運(yùn)行次數(shù)為 60 ,位數(shù)為 512
平均毫秒數(shù)為 5 ,運(yùn)行次數(shù)為 60 ,位數(shù)為 384
隨著位數(shù)的提高,耗時(shí)指數(shù)性增長(zhǎng).
抗暴力破解能力對(duì)比圖,本圖截取自<應(yīng)用密碼學(xué)>.可以看出相同密鑰長(zhǎng)度,非對(duì)稱加密比不上對(duì)稱加密,而非對(duì)稱加密又是個(gè)極耗資源的算法.
生成公鑰私鑰
func GenerateRsaKey(bits int) {
privateKey, _ := rsa.GenerateKey(rand.Reader, bits)
//保存私鑰
//使用X509規(guī)范,對(duì)公鑰私鑰進(jìn)行格式化
x509PrivateKey := x509.MarshalPKCS1PrivateKey(privateKey)
//pem格式編碼 將所有內(nèi)容替換為0-9 a-z A-Z, 基于base64解碼 末尾=用于補(bǔ)齊,末尾=個(gè)數(shù)為0-2個(gè).
block := pem.Block{
Type: "pem私鑰",
Bytes: x509PrivateKey,
}
fmt.Println(block)
privateKeyFile, _ := os.Create("private.pem")
pem.Encode(privateKeyFile, &block)
privateKeyFile.Close()
//保存公鑰
x509publicKey := x509.MarshalPKCS1PublicKey(&privateKey.PublicKey)
publicBlock := pem.Block{
Type: "公鑰",
Bytes: x509publicKey,
}
publicKeyFile, _ := os.Create("public.pem")
pem.Encode(publicKeyFile, &publicBlock)
publicKeyFile.Close()
}
接下來(lái)進(jìn)行加密解密操作
代碼千篇一律
func main() {
var timeSum time.Duration
i := 0
bits := 2304//設(shè)置密鑰位數(shù)
for ; i < 100; {
now1 := time.Now()
////創(chuàng)造多長(zhǎng)的rsa
//test.GenerateRsaKey(bits)
//明文
text :=[]byte("我就是明文啦,要對(duì)我進(jìn)行加密")
rsa_encrypt := test.Rsa_Encrypt(text, "public.pem")
fmt.Println("密文為", string(rsa_encrypt))
rsa_decrypt := test.Rsa_Decrypt(rsa_encrypt, "private.pem")
fmt.Println("原文為", string(rsa_decrypt))
now2 := time.Now()
timeSub := now2.Sub(now1)
timeSum += timeSub
i++
fmt.Println("第", i, "次任務(wù),耗時(shí)毫秒數(shù)", timeSub.Nanoseconds()/1000000)
}
fmt.Println("平均毫秒數(shù)為", int64(timeSum.Nanoseconds())/int64(1000000)/int64(i), ",運(yùn)行次數(shù)為", i, ",位數(shù)為", bits)
fmt.Println("總耗時(shí)為", int64(timeSum.Nanoseconds())/int64(1000000), "毫秒")
}
被調(diào)用部分代碼
func Rsa_Encrypt(plainText []byte,path string) []byte{
//1.讀取文件
file, _ := os.Open(path)
// 獲取文件信息
fileInfo, _ := file.Stat()
//2.讀取文件的內(nèi)容 pem
data := make([]byte,fileInfo.Size())
file.Read(data)
//3.pem解碼 --- x509編碼的內(nèi)容
block, _ := pem.Decode(data)
//4.x509解碼(反序列化)
publicKey, _ := x509.ParsePKCS1PublicKey(block.Bytes)
cipherText, _ := rsa.EncryptPKCS1v15(rand.Reader, publicKey, plainText)
return cipherText
}
// 解密操作
func Rsa_Decrypt(cipherText []byte,path string) []byte{
//1.讀取文件
file, _ := os.Open(path)
//2.讀取文件的內(nèi)容
fileInfo, _ := file.Stat()
data := make([]byte,fileInfo.Size())
file.Read(data)
//3.pem 解碼
block, _ := pem.Decode(data)
//4.x509解碼
privateKey, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
//5. 解密操作
plainText, _ := rsa.DecryptPKCS1v15(rand.Reader, privateKey, cipherText)
return plainText
}
平均毫秒數(shù)為 15 ,運(yùn)行次數(shù)為 100 ,位數(shù)為 2304,總耗時(shí)為1506毫秒
平均毫秒數(shù)為 1 ,運(yùn)行次數(shù)為 100 ,位數(shù)為 768,總耗時(shí)為 155 毫秒
由此可見(jiàn),隨著位數(shù)的增加,加密解密操作耗時(shí)指數(shù)型增長(zhǎng),感興趣的可以與對(duì)稱加密進(jìn)行對(duì)比,對(duì)相同明文進(jìn)行加密解密,效率有極大不同. 對(duì)稱加密快很多.
接下來(lái)進(jìn)行一個(gè)實(shí)驗(yàn)
設(shè)置密鑰位數(shù) bits=768
明文為 sdfdsfsdggs1231241412`efwe23efqfeqafqawegeetwt23452346ty24wgesewrwqfsaegvsaedaesd3ear
運(yùn)行程序,輸出結(jié)果
密文為 !???y?m???"cj0!nt??g2cY???YJw@R????C'??&?D*'R0c?NU??^??W?i?????,g?ā???-??z]????"
??\N??
將明文結(jié)尾再添加X(jué)
明文為sdfdsfsdggs1231241412`efwe23efqfeqafqawegeetwt23452346ty24wgesewrwqfsaegvsaedaesd3earX
運(yùn)行程序
發(fā)現(xiàn)密文沒(méi)有輸出,原因是明文長(zhǎng)度超出范圍了.
現(xiàn)在對(duì)bits進(jìn)行操作,將768改為1024
運(yùn)行程序,這次有結(jié)果輸出了.
密文為 "L?????????d??'??U?JP???MT??k??? a??J??\???????\w????"':??qp;??.}_?????]?KF?????? ???(????F,?*??紛+?GA?x????6?N??? ?=???
為什么呢?
文章最上面說(shuō)過(guò)
密文=明文(待加密) ^E(E次方) 再取N的余數(shù)
也就是說(shuō)N限制了明文的最大長(zhǎng)度. 如果明文過(guò)長(zhǎng),就會(huì)發(fā)生碰撞(不同的明文產(chǎn)生了相同的密文,這里可以好好理解下),而N與密鑰長(zhǎng)度有關(guān).
1.可加密明文的最大長(zhǎng)度與密鑰長(zhǎng)度有關(guān),密鑰越長(zhǎng),可加密明文的最大長(zhǎng)度越長(zhǎng).
2.rsa可加密的數(shù)據(jù)仍然很小,傳輸大數(shù)據(jù)不太可能.
假設(shè)用rsa加密一部電影,需要將電影進(jìn)行拆分,分開(kāi)加密解密,按照非對(duì)稱加密的效率,幾十年可能都搞不定.
引申:加密大文件,要用對(duì)稱加密先加密,再將對(duì)稱加密的密鑰進(jìn)行非對(duì)稱加密.這樣就能兼顧效率和安全.