Example #1
0
// Construct a general message Cipher
// from a Stream cipher and a cryptographic Hash.
func FromStream(newStream func(key []byte) cipher.Stream,
	newHash func() hash.Hash, blockLen, keyLen, hashLen int,
	key []byte, options ...interface{}) abstract.Cipher {

	sc := streamCipher{}
	sc.newStream = newStream
	sc.newHash = newHash
	sc.blockLen = blockLen
	sc.keyLen = keyLen
	sc.hashLen = hashLen
	sc.h = sc.newHash()

	if key == nil {
		key = random.Bytes(hashLen, random.Stream)
	}
	if len(key) > 0 {
		sc.Message(nil, nil, key)
	}

	if len(options) > 0 {
		panic("no FromStream options supported yet")
	}

	return abstract.Cipher{&sc}
}
Example #2
0
func (sk *SKEME) mkmac(masterkey, Xb1, Xb2 []byte) (cipher.Stream, []byte) {
	keylen := sk.ms.KeySize()
	hmac := hmac.New(sk.suite.Hash, masterkey)
	hmac.Write(Xb1)
	hmac.Write(Xb2)
	key := hmac.Sum(nil)[:keylen]

	stream := sk.suite.Cipher(key)
	mac := random.Bytes(keylen, stream)
	return stream, mac
}
Example #3
0
func (sk *SKEME) Recv(rm []byte) (bool, error) {

	M, err := Decrypt(sk.suite, rm, sk.lpri.Set, sk.lpri.Mine, sk.lpri.Pri,
		sk.hide)
	if err != nil {
		return false, err
	}

	// Decode the remote DH public key
	ptlen := sk.suite.PointLen()
	if len(M) < ptlen {
		return false, errors.New("SKEME message too short for DH key")
	}
	if sk.rX == nil {
		rXb := M[:ptlen]
		rX := sk.suite.Point()
		if err := rX.UnmarshalBinary(M[:ptlen]); err != nil {
			return false, err
		}
		sk.rX = rX // remote DH public key
		sk.rXb = rXb

		// Compute the shared secret and the key-confirmation MACs
		DH := sk.suite.Point().Mul(rX, sk.lx)
		seed, _ := DH.MarshalBinary()
		sk.ms = sk.suite.Cipher(seed)
		mkey := random.Bytes(sk.ms.KeySize(), sk.ms)
		sk.ls, sk.lmac = sk.mkmac(mkey, sk.lXb, sk.rXb)
		sk.rs, sk.rmac = sk.mkmac(mkey, sk.rXb, sk.lXb)

		// Transmit our key-confirmation MAC with the next message
		sk.lm = append(sk.lm, sk.lmac...)
	}

	// Decode and check the remote key-confirmation MAC if present
	maclo := ptlen
	machi := maclo + sk.ms.KeySize()
	if len(M) < machi {
		return false, nil // not an error, just not done yet
	}
	if subtle.ConstantTimeCompare(M[maclo:machi], sk.rmac) == 0 {
		return false, errors.New("SKEME remote MAC check failed")
	}

	// Shared key confirmed, good to go!
	// (Although remote might still need our key confirmation.)
	return true, nil
}
Example #4
0
func TestEmbedData(T *testing.T) {
	rand := random.Stream
	bytes := random.Bytes(50, rand)

	points := Embed(bytes)
	reconstructed, err := Extract(points)
	if err != nil {
		T.Fatalf("Error occured during data extraction: %v", err)
	}

	T.Log(points)
	T.Log(bytes)
	T.Log(reconstructed)

	if !reflect.DeepEqual(bytes, reconstructed) {
		T.Fatal("Reconstructed byte slice did not equal original")
	}
}
Example #5
0
// SpongeCipher builds a general message Cipher from a Sponge function.
func FromSponge(sponge Sponge, key []byte, options ...interface{}) abstract.Cipher {
	sc := spongeCipher{}
	sc.sponge = sponge
	sc.rate = sponge.Rate()
	sc.cap = sponge.Capacity()
	sc.pad = byte(0x7f) // default, unused by standards
	sc.buf = make([]byte, sc.rate+sc.cap)
	sc.pos = 0
	sc.parseOptions(options)

	// Key the cipher in some appropriate fashion
	if key == nil {
		key = random.Bytes(sponge.Capacity(), random.Stream)
	}
	if len(key) > 0 {
		sc.Message(nil, nil, key)
	}

	// Setup normal-case domain-separation byte used for message payloads
	sc.setDomain(domainPayload, 0)

	return abstract.Cipher{&sc}
}
Example #6
0
// Start initiates the RandHound protocol run. The client pseudo-randomly
// chooses the server grouping, forms an I1 message for each group, and sends
// it to all servers of that group.
func (rh *RandHound) Start() error {

	var err error

	// Set timestamp
	rh.time = time.Now()

	// Choose client randomness
	rand := random.Bytes(rh.Suite().Hash().Size(), random.Stream)
	rh.cliRand = rand

	// Determine server grouping
	rh.server, rh.key, err = rh.Shard(rand, rh.groups)
	if err != nil {
		return err
	}

	// Set some group parameters
	for i, group := range rh.server {
		rh.threshold[i] = 2 * len(group) / 3
		rh.polyCommit[i] = make([]abstract.Point, len(group))
		g := make([]int, len(group))
		for j, server0 := range group {
			s0 := server0.RosterIndex
			rh.ServerIdxToGroupNum[s0] = i
			rh.ServerIdxToGroupIdx[s0] = j
			g[j] = s0
		}
		rh.group[i] = g
	}

	// Compute session id
	rh.sid, err = rh.sessionID(rh.nodes, rh.faulty, rh.purpose, rh.time, rh.cliRand, rh.threshold, rh.Public(), rh.key)
	if err != nil {
		return err
	}

	// Multicast first message to grouped servers
	for i, group := range rh.server {

		index := make([]uint32, len(group))
		for j, server := range group {
			index[j] = uint32(server.RosterIndex)
		}

		i1 := &I1{
			SID:       rh.sid,
			Threshold: rh.threshold[i],
			Group:     index,
			Key:       rh.key[i],
		}

		rh.mutex.Lock()

		// Sign I1 and store signature in i1.Sig
		if err := signSchnorr(rh.Suite(), rh.Private(), i1); err != nil {
			rh.mutex.Unlock()
			return err
		}

		rh.i1s[i] = i1

		rh.mutex.Unlock()

		if err := rh.Multicast(i1, group...); err != nil {
			return err
		}
	}
	return nil
}
Example #7
0
func (rh *RandHound) handleR1(r1 WR1) error {

	msg := &r1.R1

	idx := r1.RosterIndex
	grp := rh.ServerIdxToGroupNum[idx]
	pos := rh.ServerIdxToGroupIdx[idx]

	rh.mutex.Lock()
	defer rh.mutex.Unlock()

	// Verify R1 message signature
	if err := verifySchnorr(rh.Suite(), rh.key[grp][pos], msg); err != nil {
		return err
	}

	// Verify that server replied to the correct I1 message
	if err := verifyMessage(rh.Suite(), rh.i1s[grp], msg.HI1); err != nil {
		return err
	}

	// Record R1 message
	rh.r1s[idx] = msg

	// Prepare data for recovery of polynomial commits and verification of shares
	n := len(msg.EncShare)
	poly := make([][]byte, n)
	index := make([]int, n)
	encShare := make([]abstract.Point, n)
	encProof := make([]ProofCore, n)
	for i := 0; i < n; i++ {
		poly[i] = msg.CommitPoly
		index[i] = msg.EncShare[i].Pos
		encShare[i] = msg.EncShare[i].Val
		encProof[i] = msg.EncShare[i].Proof
	}

	// Init PVSS and recover polynomial commits
	H, _ := rh.Suite().Point().Pick(nil, rh.Suite().Cipher(rh.sid))
	pvss := NewPVSS(rh.Suite(), H, rh.threshold[grp])
	polyCommit, err := pvss.Commits(poly, index)
	if err != nil {
		return err
	}

	// Record polynomial commits
	rh.polyCommit[idx] = polyCommit

	// Return, if we already committed to secrets previously
	if len(rh.chosenSecret) > 0 {
		return nil
	}

	// Verify encrypted shares
	good, _, err := pvss.Verify(H, rh.key[grp], polyCommit, encShare, encProof)
	if err != nil {
		return err
	}

	// Record valid encrypted shares per secret/server
	for _, g := range good {
		if _, ok := rh.secret[idx]; !ok {
			rh.secret[idx] = make([]int, 0)
		}
		rh.secret[idx] = append(rh.secret[idx], msg.EncShare[g].Target)
	}

	// Check if there is at least a threshold number of reconstructable secrets
	// in each group. If yes proceed to the next phase. Note the double-usage
	// of the threshold which is used to determine if enough valid shares for a
	// single secret are available and if enough secrets for a given group are
	// available
	goodSecret := make(map[int][]int)
	for i, group := range rh.server {
		var secret []int
		for _, server := range group {
			j := server.RosterIndex
			if share, ok := rh.secret[j]; ok && rh.threshold[i] <= len(share) {
				secret = append(secret, j)
			}
		}
		if rh.threshold[i] <= len(secret) {
			goodSecret[i] = secret
		}
	}

	// Proceed, if there are enough good secrets
	if len(goodSecret) == rh.groups {

		// Reset secret for the next phase (see handleR2)
		rh.secret = make(map[int][]int)

		// Choose secrets that contribute to collective randomness
		for i := range rh.server {

			// Randomly remove some secrets so that a threshold of secrets remains
			rand := random.Bytes(rh.Suite().Hash().Size(), random.Stream)
			prng := rh.Suite().Cipher(rand)
			secret := goodSecret[i]
			for j := 0; j < len(secret)-rh.threshold[i]; j++ {
				k := int(random.Uint32(prng) % uint32(len(secret)))
				secret = append(secret[:k], secret[k+1:]...)
			}
			rh.chosenSecret[i] = secret
		}

		log.Lvlf3("Grouping: %v", rh.group)
		log.Lvlf3("ChosenSecret: %v", rh.chosenSecret)

		// Transformation of commitments from int to uint32 to avoid protobuff errors
		var chosenSecret = make([][]uint32, len(rh.chosenSecret))
		for i := range rh.chosenSecret {
			var l []uint32
			for j := range rh.chosenSecret[i] {
				l = append(l, uint32(rh.chosenSecret[i][j]))
			}
			chosenSecret[i] = l
		}

		// Prepare a message for each server of a group and send it
		for i, group := range rh.server {
			for j, server := range group {

				// Among the good secrets chosen previously collect all valid
				// shares, proofs, and polynomial commits intended for the
				// target server
				var encShare []Share
				var polyCommit []abstract.Point
				for _, k := range rh.chosenSecret[i] {
					r1 := rh.r1s[k]
					pc := rh.polyCommit[k]
					encShare = append(encShare, r1.EncShare[j])
					polyCommit = append(polyCommit, pc[j])
				}

				i2 := &I2{
					Sig:          crypto.SchnorrSig{},
					SID:          rh.sid,
					ChosenSecret: chosenSecret,
					EncShare:     encShare,
					PolyCommit:   polyCommit,
				}

				if err := signSchnorr(rh.Suite(), rh.Private(), i2); err != nil {
					return err
				}

				rh.i2s[server.RosterIndex] = i2

				if err := rh.SendTo(server, i2); err != nil {
					return err
				}
			}
		}
	}

	return nil
}
Example #8
0
func TestSession(T *testing.T) {
	numUsers := 5
	numNotaries := 2
	slot := 0

	data, users, notaries := createSetup(numUsers, numNotaries)
	userciphers := make([]*UserCipherText, numUsers)
	notaryciphers := make([]*NotaryCipherText, numNotaries)

	// Create some plaintext bytes and embed them into group elements
	bytes := random.Bytes(100, random.Stream)
	plaintext := crypto.Embed(bytes)
	amount := len(plaintext)

	// Let the users construct their ciphertexts
	var err error
	for i := range users {
		if i == slot {
			userciphers[i], err = users[i].GetRealCipherText(data, plaintext)
		} else {
			userciphers[i], err = users[i].GetCoverCipherText(data, amount, slot)
		}
	}
	if err != nil {
		T.Fatalf("Failed to create proof: %v", err)
	}

	// Check the validity of the user ciphertexts
	for i, usercipher := range userciphers {
		if err := usercipher.Verify(data); err != nil {
			T.Logf("Ciphertext of user %d was invalid: %v", i, err)
			T.Fail()
		}
	}

	// Let the notaries construct their ciphertexts
	for j := range notaries {
		notaryciphers[j], err = notaries[j].GetCiphertext(data, amount)
	}
	if err != nil {
		T.Fatalf("Failed to create proof: %v", err)
	}

	// Check the validity of the notary ciphertexts
	for j, notarycipher := range notaryciphers {
		if err := notarycipher.Verify(data); err != nil {
			T.Logf("Ciphertext of notary %d was invalid: %v", j, err)
			T.Fail()
		}
	}

	// Reconstruct plaintext
	messages, err := ReconstructMessage(userciphers, notaryciphers)
	if err != nil {
		T.Logf("Failed to reconstruct plaintext: %v", err)
		T.Fail()
	}
	if len(messages) != len(plaintext) {
		T.Fatal("Got wrong amount of points, was %d, should be %d", len(messages), len(plaintext))
	}

	// Check if the reconstructed plaintext equals the original ones
	reconstructed, _ := crypto.Extract(messages)
	if !reflect.DeepEqual(bytes, reconstructed) {
		T.Fatal("Extracted plaintext does not equal the original")
	}
}