用 Golang 實現 RSA 加密和簽名
RSA(Rivest–Shamir–Adleman)加密是使用最廣的安全數據加密算法之一。
它是一種非對稱加密算法,也叫”單向加密 “。用這種方式,任何人都可以很容易地對數據進行加密,而只有用正確的” 祕鑰“才能解密。
RSA 加密,一言以蔽之
RSA 是通過生成一個公鑰和一個私鑰進行加 / 解密的。公鑰和私鑰是一起生成的,組成一對祕鑰對。
這意味着我們可以把我們的公鑰給任何想給的人。之後他們可以把想發送給我們的信息進行加密,唯一能訪問這些信息的方式就是用我們的私鑰進行解密。
祕鑰的生成過程,以及信息的加密解密過程不在本文討論範圍內,但是如果你想研究詳細信息,這裏有一個關於此主題的強大視頻 [2]。
祕鑰的生成
我們要做的第一件事就是生成公鑰私鑰對。這些祕鑰是隨機生成的,在後面所有的處理中都會用到。
我們用標準庫 crypto/rsa[3] 來生成祕鑰,用 crypto/rand[4] 庫來生成隨機數。
// The GenerateKey method takes in a reader that returns random bits, and
// the number of bits
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
// The public key is a part of the *rsa.PrivateKey struct
publicKey := privateKey.PublicKey
// use the public and private keys
// ...
publicKey
和 privateKey
變量分別用於加密和解密。
加密
我們用 EncryptOEAP[5] 函數來加密一串隨機的信息。我們需要爲這個函數提供一些輸入:
-
一個哈希函數,用了它之後要能保證即使輸入做了微小的改變,輸出哈希也會變化很大。SHA256 適合於此。
-
一個用來生成隨機位的 random reader,這樣相同的內容重複輸入時就不會有相同的輸出
-
之前生成的公鑰
-
我們想加密的信息
-
可選的標籤參數(本文中我們忽略)
encryptedBytes, err := rsa.EncryptOAEP(
sha256.New(),
rand.Reader,
&publicKey,
[]byte("super secret message"),
nil)
if err != nil {
panic(err)
}
fmt.Println("encrypted bytes: ", encryptedBytes)
這段代碼會打印加密後的字節,看起來有點像無用的信息。
解密
如果想訪問加密字節承載的信息,就需要對它們進行解密。
解密它們的唯一方法就是使用與加密時的公鑰對應的私鑰。
*rsa.PrivateKey
結構體有一個方法 Decrypt[6],我們使用這個方法從加密數據中解出原始的信息。
解密時我們需要輸入的參數有:1. 被加密的數據(稱爲_密文_)2. 加密數據用的哈希
// The first argument is an optional random data generator (the rand.Reader we used before)
// we can set this value as nil
// The OEAPOptions in the end signify that we encrypted the data using OEAP, and that we used
// SHA256 to hash the input.
decryptedBytes, err := privateKey.Decrypt(nil, encryptedBytes, &rsa.OAEPOptions{Hash: crypto.SHA256})
if err != nil {
panic(err)
}
// We get back the original information in the form of bytes, which we
// the cast to a string and print
fmt.Println("decrypted message: ", string(decryptedBytes))
簽名和校驗
RSA 祕鑰也用於簽名和校驗。簽名不同於加密,簽名可以讓你宣示真實性,而不是機密性。
也就是說,由原始信息生成一段數據,稱爲 “簽名”,而不是僞裝原始信息的內容(像加密 [7] 中做的那樣)。
請注意,只有擁有私鑰的人才能對信息進行簽名,但是有公鑰的人可以驗證它。
msg := []byte("verifiable message")
// Before signing, we need to hash our message
// The hash is what we actually sign
msgHash := sha256.New()
_, err = msgHash.Write(msg)
if err != nil {
panic(err)
}
msgHashSum := msgHash.Sum(nil)
// In order to generate the signature, we provide a random number generator,
// our private key, the hashing algorithm that we used, and the hash sum
// of our message
signature, err := rsa.SignPSS(rand.Reader, privateKey, crypto.SHA256, msgHashSum, nil)
if err != nil {
panic(err)
}
// To verify the signature, we provide the public key, the hashing algorithm
// the hash sum of our message and the signature we generated previously
// there is an optional "options" parameter which can omit for now
err = rsa.VerifyPSS(&publicKey, crypto.SHA256, msgHashSum, signature, nil)
if err != nil {
fmt.Println("could not verify signature: ", err)
return
}
// If we don't get any error from the `VerifyPSS` method, that means our
// signature is valid
fmt.Println("signature verified")
總結
本文中我們看到了如何生成 RSA 公鑰和私鑰,以及怎樣使用它們進行加密、解密、簽名和驗證任意數據。
在將它們用於你的數據之前,你需要了解一些使用限制。首先,你要加密的數據必須比你的祕鑰短。例如,EncryptOAEP 文檔 [8] 中說 “(要加密的)信息不能比公佈的模數減去哈希長度的兩倍後再減去 2 長”。
使用的哈希算法要適合你的需求。SHA256(在本例中用的就是 SHA256)可以用於大部分案例,但是如果是對數據要求更高的應用,你可能需要用 SHA512。
你可以在這裏 [9] 找到所有示例的源碼。
via: https://www.sohamkamani.com/golang/rsa-encryption/
作者:Soham Kamani[10] 譯者:lxbwolf[11] 校對:polaris1119[12]
本文由 GCTT[13] 原創編譯,Go 中文網 [14] 榮譽推出
參考資料
[1] 這裏: https://gist.github.com/sohamkamani/08377222d5e3e6bc130827f83b0c073e
[2] 強大視頻: https://www.youtube.com/watch?v=wXB-V_Keiu8
[3] crypto/rsa: https://pkg.go.dev/crypto/rsa?tab=doc
[4] crypto/rand: https://pkg.go.dev/crypto/rand?tab=doc
[5] EncryptOEAP: https://pkg.go.dev/crypto/rsa?tab=doc#EncryptOAEP
[6] Decrypt: https://pkg.go.dev/crypto/rsa?tab=doc#PrivateKey.Decrypt
[7] 加密: https://www.sohamkamani.com/golang/rsa-encryption/#encryption
[8] EncryptOAEP 文檔: https://pkg.go.dev/crypto/rsa?tab=doc#EncryptOAEP
[9] 這裏: https://gist.github.com/sohamkamani/08377222d5e3e6bc130827f83b0c073e
[10] Soham Kamani: https://twitter.com/sohamkamani
[11] lxbwolf: https://github.com/lxbwolf
[12] polaris1119: https://github.com/polaris1119
[13] GCTT: https://github.com/studygolang/GCTT
[14] Go 中文網: https://studygolang.com/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/w976zzchogZy8xkWGN--Ww