Esempio n. 1
0
File: enc.go Progetto: Liamsi/crypto
// 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
}
Esempio n. 2
0
File: enc.go Progetto: Liamsi/crypto
func header(suite abstract.Suite, X abstract.Point, x abstract.Secret,
	Xb, xb []byte, anonymitySet Set) []byte {

	//fmt.Printf("Xb %s\nxb %s\n",
	//		hex.EncodeToString(Xb),hex.EncodeToString(xb))

	// Encrypt the master secret key with each public key in the set
	S := suite.Point()
	hdr := Xb
	for i := range anonymitySet {
		Y := anonymitySet[i]
		S.Mul(Y, x) // compute DH shared secret
		seed, _ := S.MarshalBinary()
		cipher := suite.Cipher(seed)
		xc := make([]byte, len(xb))
		cipher.Partial(xc, xb, nil)
		hdr = append(hdr, xc...)
	}
	return hdr
}
Esempio n. 3
0
File: enc.go Progetto: Liamsi/crypto
// Encrypt a message for reading by any member of an explit anonymity set.
// The caller supplies one or more keys representing the anonymity set.
// If the provided set contains only one public key,
// this reduces to conventional single-receiver public-key encryption.
//
// If hide is true,
// Encrypt will produce a uniformly random-looking byte-stream,
// which reveals no metadata other than message length
// to anyone unable to decrypt the message.
// The provided abstract.Suite must support
// uniform-representation encoding of public keys for this to work.
//
func Encrypt(suite abstract.Suite, rand cipher.Stream, message []byte,
	anonymitySet Set, hide bool) []byte {

	xb, hdr := encryptKey(suite, rand, anonymitySet, hide)
	cipher := suite.Cipher(xb)

	// We now know the ciphertext layout
	hdrhi := 0 + len(hdr)
	msghi := hdrhi + len(message)
	machi := msghi + cipher.KeySize()
	ciphertext := make([]byte, machi)
	copy(ciphertext, hdr)

	// Now encrypt and MAC the message based on the master secret
	ctx := ciphertext[hdrhi:msghi]
	mac := ciphertext[msghi:machi]
	cipher.Message(ctx, message, ctx)
	cipher.Partial(mac, nil, nil)
	return ciphertext
}
Esempio n. 4
0
File: enc.go Progetto: Liamsi/crypto
// Decrypt and verify a key encrypted via encryptKey.
// On success, returns the key and the length of the decrypted header.
func decryptKey(suite abstract.Suite, ciphertext []byte, anonymitySet Set,
	mine int, privateKey abstract.Secret,
	hide bool) ([]byte, int, error) {

	// Decode the (supposed) ephemeral public key from the front
	X := suite.Point()
	var Xb []byte
	if hide {
		Xh := X.(abstract.Hiding)
		hidelen := Xh.HideLen()
		if len(ciphertext) < hidelen {
			return nil, 0, errors.New("ciphertext too short")
		}
		X.(abstract.Hiding).HideDecode(ciphertext[:hidelen])
		Xb = ciphertext[:hidelen]
	} else {
		enclen := X.MarshalSize()
		if len(ciphertext) < enclen {
			return nil, 0, errors.New("ciphertext too short")
		}
		if err := X.UnmarshalBinary(ciphertext[:enclen]); err != nil {
			return nil, 0, err
		}
		Xb = ciphertext[:enclen]
	}
	Xblen := len(Xb)

	// Decode the (supposed) master secret with our private key
	nkeys := len(anonymitySet)
	if mine < 0 || mine >= nkeys {
		panic("private-key index out of range")
	}
	seclen := suite.SecretLen()
	if len(ciphertext) < Xblen+seclen*nkeys {
		return nil, 0, errors.New("ciphertext too short")
	}
	S := suite.Point().Mul(X, privateKey)
	seed, _ := S.MarshalBinary()
	cipher := suite.Cipher(seed)
	xb := make([]byte, seclen)
	secofs := Xblen + seclen*mine
	cipher.Partial(xb, ciphertext[secofs:secofs+seclen], nil)
	x := suite.Secret()
	if err := x.UnmarshalBinary(xb); err != nil {
		return nil, 0, err
	}

	// Make sure it reproduces the correct ephemeral public key
	Xv := suite.Point().Mul(nil, x)
	if !X.Equal(Xv) {
		return nil, 0, errors.New("invalid ciphertext")
	}

	// Regenerate and check the rest of the header,
	// to ensure that that any of the anonymitySet members could decrypt it
	hdr := header(suite, X, x, Xb, xb, anonymitySet)
	hdrlen := len(hdr)
	if hdrlen != Xblen+seclen*nkeys {
		panic("wrong header size")
	}
	if subtle.ConstantTimeCompare(hdr, ciphertext[:hdrlen]) == 0 {
		return nil, 0, errors.New("invalid ciphertext")
	}

	return xb, hdrlen, nil
}