go rsa解密 (RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING)

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]++
	}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值