?
This document uses PHP Chinese website manual Release
import "crypto/rsa"
概述
索引
示例
軟件包 rsa 按照 PKCS#1 中的規(guī)定實(shí)現(xiàn) RSA 加密。
RSA 是一個(gè)單一的基本操作,用于實(shí)現(xiàn)公鑰加密或公鑰簽名。
RSA的原始加密和簽名規(guī)范是 PKCS#1,默認(rèn)情況下,術(shù)語“RSA encryption”和“RSA signatures”是指 PKCS#1 1.5版本。但是,該規(guī)范存在缺陷,新設(shè)計(jì)應(yīng)該使用版本2,通常只需通過 OAEP 和 PSS 即可調(diào)用。
該套件包含兩套接口。當(dāng)一個(gè)更抽象的接口不是必需的時(shí)候,可以使用 v1.5/OAEP 進(jìn)行加密(encrypting)/解密(decrypting)以及使用 v1.5/PSS 進(jìn)行簽名/驗(yàn)證。如果需要通過公鑰基元進(jìn)行抽象,那么 PrivateKey 結(jié)構(gòu)將從加密包中實(shí)現(xiàn) Decrypter 和 Signer 接口。
此包中的 RSA 操作不是使用恒定時(shí)間算法實(shí)現(xiàn)的。
常量
變量
func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) ([]byte, error)
func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) ([]byte, error)
func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) error
func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error)
func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) ([]byte, error)
func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error)
func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) ([]byte, error)
func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error
func VerifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, opts *PSSOptions) error
type CRTValue
type OAEPOptions
type PKCS1v15DecryptOptions
type PSSOptions
func (pssOpts *PSSOptions) HashFunc() crypto.Hash
type PrecomputedValues
type PrivateKey
func GenerateKey(random io.Reader, bits int) (*PrivateKey, error)
func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey, error)
func (priv *PrivateKey) Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error)
func (priv *PrivateKey) Precompute()
func (priv *PrivateKey) Public() crypto.PublicKey
func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error)
func (priv *PrivateKey) Validate() error
type PublicKey
DecryptOAEP DecryptPKCS1v15SessionKey EncryptOAEP SignPKCS1v15 VerifyPKCS1v15
pkcs1v15.go pss.go rsa.go
const ( // PSSSaltLengthAuto導(dǎo)致PSS簽名中的salt一樣大 // 簽名時(shí)盡可能,并在驗(yàn)證時(shí)自動(dòng)檢測(cè)。 PSSSaltLengthAuto = 0 // PSSSaltLengthEqualsHash使salt長(zhǎng)度等于長(zhǎng)度 // 簽名中使用的哈希值 PSSSaltLengthEqualsHash = -1)
ErrDecryption 表示解密消息失敗。故意避免適應(yīng)性攻擊是模糊的。
var ErrDecryption = errors.New("crypto/rsa: decryption error")
嘗試加密對(duì)于公鑰大小來說太大的消息時(shí)會(huì)返回 ErrMessageTooLong。
var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA public key size")
ErrVerification 表示驗(yàn)證簽名失敗。故意避免適應(yīng)性攻擊是模糊的。
var ErrVerification = errors.New("crypto/rsa: verification error")
func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) ([]byte, error)
OAEP 通過散列函數(shù)進(jìn)行參數(shù)化,散列函數(shù)用作隨機(jī)預(yù)言器。給定消息的加密和解密必須使用相同的散列函數(shù),sha256.New() 是一個(gè)合理的選擇。
隨機(jī)參數(shù)(如果不是零)用于隱藏私鑰操作并避免定時(shí)旁信道攻擊。盲目性僅限于此函數(shù) - 隨機(jī)數(shù)據(jù)不需要與加密時(shí)使用的數(shù)據(jù)相匹配。
標(biāo)簽參數(shù)必須與加密時(shí)給出的值匹配。有關(guān)詳細(xì)信息,請(qǐng)參閱 EncryptOAEP。
代碼:
ciphertext, _ := hex.DecodeString("4d1ee10e8f286390258c51a5e80802844c3e6358ad6690b7285218a7c7ed7fc3a4c7b950fbd04d4b0239cc060dcc7065ca6f84c1756deb71ca5685cadbb82be025e16449b905c568a19c088a1abfad54bf7ecc67a7df39943ec511091a34c0f2348d04e058fcff4d55644de3cd1d580791d4524b92f3e91695582e6e340a1c50b6c6d78e80b4e42c5b4d45e479b492de42bbd39cc642ebb80226bb5200020d501b24a37bcc2ec7f34e596b4fd6b063de4858dbf5a4e3dd18e262eda0ec2d19dbd8e890d672b63d368768360b20c0b6b8592a438fa275e5fa7f60bef0dd39673fd3989cc54d2cb80c08fcd19dacbc265ee1c6014616b0e04ea0328c2a04e73460")label := []byte("orders")// crypto / rand.Reader是阻塞RSA的良好熵源// 操作。rng := rand.Reader plaintext, err := DecryptOAEP(sha256.New(), rng, test2048Key, ciphertext, label)if err != nil { fmt.Fprintf(os.Stderr, "Error from decryption: %s\n", err) return}fmt.Printf("Plaintext: %s\n", string(plaintext))// 請(qǐng)記住,加密僅提供機(jī)密性。該// 密文應(yīng)該在假定真實(shí)性之前簽署,甚至// 甚至,考慮消息可能會(huì)被重新排序。
func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) ([]byte, error)
DecryptPKCS1v15 使用 RSA和PKCS#1 v1.5 的填充方案解密明文。如果 rand!= nil,它使用RSA盲法來避免定時(shí)側(cè)信道攻擊。
請(qǐng)注意,該函數(shù)是否返回錯(cuò)誤或不公開秘密信息。如果攻擊者可以導(dǎo)致這個(gè)函數(shù)重復(fù)運(yùn)行并且知道每個(gè)實(shí)例是否返回錯(cuò)誤,那么他們可以解密并偽造簽名,就好像他們擁有私鑰一樣。請(qǐng)參閱 DecryptPKCS1v15SessionKey 以解決此問題。
func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) error
DecryptPKCS1v15SessionKey 使用 RSA 和 PKCS#1 v1.5 中的填充方案來解密會(huì)話密鑰。如果rand != nil,則它使用 RSA 致盲來避免定時(shí)旁路通道攻擊。如果密文長(zhǎng)度不正確或者密文大于公共模數(shù),它將返回一個(gè)錯(cuò)誤。否則,不會(huì)返回錯(cuò)誤。如果填充有效,則將生成的明文消息復(fù)制到密鑰中。否則,密鑰不變。這些替代方案會(huì)在一段時(shí)間內(nèi)發(fā)生 預(yù)期該功能的用戶預(yù)先生成一個(gè)隨機(jī)會(huì)話密鑰,然后繼續(xù)使用所得值的協(xié)議。這將消除攻擊者可以獲知有關(guān)明文的任何信息的可能性。請(qǐng)參閱“Chosen Ciphertext Attacks Against Protocols Based on the RSA Encryption Standard PKCS #1(基于RSA加密標(biāo)準(zhǔn)PKCS#1選擇的針對(duì)協(xié)議的密文攻擊)”, Daniel Bleichenbacher, Advances in Cryptology (Crypto '98)。
請(qǐng)注意,如果會(huì)話密鑰太小,攻擊者可能會(huì)對(duì)其進(jìn)行暴力破解。如果他們可以這樣做,那么他們可以知道是否使用了隨機(jī)值(因?yàn)樗鼘?duì)于相同的密文會(huì)有所不同),因此是否填充是正確的。這打破了這個(gè)功能的重點(diǎn)。使用至少一個(gè)16字節(jié)的密鑰可以防止這種攻擊。
RSA 只能加密非常有限的數(shù)據(jù)量。為了加密合理數(shù)量的數(shù)據(jù),通常使用混合方案:RSA 用于加密對(duì)稱原語(如AES-GCM)的密鑰。在加密之前,通過將數(shù)據(jù)嵌入到已知結(jié)構(gòu)中來“padded”數(shù)據(jù)。這是由于許多原因,但最明顯的是確保值足夠大,以使得指數(shù)大于模數(shù)。(否則可以用平方根進(jìn)行解密)。在這些設(shè)計(jì)中,使用 PKCS#1 v1.5 時(shí),避免公開接收到的 RSA 消息是否格式良好(也就是解密結(jié)果是正確填充的消息),因?yàn)檫@泄漏了秘密信息。DecryptPKCS1v15SessionKey 專為這種情況而設(shè)計(jì),并將解密,對(duì)稱密鑰(如果格式良好)通過包含隨機(jī)密鑰的緩沖區(qū)進(jìn)行常量化。因此,如果 RSA 結(jié)果不是格式良好的,那么實(shí)現(xiàn)會(huì)在一段時(shí)間內(nèi)使用一個(gè)隨機(jī)密鑰。
代碼:
// crypto/rand.Reader是阻塞RSA的良好熵源// 操作。rng := rand.Reader// 混合方案應(yīng)該使用至少一個(gè)16字節(jié)的對(duì)稱密鑰。 這里// 我們讀取了RSA解密時(shí)不會(huì)使用的隨機(jī)密鑰// 良好的。key := make([]byte, 32)if _, err := io.ReadFull(rng, key); err != nil { panic("RNG failure")}rsaCiphertext, _ := hex.DecodeString("aabbccddeeff")if err := DecryptPKCS1v15SessionKey(rng, rsaPrivateKey, rsaCiphertext, key); err != nil { // 任何導(dǎo)致的錯(cuò)誤都將是“public” - 意味著它們 // 可以確定沒有任何秘密信息。 (對(duì)于 // 例如,如果給定RSA,則密鑰的長(zhǎng)度是不可能的 // 公鑰。) fmt.Fprintf(os.Stderr, "Error from RSA decryption: %s\n", err) return}// 給定得到的密鑰,可以使用對(duì)稱方案來解密a// 更大的密文。block, err := aes.NewCipher(key)if err != nil { panic("aes.NewCipher failed: " + err.Error())}// 由于密鑰是隨機(jī)的,因此使用固定的隨機(jī)數(shù)是可以接受的// 根據(jù)需要,(key, nonce)對(duì)仍然是唯一的。var zeroNonce [12]byte aead, err := cipher.NewGCM(block)if err != nil { panic("cipher.NewGCM failed: " + err.Error())}ciphertext, _ := hex.DecodeString("00112233445566")plaintext, err := aead.Open(nil, zeroNonce[:], ciphertext, nil)if err != nil { // RSA密文形成錯(cuò)誤; 解密會(huì) // 因?yàn)锳ES-GCM密鑰不正確而在這里失敗。 fmt.Fprintf(os.Stderr, "Error decrypting: %s\n", err) return}fmt.Printf("Plaintext: %s\n", string(plaintext))
func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error)
EncryptOAEP 使用 RSA-OAEP 加密給定的消息。
OAEP 通過散列函數(shù)進(jìn)行參數(shù)化,散列函數(shù)用作隨機(jī)預(yù)言器。給定消息的加密和解密必須使用相同的散列函數(shù),sha256.New() 是一個(gè)合理的選擇。
隨機(jī)參數(shù)被用作熵的來源以確保兩次加密相同的消息不會(huì)導(dǎo)致相同的密文。
標(biāo)簽參數(shù)可以包含任何不會(huì)被加密的數(shù)據(jù),但是它給消息提供了重要的上下文。例如,如果使用給定的公鑰來解密兩種類型的消息,則可以使用不同的標(biāo)簽值來確保用于一個(gè)目的的密文不能被攻擊者用于另一個(gè)目的。如果不需要,它可以是空的。
消息必須不超過公共模數(shù)的長(zhǎng)度減去散列長(zhǎng)度的兩倍,再減去2。
代碼:
secretMessage := []byte("send reinforcements, we're going to advance")label := []byte("orders")// crypto/rand.Reader是隨機(jī)化的一個(gè)很好的熵源// 加密函數(shù)。rng := rand.Reader ciphertext, err := EncryptOAEP(sha256.New(), rng, &test2048Key.PublicKey, secretMessage, label)if err != nil { fmt.Fprintf(os.Stderr, "Error from encryption: %s\n", err) return}// 由于加密是隨機(jī)函數(shù),密文將是// 每次都不一樣。fmt.Printf("Ciphertext: %x\n", ciphertext)
func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) ([]byte, error)
EncryptPKCS1v15 使用 RSA 和 PKCS#1 v1.5 中的填充方案加密給定的消息。消息必須不超過公共模數(shù)減去11個(gè)字節(jié)的長(zhǎng)度。
rand 參數(shù)被用作熵的來源以確保兩次加密相同的消息不會(huì)導(dǎo)致相同的密文。
警告:使用此功能來加密會(huì)話密鑰以外的明文是很危險(xiǎn)的。在新協(xié)議中使用 RSA OAEP。
func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error)
SignPKCS1v15 使用來自 RSA PKCS#1 v1.5 的 RSASSA-PKCS1-V1_5-SIGN 計(jì)算散列簽名。請(qǐng)注意,散列必須是使用給定散列函數(shù)散列輸入消息的結(jié)果。如果散列值為零,則直接對(duì)散列值進(jìn)行簽名。除互操作性之外,這不可取。
如果 rand 不是零,那么將使用 RSA 致盲來避免定時(shí)旁路信道攻擊。
這個(gè)功能是確定性的。因此,如果這組可能的消息很小,攻擊者可能能夠從消息到簽名建立一個(gè)映射并識(shí)別簽名的消息。與以往一樣,簽名提供真實(shí)性,而不是保密性。
代碼:
// crypto/rand.Reader是阻塞RSA的良好熵源// 操作rng := rand.Reader message := []byte("message to be signed")// 只能直接簽署小郵件; 因此以下的哈希// 消息,而不是消息本身,簽署。 這需要// 哈希函數(shù)是抗沖突的。 SHA-256是// 當(dāng)時(shí)應(yīng)該使用的最強(qiáng)哈希函數(shù)// writing(2016)。hashed := sha256.Sum256(message)signature, err := SignPKCS1v15(rng, rsaPrivateKey, crypto.SHA256, hashed[:])if err != nil { fmt.Fprintf(os.Stderr, "Error from signing: %s\n", err) return}fmt.Printf("Signature: %x\n", signature)
func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) ([]byte, error)
SignPSS 使用 RSASSA-PSS 1 計(jì)算散列的簽名。注意,散列必須是使用給定散列函數(shù)散列輸入消息的結(jié)果。opts 參數(shù)可能為零,在這種情況下,使用明智的默認(rèn)值。
func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error
VerifyPKCS1v15 驗(yàn)證 RSA PKCS#1 v1.5 簽名。散列是使用給定散列函數(shù)散列輸入消息的結(jié)果,sig 是簽名。返回零錯(cuò)誤表示有效簽名。如果散列值為零,則直接使用散列值。除互操作性之外,這不可取。
代碼:
message := []byte("message to be signed")signature, _ := hex.DecodeString("ad2766728615cc7a746cc553916380ca7bfa4f8983b990913bc69eb0556539a350ff0f8fe65ddfd3ebe91fe1c299c2fac135bc8c61e26be44ee259f2f80c1530")// 只能直接簽署小郵件; 因此以下的哈希// 消息,而不是消息本身,簽署。 這需要// 哈希函數(shù)是抗沖突的。 SHA-256是// 當(dāng)時(shí)應(yīng)該使用的最強(qiáng)哈希函數(shù)// writing (2016)。hashed := sha256.Sum256(message)err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.SHA256, hashed[:], signature)if err != nil { fmt.Fprintf(os.Stderr, "Error from verification: %s\n", err) return}// 簽名是來自公鑰的消息的有效簽名。
func VerifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, opts *PSSOptions) error
VerifyPSS 驗(yàn)證 PSS 簽名。散列是使用給定散列函數(shù)散列輸入消息的結(jié)果,sig 是簽名。返回零錯(cuò)誤表示有效簽名。opts 參數(shù)可能為零,在這種情況下,使用明智的默認(rèn)值。
CRTValue包含預(yù)先計(jì)算的中國(guó)剩余定理值。
type CRTValue struct { Exp *big.Int // D mod (prime-1). Coeff *big.Int // R·Coeff ≡ 1 mod Prime. R *big.Int // 在此之前的素?cái)?shù)乘積(inc p和q)。}
OAEPOptions 是使用 crypto.Decrypter 接口將選項(xiàng)傳遞給 OAEP 解密的接口。
type OAEPOptions struct { // 散列是生成掩碼時(shí)將使用的散列函數(shù)。 Hash crypto.Hash // Label是一個(gè)任意字節(jié)字符串,必須等于該值 // 加密時(shí)使用。 Label []byte}
PKCS1v15DecrypterOpts 用于使用 crypto.Decrypter 接口將選項(xiàng)傳遞給 PKCS#1 v1.5 解密。
type PKCS1v15DecryptOptions struct { // SessionKeyLen是正在進(jìn)行的會(huì)話密鑰的長(zhǎng)度 // 解密。 如果不為零,則解密期間的填充錯(cuò)誤將 // 導(dǎo)致返回此長(zhǎng)度的隨機(jī)明文而不是 // 一個(gè)錯(cuò)誤。 這些替代方案在不斷的時(shí)間內(nèi)發(fā) SessionKeyLen int}
PSSOptions 包含用于創(chuàng)建和驗(yàn)證 PSS 簽名的選項(xiàng)。
type PSSOptions struct { // SaltLength 控制 PSS 中使用的salt 的長(zhǎng)度 // 簽名。 它可以是多個(gè)字節(jié),也可以是特殊字節(jié)之一 // PSSSaltLength常數(shù)。 SaltLength int // 散列(如果不為零)會(huì)覆蓋傳遞給SignPSS的散列函數(shù)。 // 這是使用時(shí)指定哈希函數(shù)的唯一方法 // crypto.Signer接口。 Hash crypto.Hash}
func (pssOpts *PSSOptions) HashFunc() crypto.Hash
HashFunc 返回 pssOpts.Hash,以便 PSSOptions 實(shí)現(xiàn) crypto.SignerOpts。
type PrecomputedValues struct { Dp, Dq *big.Int // D mod (P-1) (or mod Q-1) Qinv *big.Int // Q^-1 mod P // CRTValues用于第3和隨后的素?cái)?shù)。 由于一個(gè) // 歷史事故,處理前兩個(gè)素?cái)?shù)的CRT // 在PKCS#1中有所不同,互操作性足夠 // 重要的是我們反映了這一點(diǎn) CRTValues []CRTValue}
一個(gè) PrivateKey 表示一個(gè) RSA 密鑰
type PrivateKey struct { PublicKey // 公共部分。 D *big.Int // 私有指數(shù) Primes []*big.Int // N的素因子有> = 2個(gè)元素。 // 預(yù)計(jì)算包含加速私有的預(yù)計(jì)算值 // 操作,如果有的話。 Precomputed PrecomputedValues}
func GenerateKey(random io.Reader, bits int) (*PrivateKey, error)
GenerateKey 使用隨機(jī)源隨機(jī)(例如,crypto/rand.Reader)生成給定位大小的 RSA 密鑰對(duì)。
func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey, error)
GenerateMultiPrimeKey 生成一個(gè)給定位大小的多素?cái)?shù) RSA 密鑰對(duì)和給定的隨機(jī)源,如1所示。雖然公鑰與2素的情況相兼容(實(shí)際上難以區(qū)分),但私鑰不是。因此,可能無法以某些格式導(dǎo)出多主密鑰私鑰或隨后將其導(dǎo)入其他代碼。
表1中的2表示給定大小的素?cái)?shù)的最大數(shù)目。
1 US patent 4405829 (1972, expired) 2(http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf)
func (priv *PrivateKey) Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error)
解密用 priv 解密密文。如果 opts 為零或類型為 * PKCS1v15DecryptOptions,則執(zhí)行 PKCS#1 v1.5 解密。否則,opts 必須具有類型 * OAEPOptions,并且完成 OAEP 解密。
func (priv *PrivateKey) Precompute()
預(yù)計(jì)算執(zhí)行一些計(jì)算,以加速未來的私鑰操作。
func (priv *PrivateKey) Public() crypto.PublicKey
公共返回與 priv 相對(duì)應(yīng)的公鑰。
func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error)
用 priv 簽名msg,從 rand 中讀取隨機(jī)數(shù)。如果opts 是 *PSSOptions,那么將使用 PSS 算法,否則將使用 PKCS#1 v1.5。此方法旨在支持保留私有部分的密鑰,例如,硬件模塊。常見用法應(yīng)該在這個(gè)包中使用 Sign* 函數(shù)。
func (priv *PrivateKey) Validate() error
驗(yàn)證對(duì)密鑰執(zhí)行基本的完整性檢查。如果密鑰有效,則返回nil,否則返回描述問題的錯(cuò)誤。
公鑰代表 RSA 密鑰的公共部分。
type PublicKey struct { N *big.Int // 模塊 E int // 公共指數(shù)}