Beispiel #1
0
// Decrypt implements the crypto.Decrypter operation for the given key.
func (key *PrivateKey) Decrypt(rand io.Reader, msg []byte, opts crypto.DecrypterOpts) ([]byte, error) {
	switch opts := opts.(type) {
	case *rsa.PKCS1v15DecryptOptions:
		ptxt, decyptErr := key.execute(gokeyless.OpRSADecrypt, msg)

		// If opts.SessionKeyLen is set, we must perform a variation of
		// rsa.DecryptPKCS1v15SessionKey to ensure the entire operation
		// is performed in constant time regardless of padding errors.
		if l := opts.SessionKeyLen; l > 0 {
			plaintext := make([]byte, l)
			if _, err := io.ReadFull(rand, plaintext); err != nil {
				return nil, err
			}
			valid := subtle.ConstantTimeEq(int32(len(ptxt)), int32(l))
			v2 := subtle.ConstantTimeLessOrEq(l, len(ptxt))
			l2 := subtle.ConstantTimeSelect(v2, l, len(ptxt))
			subtle.ConstantTimeCopy(valid, plaintext[:l2], ptxt[:l2])
			return plaintext, nil
		}
		// Otherwise, we can just return the error like rsa.DecryptPKCS1v15.
		return ptxt, decyptErr
	default:
		return nil, errors.New("invalid options for Decrypt")
	}
}
Beispiel #2
0
// Decrypt implements the crypto.Decrypter operation for the given key.
func (key *PrivateKey) Decrypt(rand io.Reader, msg []byte, opts crypto.DecrypterOpts) ([]byte, error) {
	opts1v15, ok := opts.(*rsa.PKCS1v15DecryptOptions)
	if opts != nil && !ok {
		return nil, errors.New("invalid options for Decrypt")
	}

	ptxt, err := key.execute(gokeyless.OpRSADecrypt, msg)
	if err != nil {
		return nil, err
	}

	if ok {
		// If opts.SessionKeyLen is set, we must perform a variation of
		// rsa.DecryptPKCS1v15SessionKey to ensure the entire operation
		// is performed in constant time regardless of padding errors.
		if l := opts1v15.SessionKeyLen; l > 0 {
			plaintext := make([]byte, l)
			if _, err := io.ReadFull(rand, plaintext); err != nil {
				return nil, err
			}
			valid := subtle.ConstantTimeEq(int32(len(ptxt)), int32(l))
			v2 := subtle.ConstantTimeLessOrEq(l, len(ptxt))
			l2 := subtle.ConstantTimeSelect(v2, l, len(ptxt))
			subtle.ConstantTimeCopy(valid, plaintext[:l2], ptxt[:l2])
			return plaintext, nil
		}
	}
	return ptxt, nil
}
Beispiel #3
0
// pkcsUnpad implements PKCS#7 un-padding.  If the padding is valid a valid value of 1 is returned.
// If the padding is invalid, valid is returned as 0.  Any unpaddeddata value should not be used
// if pcksUnpad determines the padding is invalid.  A logic error returns an error.  If you
// have not already authenticated the ciphertext, reporting a padding error, even through side channels
// (like timing), leaves you open to padding oracle attacks, so beware.
//
// I am implementing pkcsPad with constant time operations to forestall timing attacks that might
// be used to create a padding oracle. Since this package always authenticates first,
// timing and padding oracle attacks are ineffective because ciphertexts cannot be
// forged or manipulated with more than insignificant probability of success.
// In such a case constant time operation is unimportant, but constant timing may be important if this
// code is reused elsewhere.
func pkcsUnpad(data []byte, blocklen int) (valid int, unpaddeddata []byte, err error) {

	if blocklen > math.MaxUint8 {
		err = fmt.Errorf("Unpadding error: Blocklen %d exceeds maximum one byte unsigned integer",
			blocklen, math.MaxUint8)
		return
	}

	origlen := len(data)

	if origlen < blocklen {
		err = fmt.Errorf("Unpadding error: Data length %d is less than blocklen %d",
			origlen, blocklen)
		return
	}

	if origlen%blocklen != 0 {
		err = fmt.Errorf("Unpadding error: Data length %d is not a multiple of blocklen %d",
			origlen, blocklen)
		return
	}

	padchar := data[origlen-1]
	padcharlen := int(padchar)

	datalen := origlen - padcharlen

	valid = subtle.ConstantTimeLessOrEq(padcharlen, blocklen)

	for i := 1; i <= blocklen; i++ {
		// valid = (i > padcharlen || data[origlen-i] == padchar) && valid
		iLePadcharlen := subtle.ConstantTimeLessOrEq(i, padcharlen)
		isPadChar := subtle.ConstantTimeByteEq(data[origlen-i], padchar)
		stillvalid := subtle.ConstantTimeSelect(iLePadcharlen, isPadChar, 1)
		valid &= stillvalid
	}

	unpaddeddata = data[:datalen] // This data should not be used if invalid.
	// Returning it in any case simplifies constant timing
	return
}
Beispiel #4
0
func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid int, msg []byte, err error) {
	k := (priv.N.BitLen() + 7) / 8
	if k < 11 {
		err = ErrDecryption
		return
	}

	c := new(big.Int).SetBytes(ciphertext)
	m, err := decrypt(rand, priv, c)
	if err != nil {
		return
	}

	em := leftPad(m.Bytes(), k)
	firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0)
	secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 2)

	// The remainder of the plaintext must be a string of non-zero random
	// octets, followed by a 0, followed by the message.
	//   lookingForIndex: 1 iff we are still looking for the zero.
	//   index: the offset of the first zero byte.
	var lookingForIndex, index int
	lookingForIndex = 1

	for i := 2; i < len(em); i++ {
		equals0 := subtle.ConstantTimeByteEq(em[i], 0)
		index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
		lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
	}

	// The PS padding must be at least 8 bytes long, and it starts two
	// bytes into em.
	validPS := subtle.ConstantTimeLessOrEq(2+8, index)

	valid = firstByteIsZero & secondByteIsTwo & (^lookingForIndex & 1) & validPS
	msg = em[index+1:]
	return
}