Commit 0a048ce5 authored by Nick Sullivan's avatar Nick Sullivan Committed by Adam Langley

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/3900Reviewed-by: 's avatarAdam Langley <agl@golang.org>
parent fa971360
......@@ -124,3 +124,19 @@ type SignerOpts interface {
// hashing was done.
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.
// 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.
// 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
......
......@@ -51,14 +51,25 @@ var decryptPKCS1v15Tests = []DecryptPKCS1v15Test{
}
func TestDecryptPKCS1v15(t *testing.T) {
for i, test := range decryptPKCS1v15Tests {
out, err := DecryptPKCS1v15(nil, rsaPrivateKey, 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)
decryptionFuncs := []func([]byte) ([]byte, error){
func(ciphertext []byte) (plaintext []byte, err error) {
return DecryptPKCS1v15(nil, rsaPrivateKey, ciphertext)
},
func(ciphertext []byte) (plaintext []byte, err error) {
return rsaPrivateKey.Decrypt(nil, ciphertext, nil)
},
}
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) {
random := rand.Reader
......
......@@ -24,6 +24,16 @@ type PublicKey struct {
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 (
errPublicModulus = errors.New("crypto/rsa: missing public modulus")
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)
}
// 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 {
Dp, Dq *big.Int // D mod (P-1) (or mod Q-1)
Qinv *big.Int // Q^-1 mod P
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment