mirror of
https://github.com/golang/go
synced 2024-11-18 09:04:49 -07:00
crypto/rsa: implement crypto.Decrypter
Decrypter is an interface to support opaque private keys that perform decryption operations. This interface is analogous to the crypto.Signer interface. This change introduces the crypto.Decrypter interface and implements the crypto.Decrypter interface for rsa.PrivateKey with both OAEP and PKCS#1 v1.5 padding modes. Change-Id: I433f649f84ed3c2148337d735cafd75f1d94a904 Reviewed-on: https://go-review.googlesource.com/3900 Reviewed-by: Adam Langley <agl@golang.org>
This commit is contained in:
parent
fa97136038
commit
0a048ce5e9
@ -124,3 +124,19 @@ type SignerOpts interface {
|
|||||||
// hashing was done.
|
// hashing was done.
|
||||||
HashFunc() Hash
|
HashFunc() Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decrypter is an interface for an opaque private key that can be used for
|
||||||
|
// asymmetric decryption operations. For example, an RSA key kept in a hardware
|
||||||
|
// module.
|
||||||
|
type Decrypter interface {
|
||||||
|
// Public returns the public key corresponding to the opaque,
|
||||||
|
// private key.
|
||||||
|
Public() PublicKey
|
||||||
|
|
||||||
|
// Decrypt decrypts msg. The opts argument should be appropriate for
|
||||||
|
// the primitive used. See the documentation in each implementation for
|
||||||
|
// details.
|
||||||
|
Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DecrypterOpts interface{}
|
||||||
|
@ -14,6 +14,16 @@ import (
|
|||||||
|
|
||||||
// This file implements encryption and decryption using PKCS#1 v1.5 padding.
|
// This file implements encryption and decryption using PKCS#1 v1.5 padding.
|
||||||
|
|
||||||
|
// PKCS1v15DecrypterOpts is for passing options to PKCS#1 v1.5 decryption using
|
||||||
|
// the crypto.Decrypter interface.
|
||||||
|
type PKCS1v15DecryptOptions struct {
|
||||||
|
// SessionKeyLen is the length of the session key that is being
|
||||||
|
// decrypted. If not zero, then a padding error during decryption will
|
||||||
|
// cause a random plaintext of this length to be returned rather than
|
||||||
|
// an error. These alternatives happen in constant time.
|
||||||
|
SessionKeyLen int
|
||||||
|
}
|
||||||
|
|
||||||
// EncryptPKCS1v15 encrypts the given message with RSA and the padding scheme from PKCS#1 v1.5.
|
// EncryptPKCS1v15 encrypts the given message with RSA and the padding scheme from PKCS#1 v1.5.
|
||||||
// The message must be no longer than the length of the public modulus minus 11 bytes.
|
// The message must be no longer than the length of the public modulus minus 11 bytes.
|
||||||
// WARNING: use of this function to encrypt plaintexts other than session keys
|
// WARNING: use of this function to encrypt plaintexts other than session keys
|
||||||
|
@ -51,14 +51,25 @@ var decryptPKCS1v15Tests = []DecryptPKCS1v15Test{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDecryptPKCS1v15(t *testing.T) {
|
func TestDecryptPKCS1v15(t *testing.T) {
|
||||||
for i, test := range decryptPKCS1v15Tests {
|
decryptionFuncs := []func([]byte) ([]byte, error){
|
||||||
out, err := DecryptPKCS1v15(nil, rsaPrivateKey, decodeBase64(test.in))
|
func(ciphertext []byte) (plaintext []byte, err error) {
|
||||||
if err != nil {
|
return DecryptPKCS1v15(nil, rsaPrivateKey, ciphertext)
|
||||||
t.Errorf("#%d error decrypting", i)
|
},
|
||||||
}
|
func(ciphertext []byte) (plaintext []byte, err error) {
|
||||||
want := []byte(test.out)
|
return rsaPrivateKey.Decrypt(nil, ciphertext, nil)
|
||||||
if !bytes.Equal(out, want) {
|
},
|
||||||
t.Errorf("#%d got:%#v want:%#v", i, out, want)
|
}
|
||||||
|
|
||||||
|
for _, decryptFunc := range decryptionFuncs {
|
||||||
|
for i, test := range decryptPKCS1v15Tests {
|
||||||
|
out, err := decryptFunc(decodeBase64(test.in))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("#%d error decrypting", i)
|
||||||
|
}
|
||||||
|
want := []byte(test.out)
|
||||||
|
if !bytes.Equal(out, want) {
|
||||||
|
t.Errorf("#%d got:%#v want:%#v", i, out, want)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,6 +149,22 @@ func TestEncryptPKCS1v15SessionKey(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEncryptPKCS1v15DecrypterSessionKey(t *testing.T) {
|
||||||
|
for i, test := range decryptPKCS1v15SessionKeyTests {
|
||||||
|
plaintext, err := rsaPrivateKey.Decrypt(rand.Reader, decodeBase64(test.in), &PKCS1v15DecryptOptions{SessionKeyLen: 4})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("#%d: error decrypting: %s", i, err)
|
||||||
|
}
|
||||||
|
if len(plaintext) != 4 {
|
||||||
|
t.Fatalf("#%d: incorrect length plaintext: got %d, want 4", i, len(plaintext))
|
||||||
|
}
|
||||||
|
|
||||||
|
if test.out != "FAIL" && !bytes.Equal(plaintext, []byte(test.out)) {
|
||||||
|
t.Errorf("#%d: incorrect plaintext: got %x, want %x", plaintext, test.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNonZeroRandomBytes(t *testing.T) {
|
func TestNonZeroRandomBytes(t *testing.T) {
|
||||||
random := rand.Reader
|
random := rand.Reader
|
||||||
|
|
||||||
|
@ -24,6 +24,16 @@ type PublicKey struct {
|
|||||||
E int // public exponent
|
E int // public exponent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OAEPOptions is an interface for passing options to OAEP decryption using the
|
||||||
|
// crypto.Decrypter interface.
|
||||||
|
type OAEPOptions struct {
|
||||||
|
// Hash is the hash function that will be used when generating the mask.
|
||||||
|
Hash crypto.Hash
|
||||||
|
// Label is an arbitrary byte string that must be equal to the value
|
||||||
|
// used when encrypting.
|
||||||
|
Label []byte
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errPublicModulus = errors.New("crypto/rsa: missing public modulus")
|
errPublicModulus = errors.New("crypto/rsa: missing public modulus")
|
||||||
errPublicExponentSmall = errors.New("crypto/rsa: public exponent too small")
|
errPublicExponentSmall = errors.New("crypto/rsa: public exponent too small")
|
||||||
@ -77,6 +87,37 @@ func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts)
|
|||||||
return SignPKCS1v15(rand, priv, opts.HashFunc(), msg)
|
return SignPKCS1v15(rand, priv, opts.HashFunc(), msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decrypt decrypts ciphertext with priv. If opts is nil or of type
|
||||||
|
// *PKCS1v15DecryptOptions then PKCS#1 v1.5 decryption is performed. Otherwise
|
||||||
|
// opts must have type *OAEPOptions and OAEP decryption is done.
|
||||||
|
func (priv *PrivateKey) Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) {
|
||||||
|
if opts == nil {
|
||||||
|
return DecryptPKCS1v15(rand, priv, ciphertext)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch opts := opts.(type) {
|
||||||
|
case *OAEPOptions:
|
||||||
|
return DecryptOAEP(opts.Hash.New(), rand, priv, ciphertext, opts.Label)
|
||||||
|
|
||||||
|
case *PKCS1v15DecryptOptions:
|
||||||
|
if l := opts.SessionKeyLen; l > 0 {
|
||||||
|
plaintext = make([]byte, l)
|
||||||
|
if _, err := rand.Read(plaintext); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := DecryptPKCS1v15SessionKey(rand, priv, ciphertext, plaintext); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return plaintext, nil
|
||||||
|
} else {
|
||||||
|
return DecryptPKCS1v15(rand, priv, ciphertext)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, errors.New("crypto/rsa: invalid options for Decrypt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type PrecomputedValues struct {
|
type PrecomputedValues struct {
|
||||||
Dp, Dq *big.Int // D mod (P-1) (or mod Q-1)
|
Dp, Dq *big.Int // D mod (P-1) (or mod Q-1)
|
||||||
Qinv *big.Int // Q^-1 mod P
|
Qinv *big.Int // Q^-1 mod P
|
||||||
|
Loading…
Reference in New Issue
Block a user