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 = DecryptionError{} 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) } valid = firstByteIsZero & secondByteIsTwo & (^lookingForIndex & 1) msg = em[index+1:] return }
// Decrypt takes two integers, resulting from an ElGamal encryption, and // returns the plaintext of the message. An error can result only if the // ciphertext is invalid. Users should keep in mind that this is a padding // oracle and thus, if exposed to an adaptive chosen ciphertext attack, can // be used to break the cryptosystem. See ``Chosen Ciphertext Attacks // Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel // Bleichenbacher, Advances in Cryptology (Crypto '98), func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) { s := new(big.Int).Exp(c1, priv.X, priv.P) s.ModInverse(s, priv.P) s.Mul(s, c2) s.Mod(s, priv.P) em := s.Bytes() firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 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 := 1; i < len(em); i++ { equals0 := subtle.ConstantTimeByteEq(em[i], 0) index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index) lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex) } if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 { return nil, errors.New("elgamal: decryption error") } return em[index+1:], nil }
func main() { log.Printf("%d", subtle.ConstantTimeByteEq(43, 65)) log.Printf("%d", subtle.ConstantTimeCompare([]byte("batman"), []byte("robin "))) bytes := make([]byte, 6) subtle.ConstantTimeCopy(1, bytes, []byte("batman")) log.Printf("%s", bytes) log.Printf("%d", subtle.ConstantTimeEq(256, 255)) log.Printf("%d", subtle.ConstantTimeSelect(1, 2, 3)) log.Printf("%d", subtle.ConstantTimeSelect(0, 2, 3)) }
// 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") } }
// 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 }
// New returns a hash.Hash computing the CMac checksum. // If the block cipher is not supported by CMac // (see package doc), a non-nil error is returned. func New(c cipher.Block) (hash.Hash, error) { if c == nil { return nil, errors.New("the cipher.Block must not be nil") } bs := c.BlockSize() var p int switch bs { default: return nil, errors.New("cipher block size not supported") case 8: p = p64 case 16: p = p128 case 32: p = p256 case 64: p = p512 case 128: p = p1024 } m := &macFunc{ cipher: c, k0: make([]byte, bs), k1: make([]byte, bs), buf: make([]byte, bs), } c.Encrypt(m.k0, m.k0) v := shift(m.k0, m.k0) m.k0[bs-1] ^= byte(subtle.ConstantTimeSelect(v, p, 0)) v = shift(m.k1, m.k0) m.k1[bs-1] ^= byte(subtle.ConstantTimeSelect(v, p, 0)) return m, nil }
// decryptPKCS1v15 decrypts ciphertext using priv and blinds the operation if // rand is not nil. It returns one or zero in valid that indicates whether the // plaintext was correctly structured. In either case, the plaintext is // returned in em so that it may be read independently of whether it was valid // in order to maintain constant memory access patterns. If the plaintext was // valid then index contains the index of the original message in em. func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid int, em []byte, index int, 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. 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 index = subtle.ConstantTimeSelect(valid, index+1, 0) return valid, em, index, nil }
// 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 }
// DecryptOAEP decrypts ciphertext using RSA-OAEP. // If random != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks. func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err error) { if err := checkPub(&priv.PublicKey); err != nil { return nil, err } k := (priv.N.BitLen() + 7) / 8 if len(ciphertext) > k || k < hash.Size()*2+2 { err = ErrDecryption return } c := new(big.Int).SetBytes(ciphertext) m, err := decrypt(random, priv, c) if err != nil { return } hash.Write(label) lHash := hash.Sum(nil) hash.Reset() // Converting the plaintext number to bytes will strip any // leading zeros so we may have to left pad. We do this unconditionally // to avoid leaking timing information. (Although we still probably // leak the number of leading zeros. It's not clear that we can do // anything about this.) em := leftPad(m.Bytes(), k) firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) seed := em[1 : hash.Size()+1] db := em[hash.Size()+1:] mgf1XOR(seed, hash, db) mgf1XOR(db, hash, 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 { err = ErrDecryption return } msg = rest[index+1:] return }
// decrypt checks and strips the mac and decrypts the data in b. Returns a // success boolean, the number of bytes to skip from the start of the record in // order to get the application payload, and an optional alert value. func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert) { // pull out payload payload := b.data[recordHeaderLen:] macSize := 0 if hc.mac != nil { macSize = hc.mac.Size() } paddingGood := byte(255) paddingLen := 0 explicitIVLen := 0 // decrypt if hc.cipher != nil { switch c := hc.cipher.(type) { case cipher.Stream: c.XORKeyStream(payload, payload) case cipher.AEAD: explicitIVLen = 8 if len(payload) < explicitIVLen { return false, 0, alertBadRecordMAC } nonce := payload[:8] payload = payload[8:] copy(hc.additionalData[:], hc.seq[:]) copy(hc.additionalData[8:], b.data[:3]) n := len(payload) - c.Overhead() hc.additionalData[11] = byte(n >> 8) hc.additionalData[12] = byte(n) var err error payload, err = c.Open(payload[:0], nonce, payload, hc.additionalData[:]) if err != nil { return false, 0, alertBadRecordMAC } b.resize(recordHeaderLen + explicitIVLen + len(payload)) case cbcMode: blockSize := c.BlockSize() if hc.version >= VersionTLS11 { explicitIVLen = blockSize } if len(payload)%blockSize != 0 || len(payload) < roundUp(explicitIVLen+macSize+1, blockSize) { return false, 0, alertBadRecordMAC } if explicitIVLen > 0 { c.SetIV(payload[:explicitIVLen]) payload = payload[explicitIVLen:] } c.CryptBlocks(payload, payload) if hc.version == VersionSSL30 { paddingLen, paddingGood = extractPaddingSSL30(payload) } else { paddingLen, paddingGood = extractPadding(payload) // To protect against CBC padding oracles like Lucky13, the data // past paddingLen (which is secret) is passed to the MAC // function as extra data, to be fed into the HMAC after // computing the digest. This makes the MAC constant time as // long as the digest computation is constant time and does not // affect the subsequent write. } default: panic("unknown cipher type") } } // check, strip mac if hc.mac != nil { if len(payload) < macSize { return false, 0, alertBadRecordMAC } // strip mac off payload, b.data n := len(payload) - macSize - paddingLen n = subtle.ConstantTimeSelect(int(uint32(n)>>31), 0, n) // if n < 0 { n = 0 } b.data[3] = byte(n >> 8) b.data[4] = byte(n) remoteMAC := payload[n : n+macSize] localMAC := hc.mac.MAC(hc.inDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], payload[:n], payload[n+macSize:]) if subtle.ConstantTimeCompare(localMAC, remoteMAC) != 1 || paddingGood != 255 { return false, 0, alertBadRecordMAC } hc.inDigestBuf = localMAC b.resize(recordHeaderLen + explicitIVLen + n) } hc.incSeq() return true, recordHeaderLen + explicitIVLen, 0 }