Skip to content
Snippets Groups Projects
Commit 5d9b0dbc authored by Jono Wenger's avatar Jono Wenger
Browse files

Merge branch 'jono/singleUseTransmitKey' into 'release'

Add single-use transmission key generation

See merge request elixxir/crypto!249
parents cc4926b3 9f5efa4b
No related branches found
No related tags found
No related merge requests found
......@@ -9,32 +9,21 @@ package singleUse
import (
"bytes"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/hash"
)
const macConstant = "macConstant"
// MakeMAC generates the MAC for the given base key and encrypted payload.
func MakeMAC(baseKey *cyclic.Int, encryptedPayload []byte) []byte {
h, err := hash.NewCMixHash()
if err != nil {
jww.ERROR.Panicf("Failed to create hash: %v", err)
// MakeMAC generates the MAC used in the cmix message holding the single-use
// payload.
func MakeMAC(dhKey *cyclic.Int, encryptedPayload []byte) []byte {
return makeHash(dhKey, encryptedPayload, []byte(macConstant))
}
// Hash the key, number, and constant
h.Write(baseKey.Bytes())
h.Write(encryptedPayload)
h.Write([]byte(macConstant))
return h.Sum(nil)
}
// VerifyMAC determines if the provided MAC is valid for the given base key and
// VerifyMAC determines if the provided MAC is valid for the given key and
// encrypted payload.
func VerifyMAC(baseKey *cyclic.Int, encryptedPayload, receivedMAC []byte) bool {
newMAC := MakeMAC(baseKey, encryptedPayload)
func VerifyMAC(dhKey *cyclic.Int, encryptedPayload, receivedMAC []byte) bool {
newMAC := MakeMAC(dhKey, encryptedPayload)
return bytes.Equal(newMAC, receivedMAC)
}
......@@ -35,17 +35,17 @@ func TestMAC_Consistency(t *testing.T) {
for i, expected := range expectedMACs {
privKey := diffieHellman.GeneratePrivateKey(diffieHellman.DefaultPrivateKeyLength, grp, prng)
pubkey := diffieHellman.GeneratePublicKey(privKey, grp)
baseKey := diffieHellman.GenerateSessionKey(privKey, pubkey, grp)
dhKey := diffieHellman.GenerateSessionKey(privKey, pubkey, grp)
encryptedPayload := make([]byte, 128)
prng.Read(encryptedPayload)
testMAC := MakeMAC(baseKey, encryptedPayload)
testMAC := MakeMAC(dhKey, encryptedPayload)
testMACBase64 := base64.StdEncoding.EncodeToString(testMAC)
if expected != testMACBase64 {
t.Errorf("MakeMAC() did not return the expected MAC for the given "+
"base key and encrypted payload at index %d."+
"\nbase key: %s\nexpected: %s\nreceived: %s",
i, baseKey.Text(10), expected, testMACBase64)
i, dhKey.Text(10), expected, testMACBase64)
}
}
}
......@@ -62,18 +62,18 @@ func TestMAC_Unique(t *testing.T) {
for i := 0; i < 100; i++ {
privKey := diffieHellman.GeneratePrivateKey(diffieHellman.DefaultPrivateKeyLength, grp, prng)
pubkey := diffieHellman.GeneratePublicKey(privKey, grp)
baseKey := diffieHellman.GenerateSessionKey(privKey, pubkey, grp)
dhKey := diffieHellman.GenerateSessionKey(privKey, pubkey, grp)
encryptedPayload := make([]byte, 128)
prng.Read(encryptedPayload)
testMAC := MakeMAC(baseKey, encryptedPayload)
testMAC := MakeMAC(dhKey, encryptedPayload)
testMACBase64 := base64.StdEncoding.EncodeToString(testMAC)
if _, exists := MACs[testMACBase64]; exists {
t.Errorf("Generated MAC collides with previously generated MAC."+
"\ncurrent MAC: baseKey: %s encryptedPayload: %s"+
"\npreviouse MAC: baseKey: %s encryptedPayload: %s"+
"\ncurrent MAC: dhKey: %s encryptedPayload: %s"+
"\npreviouse MAC: dhKey: %s encryptedPayload: %s"+
"\nMAC: %s",
baseKey.Text(10),
dhKey.Text(10),
base64.StdEncoding.EncodeToString(encryptedPayload),
MACs[testMACBase64].key.Text(10),
base64.StdEncoding.EncodeToString(MACs[testMACBase64].encryptedPayload),
......@@ -82,7 +82,7 @@ func TestMAC_Unique(t *testing.T) {
MACs[testMACBase64] = struct {
key *cyclic.Int
encryptedPayload []byte
}{baseKey, encryptedPayload}
}{dhKey, encryptedPayload}
}
}
}
......@@ -106,18 +106,18 @@ func TestVerifyMAC(t *testing.T) {
for i, expected := range expectedMACs {
privKey := diffieHellman.GeneratePrivateKey(diffieHellman.DefaultPrivateKeyLength, grp, prng)
pubkey := diffieHellman.GeneratePublicKey(privKey, grp)
baseKey := diffieHellman.GenerateSessionKey(privKey, pubkey, grp)
dhKey := diffieHellman.GenerateSessionKey(privKey, pubkey, grp)
encryptedPayload := make([]byte, 128)
prng.Read(encryptedPayload)
testMAC := MakeMAC(baseKey, encryptedPayload)
testMAC := MakeMAC(dhKey, encryptedPayload)
testMACBase64 := base64.StdEncoding.EncodeToString(testMAC)
receivedMac, _ := base64.StdEncoding.DecodeString(expected)
if !VerifyMAC(baseKey, encryptedPayload, receivedMac) {
if !VerifyMAC(dhKey, encryptedPayload, receivedMac) {
t.Errorf("VerifyMAC() failed for a correct MAC (%d)."+
"\nbase key: %s\nexpected: %s\nreceived: %s",
i, baseKey.Text(10), expected, testMACBase64)
i, dhKey.Text(10), expected, testMACBase64)
}
}
}
......@@ -17,28 +17,39 @@ import (
const responseFPConstant = "responseFPConstant"
func ResponseFingerprint(pubKey *cyclic.Int, keyNum uint64) format.Fingerprint {
// ResponseFingerprint generates the fingerprint for the response message for
// the given key number.
func ResponseFingerprint(dhKey *cyclic.Int, keyNum uint64) format.Fingerprint {
// Create fingerprint
fp := format.Fingerprint{}
copy(fp[:], makeHash(pubKey, keyNum, responseFPConstant))
copy(fp[:], makeKeyHash(dhKey, keyNum, responseFPConstant))
return fp
}
func makeHash(pubKey *cyclic.Int, keyNum uint64, constant string) []byte {
// makeHash generates a hash from the given key and list of bytes.
func makeHash(key *cyclic.Int, data ...[]byte) []byte {
// Create new hash
h, err := hash.NewCMixHash()
if err != nil {
jww.ERROR.Panicf("Failed to create hash: %v", err)
jww.ERROR.Panicf("Failed to create new hash for single-use "+
"communication: %v", err)
}
// Convert the key number to bytes
buff := make([]byte, binary.MaxVarintLen64)
binary.BigEndian.PutUint64(buff, keyNum)
// Hash the key, number, and constant
h.Write(pubKey.Bytes())
h.Write(buff)
h.Write([]byte(constant))
// Hash the key and data
h.Write(key.Bytes())
for _, d := range data {
h.Write(d)
}
return h.Sum(nil)
}
// makeKeyHash generates a hash from a key, an integer, and a string.
func makeKeyHash(dhKey *cyclic.Int, keyNum uint64, constant string) []byte {
// Convert the key number to bytes
keyNumBytes := make([]byte, binary.MaxVarintLen64)
binary.BigEndian.PutUint64(keyNumBytes, keyNum)
return makeHash(dhKey, keyNumBytes, []byte(constant))
}
......@@ -21,16 +21,16 @@ func TestResponseFingerprint(t *testing.T) {
grp := getGrp()
prng := rand.New(rand.NewSource(42))
pubKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
dhKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
diffieHellman.DefaultPrivateKeyLength, grp, prng), grp)
testFP := ResponseFingerprint(pubKey, 0)
testFP := ResponseFingerprint(dhKey, 0)
testFPBase64 := base64.StdEncoding.EncodeToString(testFP[:])
if expectedFP != testFPBase64 {
t.Errorf("ResponseFingerprint() did not return the expected "+
"fingerprint for public key %s."+
"\nexpected: %s\nreceived: %s",
pubKey.Text(10), expectedFP, testFPBase64)
dhKey.Text(10), expectedFP, testFPBase64)
}
}
......@@ -52,15 +52,15 @@ func Test_makeHash_Consistency(t *testing.T) {
prng := rand.New(rand.NewSource(42))
for i, expectedHash := range expectedHashes {
pubKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
dhKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
diffieHellman.DefaultPrivateKeyLength, grp, prng), grp)
testHash := makeHash(pubKey, uint64(i), "constant")
testHash := makeKeyHash(dhKey, uint64(i), "constant")
testHashBase64 := base64.StdEncoding.EncodeToString(testHash)
if expectedHash != testHashBase64 {
t.Errorf("makeHash() did not return the expected hash for public "+
"key %s at index %d.\nexpected: %s\nreceived: %s",
pubKey.Text(10), i, expectedHash, testHashBase64)
dhKey.Text(10), i, expectedHash, testHashBase64)
}
}
}
......@@ -72,18 +72,18 @@ func Test_makeHash_Unique(t *testing.T) {
hashes := make(map[string]*cyclic.Int, 100)
for i := 0; i < 100; i++ {
pubKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
dhKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
diffieHellman.DefaultPrivateKeyLength, grp, prng), grp)
testHash := makeHash(pubKey, uint64(i), "constant")
testHash := makeKeyHash(dhKey, uint64(i), "constant")
hashBase64 := base64.StdEncoding.EncodeToString(testHash)
if hashes[hashBase64] != nil {
t.Errorf("Generated hash from key %s collides with "+
"previously generated hash from key %s.\nfingerprint: %s",
pubKey.Text(10), hashes[hashBase64].Text(10), hashBase64)
dhKey.Text(10), hashes[hashBase64].Text(10), hashBase64)
} else {
hashes[hashBase64] = pubKey
hashes[hashBase64] = dhKey
}
}
}
......@@ -13,6 +13,8 @@ import (
const responseKeyConstant = "responseKeyConstant"
func ResponseKey(pubKey *cyclic.Int, keyNum uint64) []byte {
return makeHash(pubKey, keyNum, responseKeyConstant)
// ResponseKey generates the key for the response message that corresponds with
// the given key number.
func ResponseKey(dhKey *cyclic.Int, keyNum uint64) []byte {
return makeKeyHash(dhKey, keyNum, responseKeyConstant)
}
......@@ -20,14 +20,14 @@ func TestResponseKey(t *testing.T) {
grp := getGrp()
prng := rand.New(rand.NewSource(42))
pubKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
dhKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
diffieHellman.DefaultPrivateKeyLength, grp, prng), grp)
testKey := ResponseKey(pubKey, 0)
testKey := ResponseKey(dhKey, 0)
testKeyBase64 := base64.StdEncoding.EncodeToString(testKey)
if expectedKey != testKeyBase64 {
t.Errorf("ResponseKey() did not return the expected key for public "+
"key %s.\nexpected: %s\nreceived: %s",
pubKey.Text(10), expectedKey, testKeyBase64)
dhKey.Text(10), expectedKey, testKeyBase64)
}
}
......@@ -8,29 +8,18 @@
package singleUse
import (
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/hash"
"gitlab.com/elixxir/primitives/format"
)
const transmitFPConstant = "transmitFPConstant"
func TransmitFingerprint(pubKey *cyclic.Int) format.Fingerprint {
// Create new hash
h, err := hash.NewCMixHash()
if err != nil {
jww.ERROR.Panicf("Failed to create hash: %v", err)
}
// Hash the key and constant
h.Write(pubKey.Bytes())
h.Write([]byte(transmitFPConstant))
keyHash := h.Sum(nil)
// TransmitFingerprint generates the fingerprint used for the transmission
// message.
func TransmitFingerprint(dhKey *cyclic.Int) format.Fingerprint {
// Create fingerprint
fp := format.Fingerprint{}
copy(fp[:], keyHash)
copy(fp[:], makeHash(dhKey, []byte(transmitFPConstant)))
return fp
}
......@@ -35,16 +35,16 @@ func TestTransmitFingerprint_Consistency(t *testing.T) {
prng := rand.New(rand.NewSource(42))
for i, expected := range expectedFPs {
pubKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
dhKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
diffieHellman.DefaultPrivateKeyLength, grp, prng), grp)
testFP := TransmitFingerprint(pubKey)
testFP := TransmitFingerprint(dhKey)
testFPBase64 := base64.StdEncoding.EncodeToString(testFP[:])
if expected != testFPBase64 {
t.Errorf("TransmitFingerprint() did not return the expected "+
"fingerprint for public key %s at index %d."+
"\nexpected: %s\nreceived: %s",
pubKey.Text(10), i, expected, testFPBase64)
dhKey.Text(10), i, expected, testFPBase64)
}
}
}
......@@ -56,17 +56,17 @@ func TestTransmitFingerprint_Unique(t *testing.T) {
FPs := make(map[format.Fingerprint]*cyclic.Int, 100)
for i := 0; i < 100; i++ {
pubKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
dhKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
diffieHellman.DefaultPrivateKeyLength, grp, prng), grp)
testFP := TransmitFingerprint(pubKey)
testFP := TransmitFingerprint(dhKey)
if FPs[testFP] != nil {
t.Errorf("Generated fingerprint from key %s collides with "+
"previously generated fingerprint from key %s."+
"\nfingerprint: %s", pubKey.Text(10), FPs[testFP].Text(10),
"\nfingerprint: %s", dhKey.Text(10), FPs[testFP].Text(10),
base64.StdEncoding.EncodeToString(testFP[:]))
} else {
FPs[testFP] = pubKey
FPs[testFP] = dhKey
}
}
}
......
///////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
///////////////////////////////////////////////////////////////////////////////
package singleUse
import (
"gitlab.com/elixxir/crypto/cyclic"
)
const transmitKeyConstant = "transmitKeyConstant"
// TransmitFingerprint generates the key used for the transmission message.
func TransmitKey(dhKey *cyclic.Int) []byte {
return makeHash(dhKey, []byte(transmitKeyConstant))
}
///////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
///////////////////////////////////////////////////////////////////////////////
package singleUse
import (
"encoding/base64"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/diffieHellman"
"math/rand"
"testing"
)
// Tests that the generated keys do not change.
func TestTransmitKey_Consistency(t *testing.T) {
expectedKeys := []string{
"r8w70j5FjEcdt8xlpJl4eQxIem+UMrpXt5K/JYhXj2g=",
"0FVEW60pQRTgfZXhn+wRa+PqPSAM9vMCH1YjRYUoi9s=",
"aIhJ7Oy0/1uIz3PPme4KOVrPf4VIpQ7iUj3DZ0iTDEg=",
"iZZphXY4wO55I8Y3T83vdfvzowjT8Kfvm66QtvZ9lmE=",
"zMmiCDe7d8mFDJvXrBmv81UXWB2fPZMzcPScUaLuvos=",
"HvdofUNn/dRIPnXyre0naqnrWNEO8Fa5XiXFzHgR2SY=",
"D72jZPNZ7NwS+y00yaT2jwX8e+8WXJFsIMp7DX1eIG0=",
"pfhnc3jF/c52OG9BQIbRCaUluyAPgz1+M/TUVigbi44=",
"F4Xlmu/ceaAOcXjM9gqhr4uG4q0l6u+tHG34xjaeNFM=",
"njlwVRA/zIER7c4znROHKaswUNktB4z7L9MLa3bcjnY=",
}
grp := getGrp()
prng := rand.New(rand.NewSource(42))
for i, expected := range expectedKeys {
dhKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
diffieHellman.DefaultPrivateKeyLength, grp, prng), grp)
testKey := base64.StdEncoding.EncodeToString(TransmitKey(dhKey))
if expected != testKey {
t.Errorf("TransmitKey() did not return the expected key "+
"for public key %s at index %d.\nexpected: %s\nreceived: %s",
dhKey.Text(10), i, expected, testKey)
}
}
}
// Tests that all generated keys are unique.
func TestTransmitKey_Unique(t *testing.T) {
grp := getGrp()
prng := rand.New(rand.NewSource(42))
keys := make(map[string]*cyclic.Int, 100)
for i := 0; i < 100; i++ {
dhKey := diffieHellman.GeneratePublicKey(diffieHellman.GeneratePrivateKey(
diffieHellman.DefaultPrivateKeyLength, grp, prng), grp)
testKey := base64.StdEncoding.EncodeToString(TransmitKey(dhKey))
if keys[testKey] != nil {
t.Errorf("Generated fingerprint from key %s collides with "+
"previously generated fingerprint from key %s.\nfingerprint: %s",
dhKey.Text(10), keys[testKey].Text(10), testKey)
} else {
keys[testKey] = dhKey
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment