Пример #1
0
// Decrypt a message encrypted for a particular anonymity set.
// Returns the cleartext message on success, or an error on failure.
//
// The caller provides the anonymity set for which the message is intended,
// and the private key corresponding to one of the public keys in the set.
// Decrypt verifies that the message is encrypted correctly for this set -
// in particular, that it could be decrypted by ALL of the listed members -
// before returning successfully with the decrypted message.
// This verification ensures that a malicious sender
// cannot de-anonymize a receiver by constructing a ciphertext incorrectly
// so as to be decryptable by only some members of the set.
// As a side-effect, this verification also ensures plaintext-awareness:
// that is, it is infeasible for a sender to construct any ciphertext
// that will be accepted by the receiver without knowing the plaintext.
//
func Decrypt(suite abstract.Suite, ciphertext []byte, anonymitySet Set,
	mine int, privateKey abstract.Secret, hide bool) ([]byte, error) {

	// Decrypt and check the encrypted key-header.
	xb, hdrlen, err := decryptKey(suite, ciphertext, anonymitySet,
		mine, privateKey, hide)
	if err != nil {
		return nil, err
	}

	// Determine the message layout
	cipher := suite.Cipher(xb)
	maclen := cipher.KeySize()
	if len(ciphertext) < hdrlen+maclen {
		return nil, errors.New("ciphertext too short")
	}
	hdrhi := hdrlen
	msghi := len(ciphertext) - maclen

	// Decrypt the message and check the MAC
	ctx := ciphertext[hdrhi:msghi]
	mac := ciphertext[msghi:]
	msg := make([]byte, len(ctx))
	cipher.Message(msg, ctx, ctx)
	cipher.Partial(mac, mac, nil)
	if subtle.ConstantTimeAllEq(mac, 0) == 0 {
		return nil, errors.New("invalid ciphertext: failed MAC check")
	}
	return msg, nil
}
Пример #2
0
// Open decrypts and authenticates a message encrypted using Seal.
// It decrypts sealed message src and appends it onto plaintext buffer dst,
// growing the dst buffer if it is too small (or nil),
// and returns the resulting destination buffer or an error.
//
func (c Cipher) Open(dst, src []byte) ([]byte, error) {
	m := c.KeySize()
	l := len(src) - m
	if l < 0 {
		return nil, errors.New("sealed ciphertext too short")
	}
	ctx := src[:l]
	mac := src[l:]
	dst, msg := util.Grow(dst, l)

	if &msg[0] != &ctx[0] { // Decrypt and absorb ciphertext
		c.Message(msg, ctx, ctx)
	} else {
		tmp := make([]byte, l)
		c.Message(tmp, ctx, ctx)
		copy(msg, tmp)
	}

	c.Message(mac, mac, nil) // Compute MAC and XOR with received
	if subtle.ConstantTimeAllEq(mac, 0) == 0 {
		return nil, errors.New("ciphertext authentication failed")
	}

	return dst, nil
}
Пример #3
0
func (ca *cipherAEAD) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {

	// Fork off a temporary Cipher state indexed via the nonce
	ct := ca.Clone()
	ct.Message(nil, nil, nonce)

	// Compute the plaintext's length
	authl := ct.KeySize()
	plainl := len(ciphertext) - authl
	if plainl < 0 {
		return nil, errors.New("AEAD ciphertext too short")
	}
	auth := ciphertext[plainl:]
	ciphertext = ciphertext[:plainl]

	// Decrypt the plaintext and update the temporary Cipher state
	dst, plaintext := util.Grow(dst, plainl)
	ct.Message(plaintext, ciphertext, ciphertext)

	// Compute and check the authenticator based on post-encryption state
	ct.Message(auth, auth, nil)
	if subtle.ConstantTimeAllEq(auth, 0) == 0 {
		return nil, errors.New("AEAD authenticator check failed")
	}

	return dst, nil
}
Пример #4
0
// Tests a Cipher:
// 1) Encryption / decryption work
// 2) Encryption / decryption with different key don't work
// 3) Changing a bit in the ciphertext or mac results in failed mac check
// 4) Different keys produce sufficiently random output
func TestAuthenticateAndEncrypt(t *testing.T,
	newCipher func([]byte, ...interface{}) abstract.Cipher,
	n int, bitdiff float64, text []byte) {
	cryptsize := len(text)
	decrypted := make([]byte, len(text))

	bc := newCipher(nil)
	keysize := bc.KeySize()
	hashsize := bc.HashSize()
	mac := make([]byte, hashsize)

	ncrypts := make([][]byte, n)
	nkeys := make([][]byte, n)
	nmacs := make([][]byte, n)

	// Encrypt / decrypt / mac test
	for i := range nkeys {
		nkeys[i] = make([]byte, keysize)
		rand.Read(nkeys[i])
		bc = newCipher(nkeys[i])
		ncrypts[i] = make([]byte, cryptsize)
		bc.Message(ncrypts[i], text, ncrypts[i])
		nmacs[i] = make([]byte, hashsize)
		bc.Message(nmacs[i], nil, nil)

		bc = newCipher(nkeys[i])
		bc.Message(decrypted, ncrypts[i], ncrypts[i])
		if !bytes.Equal(text, decrypted) {
			t.Log("Encryption / Decryption failed", i)
			t.FailNow()
		}

		bc.Message(mac, nmacs[i], nil)
		if subtle.ConstantTimeAllEq(mac, 0) != 1 {
			t.Log("MAC Check failed")
			t.FailNow()
		}
	}

	// Different keys test
	for i := range ncrypts {
		for j := range ncrypts {
			if i == j {
				continue
			}
			bc = newCipher(nkeys[i])
			bc.Message(decrypted, ncrypts[j], ncrypts[j])
			bc.Message(mac, nmacs[j], nil)
			if subtle.ConstantTimeAllEq(mac, 0) == 1 {
				t.Log("MAC Check passed")
				t.FailNow()
			}
		}
	}

	// Not enough randomness in 1 byte to pass this consistently
	if len(ncrypts[0]) < 8 {
		return
	}

	// Bit difference test
	for i := range ncrypts {
		for j := i + 1; j < len(ncrypts); j++ {
			res := BitDiff(ncrypts[i], ncrypts[j])
			if res < bitdiff {
				t.Log("Encryptions not sufficiently different", res)
				t.FailNow()
			}
		}
	}

	deltacopy := make([]byte, cryptsize)

	// Bits in either testmsg or testmac should be flipped
	// then the resulting MAC check should fail
	deltatest := func(index int, testmsg []byte, testmac []byte) {
		bc = newCipher(nkeys[index])
		bc.Message(decrypted, testmsg, testmsg)
		bc.Message(mac, testmac, nil)
		if subtle.ConstantTimeAllEq(mac, 0) == 1 {
			t.Log("MAC Check passed")
			t.FailNow()
		}
	}

	for i := range ncrypts {
		copy(ncrypts[i], deltacopy)

		deltacopy[0] ^= 255
		deltatest(i, deltacopy, nmacs[i])
		deltacopy[0] = ncrypts[i][0]

		deltacopy[len(deltacopy)/2-1] ^= 255
		deltatest(i, deltacopy, nmacs[i])
		deltacopy[len(deltacopy)/2-1] = ncrypts[i][len(deltacopy)/2-1]

		deltacopy[len(deltacopy)-1] ^= 255
		deltatest(i, deltacopy, nmacs[i])
		deltacopy[len(deltacopy)-1] = ncrypts[i][len(deltacopy)-1]

		deltamac := make([]byte, hashsize)
		copy(nmacs[i], deltamac)
		deltamac[0] ^= 255
		deltatest(i, ncrypts[i], deltamac)
	}
}