首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

crypto/rsa

  • import "crypto/rsa"
  • 概述
  • 索引
  • 示例

概述

软件包 rsa 按照 PKCS#1 中的规定实现 RSA 加密。

RSA 是一个单一的基本操作,用于实现公钥加密或公钥签名。

RSA的原始加密和签名规范是 PKCS#1,默认情况下,术语“RSA encryption”和“RSA signatures”是指 PKCS#1 1.5版本。但是,该规范存在缺陷,新设计应该使用版本2,通常只需通过 OAEP 和 PSS 即可调用。

该套件包含两套接口。当一个更抽象的接口不是必需的时候,可以使用 v1.5/OAEP 进行加密(encrypting)/解密(decrypting)以及使用 v1.5/PSS 进行签名/验证。如果需要通过公钥基元进行抽象,那么 PrivateKey 结构将从加密包中实现 Decrypter 和 Signer 接口。

此包中的 RSA 操作不是使用恒定时间算法实现的。

索引

  • 常量
  • 变量
  • 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

包文件

常量

代码语言:txt
复制
const (
        // PSSSaltLengthAuto导致PSS签名中的salt一样大
        // 签名时尽可能,并在验证时自动检测。
        PSSSaltLengthAuto = 0
        // PSSSaltLengthEqualsHash使salt长度等于长度
        // 签名中使用的哈希值
        PSSSaltLengthEqualsHash = -1
)

变量

ErrDecryption 表示解密消息失败。故意避免适应性攻击是模糊的。

代码语言:javascript
复制
var ErrDecryption = errors.New("crypto/rsa: decryption error")

尝试加密对于公钥大小来说太大的消息时会返回 ErrMessageTooLong。

代码语言:javascript
复制
var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA public key size")

ErrVerification 表示验证签名失败。故意避免适应性攻击是模糊的。

代码语言:javascript
复制
var ErrVerification = errors.New("crypto/rsa: verification error")

func DecryptOAEP(查看源代码)

代码语言:javascript
复制
func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) ([]byte, error)

OAEP 通过散列函数进行参数化,散列函数用作随机预言器。给定消息的加密和解密必须使用相同的散列函数,sha256.New() 是一个合理的选择。

随机参数(如果不是零)用于隐藏私钥操作并避免定时旁信道攻击。盲目性仅限于此函数 - 随机数据不需要与加密时使用的数据相匹配。

标签参数必须与加密时给出的值匹配。有关详细信息,请参阅 EncryptOAEP。

示例

代码:

代码语言:txt
复制
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))

// 请记住,加密仅提供机密性。该
// 密文应该在假定真实性之前签署,甚至
// 甚至,考虑消息可能会被重新排序。

func DecryptPKCS1v15(查看源代码)

代码语言:javascript
复制
func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) ([]byte, error)

DecryptPKCS1v15 使用 RSA和PKCS#1 v1.5 的填充方案解密明文。如果 rand!= nil,它使用RSA盲法来避免定时侧信道攻击。

请注意,该函数是否返回错误或不公开秘密信息。如果攻击者可以导致这个函数重复运行并且知道每个实例是否返回错误,那么他们可以解密并伪造签名,就好像他们拥有私钥一样。请参阅 DecryptPKCS1v15SessionKey 以解决此问题。

func DecryptPKCS1v15SessionKey(查看源代码)

代码语言:javascript
复制
func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) error

DecryptPKCS1v15SessionKey 使用 RSA 和 PKCS#1 v1.5 中的填充方案来解密会话密钥。如果rand != nil,则它使用 RSA 致盲来避免定时旁路通道攻击。如果密文长度不正确或者密文大于公共模数,它将返回一个错误。否则,不会返回错误。如果填充有效,则将生成的明文消息复制到密钥中。否则,密钥不变。这些替代方案会在一段时间内发生 预期该功能的用户预先生成一个随机会话密钥,然后继续使用所得值的协议。这将消除攻击者可以获知有关明文的任何信息的可能性。请参阅“Chosen Ciphertext Attacks Against Protocols Based on the RSA Encryption Standard PKCS #1(基于RSA加密标准PKCS#1选择的针对协议的密文攻击)”, Daniel Bleichenbacher, Advances in Cryptology (Crypto '98)。

请注意,如果会话密钥太小,攻击者可能会对其进行暴力破解。如果他们可以这样做,那么他们可以知道是否使用了随机值(因为它对于相同的密文会有所不同),因此是否填充是正确的。这打破了这个功能的重点。使用至少一个16字节的密钥可以防止这种攻击。

示例

RSA 只能加密非常有限的数据量。为了加密合理数量的数据,通常使用混合方案:RSA 用于加密对称原语(如AES-GCM)的密钥。在加密之前,通过将数据嵌入到已知结构中来“padded”数据。这是由于许多原因,但最明显的是确保值足够大,以使得指数大于模数。(否则可以用平方根进行解密)。在这些设计中,使用 PKCS#1 v1.5 时,避免公开接收到的 RSA 消息是否格式良好(也就是解密结果是正确填充的消息),因为这泄漏了秘密信息。DecryptPKCS1v15SessionKey 专为这种情况而设计,并将解密,对称密钥(如果格式良好)通过包含随机密钥的缓冲区进行常量化。因此,如果 RSA 结果不是格式良好的,那么实现会在一段时间内使用一个随机密钥。

代码:

代码语言:txt
复制
// crypto/rand.Reader是阻塞RSA的良好熵源
// 操作。
rng := rand.Reader

// 混合方案应该使用至少一个16字节的对称密钥。 这里
// 我们读取了RSA解密时不会使用的随机密钥
// 良好的。
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 {
        // 任何导致的错误都将是“public” - 意味着它们
        // 可以确定没有任何秘密信息。 (对于
        // 例如,如果给定RSA,则密钥的长度是不可能的
        // 公钥。)
        fmt.Fprintf(os.Stderr, "Error from RSA decryption: %s\n", err)
        return
}

// 给定得到的密钥,可以使用对称方案来解密a
// 更大的密文。
block, err := aes.NewCipher(key)
if err != nil {
        panic("aes.NewCipher failed: " + err.Error())
}

// 由于密钥是随机的,因此使用固定的随机数是可以接受的
// 根据需要,(key, nonce)对仍然是唯一的。
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密文形成错误; 解密会
        // 因为AES-GCM密钥不正确而在这里失败。
        fmt.Fprintf(os.Stderr, "Error decrypting: %s\n", err)
        return
}

fmt.Printf("Plaintext: %s\n", string(plaintext))

func EncryptOAEP(查看源代码)

代码语言:javascript
复制
func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error)

EncryptOAEP 使用 RSA-OAEP 加密给定的消息。

OAEP 通过散列函数进行参数化,散列函数用作随机预言器。给定消息的加密和解密必须使用相同的散列函数,sha256.New() 是一个合理的选择。

随机参数被用作熵的来源以确保两次加密相同的消息不会导致相同的密文。

标签参数可以包含任何不会被加密的数据,但是它给消息提供了重要的上下文。例如,如果使用给定的公钥来解密两种类型的消息,则可以使用不同的标签值来确保用于一个目的的密文不能被攻击者用于另一个目的。如果不需要,它可以是空的。

消息必须不超过公共模数的长度减去散列长度的两倍,再减去2。

示例

代码:

代码语言:txt
复制
secretMessage := []byte("send reinforcements, we're going to advance")
label := []byte("orders")

// crypto/rand.Reader是随机化的一个很好的熵源
// 加密函数。
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
}

// 由于加密是随机函数,密文将是
// 每次都不一样。
fmt.Printf("Ciphertext: %x\n", ciphertext)

func EncryptPKCS1v15(查看源代码)

代码语言:javascript
复制
func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) ([]byte, error)

EncryptPKCS1v15 使用 RSA 和 PKCS#1 v1.5 中的填充方案加密给定的消息。消息必须不超过公共模数减去11个字节的长度。

rand 参数被用作熵的来源以确保两次加密相同的消息不会导致相同的密文。

警告:使用此功能来加密会话密钥以外的明文是很危险的。在新协议中使用 RSA OAEP。

func SignPKCS1v15(查看源代码)

代码语言:javascript
复制
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 计算散列签名。请注意,散列必须是使用给定散列函数散列输入消息的结果。如果散列值为零,则直接对散列值进行签名。除互操作性之外,这不可取。

如果 rand 不是零,那么将使用 RSA 致盲来避免定时旁路信道攻击。

这个功能是确定性的。因此,如果这组可能的消息很小,攻击者可能能够从消息到签名建立一个映射并识别签名的消息。与以往一样,签名提供真实性,而不是保密性。

示例

代码:

代码语言:txt
复制
// crypto/rand.Reader是阻塞RSA的良好熵源
// 操作
rng := rand.Reader

message := []byte("message to be signed")

// 只能直接签署小邮件; 因此以下的哈希
// 消息,而不是消息本身,签署。 这需要
// 哈希函数是抗冲突的。 SHA-256是
// 当时应该使用的最强哈希函数
// 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)
代码语言:javascript
复制
func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) ([]byte, error)

SignPSS 使用 RSASSA-PSS 1 计算散列的签名。注意,散列必须是使用给定散列函数散列输入消息的结果。opts 参数可能为零,在这种情况下,使用明智的默认值。

func VerifyPKCS1v15(查看源代码)

代码语言:javascript
复制
func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error

VerifyPKCS1v15 验证 RSA PKCS#1 v1.5 签名。散列是使用给定散列函数散列输入消息的结果,sig 是签名。返回零错误表示有效签名。如果散列值为零,则直接使用散列值。除互操作性之外,这不可取。

示例

代码:

代码语言:txt
复制
message := []byte("message to be signed")
signature, _ := hex.DecodeString("ad2766728615cc7a746cc553916380ca7bfa4f8983b990913bc69eb0556539a350ff0f8fe65ddfd3ebe91fe1c299c2fac135bc8c61e26be44ee259f2f80c1530")

// 只能直接签署小邮件; 因此以下的哈希
// 消息,而不是消息本身,签署。 这需要
// 哈希函数是抗冲突的。 SHA-256是
// 当时应该使用的最强哈希函数
// 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(查看源代码)

代码语言:javascript
复制
func VerifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, opts *PSSOptions) error

VerifyPSS 验证 PSS 签名。散列是使用给定散列函数散列输入消息的结果,sig 是签名。返回零错误表示有效签名。opts 参数可能为零,在这种情况下,使用明智的默认值。

CRTValue包含预先计算的中国剩余定理值。

代码语言:txt
复制
type CRTValue struct {
        Exp   *big.Int // D mod (prime-1).
        Coeff *big.Int // R·Coeff ≡ 1 mod Prime.
        R     *big.Int // 在此之前的素数乘积(inc p和q)。
}

type OAEPOptions(查看源代码)

OAEPOptions 是使用 crypto.Decrypter 接口将选项传递给 OAEP 解密的接口。

代码语言:txt
复制
type OAEPOptions struct {
        // 散列是生成掩码时将使用的散列函数。
        Hash crypto.Hash
        // Label是一个任意字节字符串,必须等于该值
        // 加密时使用。
        Label []byte
}

type PKCS1v15DecryptOptions(查看源代码)

PKCS1v15DecrypterOpts 用于使用 crypto.Decrypter 接口将选项传递给 PKCS#1 v1.5 解密。

代码语言:txt
复制
type PKCS1v15DecryptOptions struct {
        // SessionKeyLen是正在进行的会话密钥的长度
        // 解密。 如果不为零,则解密期间的填充错误将
        // 导致返回此长度的随机明文而不是
        // 一个错误。 这些替代方案在不断的时间内发
        SessionKeyLen int
}

type PSSOptions(查看源代码)

PSSOptions 包含用于创建和验证 PSS 签名的选项。

代码语言:txt
复制
type PSSOptions struct {
        // SaltLength 控制 PSS 中使用的salt 的长度
        // 签名。 它可以是多个字节,也可以是特殊字节之一
        // PSSSaltLength常数。
        SaltLength int

        // 散列(如果不为零)会覆盖传递给SignPSS的散列函数。
        // 这是使用时指定哈希函数的唯一方法
        // crypto.Signer接口。
        Hash crypto.Hash
}

func (*PSSOptions) HashFunc(查看源代码)

代码语言:javascript
复制
func (pssOpts *PSSOptions) HashFunc() crypto.Hash

HashFunc 返回 pssOpts.Hash,以便 PSSOptions 实现 crypto.SignerOpts。

type PrecomputedValues(查看源代码)

代码语言:txt
复制
type PrecomputedValues struct {
        Dp, Dq *big.Int // D mod (P-1) (or mod Q-1)
        Qinv   *big.Int // Q^-1 mod P

        // CRTValues用于第3和随后的素数。 由于一个
        // 历史事故,处理前两个素数的CRT
        // 在PKCS#1中有所不同,互操作性足够
        // 重要的是我们反映了这一点
        CRTValues []CRTValue
}

type PrivateKey(查看源代码)

一个 PrivateKey 表示一个 RSA 密钥

代码语言:txt
复制
type PrivateKey struct {
        PublicKey            // 公共部分。
        D         *big.Int   // 私有指数
        Primes    []*big.Int // N的素因子有> = 2个元素。

        // 预计算包含加速私有的预计算值
        // 操作,如果有的话。
        Precomputed PrecomputedValues
}

func GenerateKey(查看源代码)

代码语言:javascript
复制
func GenerateKey(random io.Reader, bits int) (*PrivateKey, error)

GenerateKey 使用随机源随机(例如,crypto/rand.Reader)生成给定位大小的 RSA 密钥对。

func GenerateMultiPrimeKey(查看源代码)

代码语言:javascript
复制
func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey, error)

GenerateMultiPrimeKey 生成一个给定位大小的多素数 RSA 密钥对和给定的随机源,如1所示。虽然公钥与2素的情况相兼容(实际上难以区分),但私钥不是。因此,可能无法以某些格式导出多主密钥私钥或随后将其导入其他代码。

表1中的2表示给定大小的素数的最大数目。

func (*PrivateKey) Decrypt(查看源代码)

代码语言:javascript
复制
func (priv *PrivateKey) Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error)

解密用 priv 解密密文。如果 opts 为零或类型为 * PKCS1v15DecryptOptions,则执行 PKCS#1 v1.5 解密。否则,opts 必须具有类型 * OAEPOptions,并且完成 OAEP 解密。

func (*PrivateKey) Precompute(查看源代码)

代码语言:javascript
复制
func (priv *PrivateKey) Precompute()

预计算执行一些计算,以加速未来的私钥操作。

func (*PrivateKey) Public(查看源代码)

代码语言:javascript
复制
func (priv *PrivateKey) Public() crypto.PublicKey

公共返回与 priv 相对应的公钥。

func (*PrivateKey) Sign(查看源代码)

代码语言:javascript
复制
func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error)

用 priv 签名msg,从 rand 中读取随机数。如果opts 是 *PSSOptions,那么将使用 PSS 算法,否则将使用 PKCS#1 v1.5。此方法旨在支持保留私有部分的密钥,例如,硬件模块。常见用法应该在这个包中使用 Sign* 函数。

func (*PrivateKey) Validate(查看源代码)

代码语言:javascript
复制
func (priv *PrivateKey) Validate() error

验证对密钥执行基本的完整性检查。如果密钥有效,则返回nil,否则返回描述问题的错误。

type PublicKey(查看源代码)

公钥代表 RSA 密钥的公共部分。

代码语言:txt
复制
type PublicKey struct {
        N *big.Int // 模块
        E int      // 公共指数
}

扫码关注腾讯云开发者

领取腾讯云代金券