go rsa解密
go 官方API 支持的是掩码函数和掩码参数一致。因为我需要使用SHA-256掩码函数,SHA-1掩码参数索引把官方源码拿出来改了一点。
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/sha256"
"crypto/subtle"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
"hash"
"io"
"math/big"
"sync"
)
func RasDecryption(plainText []byte, privateKey []byte) ([]byte, error) {
base64DecodeBytes, err := base64.StdEncoding.DecodeString(string(plainText))
publicDecodBlock, _ := pem.Decode(privateKey)
keyResult, err := x509.ParsePKCS8PrivateKey(publicDecodBlock.Bytes)
if err != nil {
return nil, fmt.Errorf("parse error")
}
priv := keyResult.(*rsa.PrivateKey)
decryption, err := DecryptOAEP(sha256.New(), rand.Reader, priv, base64DecodeBytes, nil)
if err != nil {
return nil, err
}
return decryption, nil
}
// func main() {
// str := "GDgJtSIBO3n1z85CHn1CIZmUoUEy2hHub6xiqD3/E1gy/3wSuh3sMledLPKixvT1REXnmmif+2cEhLjhSeBQohwthBg2Q97xQOWr0IgVxtc5bjURwhy/NzxW0sRmC/hzhemYfj5cUnJ+4CjacC0g/iDEB9iaywLa8trhXqGkSF8wW66tadRNxQX5aV4e6BEpa3LzxPNB050yMTt14fWNQ9sO3apSdgqVuQnSBoYp30DcRFBqxHWs5gmJmJ7cb/gyHKYQbqfBtlAC8BeZDtDEQ+Iti60ce+VRX9+r/j+OfVXnb7bDGyHmqPBP7W5+wLiBqt2F1pQNLXaYpFH52F1a0e0FySw2W+RcKpjDuChmWXtfH3brfF6e6icM0Z6DiYJblQfEVibeJEFtppibnJwpDkt66FBy6xJ9nyMWVc7For/ql2+Eg8wwd5ql1ki7fW6XZOhe8xIvO8RuG2yMtvSNnr/jXXVkoso5zMsIKzXwgV77ezF3vg3eTa+NC6erQXJB"
// origData, err := RasDecryption([]byte(str), PrivateKey)
// if err != nil {
// panic(err)
// }
// fmt.Println("解密数据:", string(origData))
// }
var (
errPublicModulus = errors.New("crypto/rsa: missing public modulus")
errPublicExponentSmall = errors.New("crypto/rsa: public exponent too small")
errPublicExponentLarge = errors.New("crypto/rsa: public exponent too large")
)
// ErrDecryption represents a failure to decrypt a message.
// It is deliberately vague to avoid adaptive attacks.
var ErrDecryption = errors.New("crypto/rsa: decryption error")
// ErrVerification represents a failure to verify a signature.
// It is deliberately vague to avoid adaptive attacks.
var ErrVerification = errors.New("crypto/rsa: verification error")
func checkPub(pub *rsa.PublicKey) error {
if pub.N == nil {
return errPublicModulus
}
if pub.E < 2 {
return errPublicExponentSmall
}
if pub.E > 1<<31-1 {
return errPublicExponentLarge
}
return nil
}
func DecryptOAEP(hash hash.Hash, random io.Reader, priv *rsa.PrivateKey, ciphertext []byte, label []byte) ([]byte, error) {
if err := checkPub(&priv.PublicKey); err != nil {
return nil, err
}
k := priv.Size()
if len(ciphertext) > k ||
k < hash.Size()*2+2 {
return nil, ErrDecryption
}
c := new(big.Int).SetBytes(ciphertext)
m, err := decrypt(random, priv, c)
if err != nil {
return nil, err
}
hash.Write(label)
lHash := hash.Sum(nil)
hash.Reset()
// We probably leak the number of leading zeros.
// It's not clear that we can do anything about this.
em := m.FillBytes(make([]byte, k))
firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0)
seed := em[1 : hash.Size()+1]
db := em[hash.Size()+1:]
// 此处设置掩码参数
mgf1XOR(seed, sha1.New(), db)
mgf1XOR(db, sha1.New(), seed)
lHash2 := db[0:hash.Size()]
// We have to validate the plaintext in constant time in order to avoid
// attacks like: J. Manger. A Chosen Ciphertext Attack on RSA Optimal
// Asymmetric Encryption Padding (OAEP) as Standardized in PKCS #1
// v2.0. In J. Kilian, editor, Advances in Cryptology.
lHash2Good := subtle.ConstantTimeCompare(lHash, lHash2)
// The remainder of the plaintext must be zero or more 0x00, followed
// by 0x01, followed by the message.
// lookingForIndex: 1 iff we are still looking for the 0x01
// index: the offset of the first 0x01 byte
// invalid: 1 iff we saw a non-zero byte before the 0x01.
var lookingForIndex, index, invalid int
lookingForIndex = 1
rest := db[hash.Size():]
for i := 0; i < len(rest); i++ {
equals0 := subtle.ConstantTimeByteEq(rest[i], 0)
equals1 := subtle.ConstantTimeByteEq(rest[i], 1)
index = subtle.ConstantTimeSelect(lookingForIndex&equals1, i, index)
lookingForIndex = subtle.ConstantTimeSelect(equals1, 0, lookingForIndex)
invalid = subtle.ConstantTimeSelect(lookingForIndex&^equals0, 1, invalid)
}
if firstByteIsZero&lHash2Good&^invalid&^lookingForIndex != 1 {
return nil, ErrDecryption
}
return rest[index+1:], nil
}
var bigZero = big.NewInt(0)
var bigOne = big.NewInt(1)
// decrypt performs an RSA decryption, resulting in a plaintext integer. If a
// random source is given, RSA blinding is used.
func decrypt(random io.Reader, priv *rsa.PrivateKey, c *big.Int) (m *big.Int, err error) {
if c.Cmp(priv.N) > 0 {
err = ErrDecryption
return
}
if priv.N.Sign() == 0 {
return nil, ErrDecryption
}
var ir *big.Int
if random != nil {
MaybeReadByte(random)
// Blinding enabled. Blinding involves multiplying c by r^e.
// Then the decryption operation performs (m^e * r^e)^d mod n
// which equals mr mod n. The factor of r can then be removed
// by multiplying by the multiplicative inverse of r.
var r *big.Int
ir = new(big.Int)
for {
r, err = rand.Int(random, priv.N)
if err != nil {
return
}
if r.Cmp(bigZero) == 0 {
r = bigOne
}
ok := ir.ModInverse(r, priv.N)
if ok != nil {
break
}
}
bigE := big.NewInt(int64(priv.E))
rpowe := new(big.Int).Exp(r, bigE, priv.N) // N != 0
cCopy := new(big.Int).Set(c)
cCopy.Mul(cCopy, rpowe)
cCopy.Mod(cCopy, priv.N)
c = cCopy
}
if priv.Precomputed.Dp == nil {
m = new(big.Int).Exp(c, priv.D, priv.N)
} else {
// We have the precalculated values needed for the CRT.
m = new(big.Int).Exp(c, priv.Precomputed.Dp, priv.Primes[0])
m2 := new(big.Int).Exp(c, priv.Precomputed.Dq, priv.Primes[1])
m.Sub(m, m2)
if m.Sign() < 0 {
m.Add(m, priv.Primes[0])
}
m.Mul(m, priv.Precomputed.Qinv)
m.Mod(m, priv.Primes[0])
m.Mul(m, priv.Primes[1])
m.Add(m, m2)
for i, values := range priv.Precomputed.CRTValues {
prime := priv.Primes[2+i]
m2.Exp(c, values.Exp, prime)
m2.Sub(m2, m)
m2.Mul(m2, values.Coeff)
m2.Mod(m2, prime)
if m2.Sign() < 0 {
m2.Add(m2, prime)
}
m2.Mul(m2, values.R)
m.Add(m, m2)
}
}
if ir != nil {
// Unblind.
m.Mul(m, ir)
m.Mod(m, priv.N)
}
return
}
var (
closedChanOnce sync.Once
closedChan chan struct{}
)
// MaybeReadByte reads a single byte from r with ~50% probability. This is used
// to ensure that callers do not depend on non-guaranteed behaviour, e.g.
// assuming that rsa.GenerateKey is deterministic w.r.t. a given random stream.
//
// This does not affect tests that pass a stream of fixed bytes as the random
// source (e.g. a zeroReader).
func MaybeReadByte(r io.Reader) {
closedChanOnce.Do(func() {
closedChan = make(chan struct{})
close(closedChan)
})
select {
case <-closedChan:
return
case <-closedChan:
var buf [1]byte
r.Read(buf[:])
}
}
// mgf1XOR XORs the bytes in out with a mask generated using the MGF1 function
// specified in PKCS #1 v2.1.
func mgf1XOR(out []byte, hash hash.Hash, seed []byte) {
var counter [4]byte
var digest []byte
done := 0
for done < len(out) {
hash.Write(seed)
hash.Write(counter[0:4])
digest = hash.Sum(digest[:0])
hash.Reset()
for i := 0; i < len(digest) && done < len(out); i++ {
out[done] ^= digest[i]
done++
}
incCounter(&counter)
}
}
// incCounter increments a four byte, big-endian counter.
func incCounter(c *[4]byte) {
if c[3]++; c[3] != 0 {
return
}
if c[2]++; c[2] != 0 {
return
}
if c[1]++; c[1] != 0 {
return
}
c[0]++
}