diff --git a/e2e/singleUse/mac.go b/e2e/singleUse/mac.go index 9b61361e3c235dad90cd675a4086fd3e82cdcc1e..361137c3582448a07e936ece084e5abdf9adf5fd 100644 --- a/e2e/singleUse/mac.go +++ b/e2e/singleUse/mac.go @@ -15,7 +15,7 @@ import ( const macSalt = "singleUseMacSalt" -// MakeMAC generates the MAC used in both the transmission and response cMix +// MakeMAC generates the MAC used in both the request and response cMix // messages. func MakeMAC(key []byte, encryptedPayload []byte) []byte { h := hmac.New(hash.DefaultHash, key) diff --git a/e2e/singleUse/recipientID.go b/e2e/singleUse/recipientID.go index d679829df517f2761f740ae02e440465f882b803..232ff4339b5dfc13bd559a4251f1d575c2859b55 100644 --- a/e2e/singleUse/recipientID.go +++ b/e2e/singleUse/recipientID.go @@ -15,7 +15,7 @@ import ( ) // NewRecipientID generates the recipient ID for a single-use sender. The ID is -// generated from the hash of the unencrypted transmission payload. The +// generated from the hash of the unencrypted request payload. The // unencryptedPayload must contain a nonce to prevent collision on the same // message being sent multiple times. func NewRecipientID(pubKey *cyclic.Int, unencryptedPayload []byte) *id.ID { @@ -23,7 +23,7 @@ func NewRecipientID(pubKey *cyclic.Int, unencryptedPayload []byte) *id.ID { h, err := hash.NewCMixHash() if err != nil { jww.FATAL.Panicf("[SU] Failed to create new hash for single-use "+ - "communication recipient ID: %+v", err) + "recipient ID: %+v", err) } // Hash the public key and unencrypted payload diff --git a/e2e/singleUse/transmitFingerprint.go b/e2e/singleUse/requestFingerprint.go similarity index 78% rename from e2e/singleUse/transmitFingerprint.go rename to e2e/singleUse/requestFingerprint.go index 856de645f813d57a74ed1f0f17aa8ca5ff2c1d88..9ba058610154d47ee80b75488be43128238e0e60 100644 --- a/e2e/singleUse/transmitFingerprint.go +++ b/e2e/singleUse/requestFingerprint.go @@ -14,21 +14,20 @@ import ( "gitlab.com/elixxir/primitives/format" ) -const transmitFpSalt = "singleUseTransmitFingerprintSalt" +const requestFpSalt = "singleUseTransmitFingerprintSalt" -// NewTransmitFingerprint generates the fingerprint used for the transmission -// message. -func NewTransmitFingerprint(pubKey *cyclic.Int) format.Fingerprint { +// NewRequestFingerprint generates the fingerprint used for the request message. +func NewRequestFingerprint(pubKey *cyclic.Int) format.Fingerprint { // Create new hash h, err := hash.NewCMixHash() if err != nil { jww.FATAL.Panicf("[SU] Failed to create new hash for single-use "+ - "transmission fingerprint: %+v", err) + "request fingerprint: %+v", err) } // Hash the public key and salt h.Write(pubKey.Bytes()) - h.Write([]byte(transmitFpSalt)) + h.Write([]byte(requestFpSalt)) // Get hash bytes fp := format.Fingerprint{} diff --git a/e2e/singleUse/transmitFingerprint_test.go b/e2e/singleUse/requestFingerprint_test.go similarity index 89% rename from e2e/singleUse/transmitFingerprint_test.go rename to e2e/singleUse/requestFingerprint_test.go index 1525196befdb984de987e1de9bee19c82c7ea781..7c71d4aebbb3927fb1bb50312a65fa8760bef49b 100644 --- a/e2e/singleUse/transmitFingerprint_test.go +++ b/e2e/singleUse/requestFingerprint_test.go @@ -17,7 +17,7 @@ import ( ) // Tests that the generated fingerprints do not change. -func TestNewTransmitFingerprint_Consistency(t *testing.T) { +func TestNewRequestFingerprint_Consistency(t *testing.T) { expectedFPs := []string{ "Esl9VY4LNOmXqmmEpZfu0Koo/++Zqx/vDSqBFFpdvjI=", "ASz49SEnYLLW7KkVLbHJiYOAlkkY1r/AJBHaR2s1UDk=", @@ -37,11 +37,11 @@ func TestNewTransmitFingerprint_Consistency(t *testing.T) { diffieHellman.DefaultPrivateKeyLength, getGrp(), prng) pubKey := diffieHellman.GeneratePublicKey(privKey, getGrp()) - testFP := NewTransmitFingerprint(pubKey) + testFP := NewRequestFingerprint(pubKey) testFpBase64 := base64.StdEncoding.EncodeToString(testFP[:]) if expectedFP != testFpBase64 { - t.Errorf("NewTransmitFingerprint did not return the expected "+ + t.Errorf("NewRequestFingerprint did not return the expected "+ "fingerprint (%d).\nexpected: %s\nreceived: %s", i, expectedFP, testFpBase64) } @@ -49,7 +49,7 @@ func TestNewTransmitFingerprint_Consistency(t *testing.T) { } // Tests that all generated fingerprints are unique. -func TestNewTransmitFingerprint_Unique(t *testing.T) { +func TestNewRequestFingerprint_Unique(t *testing.T) { testRuns := 20 prng := rand.New(rand.NewSource(42)) FPs := make(map[format.Fingerprint]*cyclic.Int) @@ -58,7 +58,7 @@ func TestNewTransmitFingerprint_Unique(t *testing.T) { privKey := diffieHellman.GeneratePrivateKey( diffieHellman.DefaultPrivateKeyLength, getGrp(), prng) pubKey := diffieHellman.GeneratePublicKey(privKey, getGrp()) - testFP := NewTransmitFingerprint(pubKey) + testFP := NewRequestFingerprint(pubKey) if FPs[testFP] != nil { t.Errorf("generated fingerprint from key %s collides with "+ diff --git a/e2e/singleUse/transmitKey.go b/e2e/singleUse/requestKey.go similarity index 77% rename from e2e/singleUse/transmitKey.go rename to e2e/singleUse/requestKey.go index d8516165072f7e3020f0f828c8ad038829f77f7b..871ed67901ec9d3e801600a38f3302aa9aad6478 100644 --- a/e2e/singleUse/transmitKey.go +++ b/e2e/singleUse/requestKey.go @@ -13,20 +13,20 @@ import ( "gitlab.com/elixxir/crypto/hash" ) -const transmitKeySalt = "singleUseTransmitKeySalt" +const requestKeySalt = "singleUseTransmitKeySalt" -// NewTransmitKey generates the key used for the transmission message. -func NewTransmitKey(dhKey *cyclic.Int) []byte { +// NewRequestKey generates the key used for the request message. +func NewRequestKey(dhKey *cyclic.Int) []byte { // Create new hash h, err := hash.NewCMixHash() if err != nil { jww.FATAL.Panicf("[SU] Failed to create new hash for single-use "+ - "communication transmission key: %+v", err) + "request key: %+v", err) } // Hash the DH key and salt h.Write(dhKey.Bytes()) - h.Write([]byte(transmitKeySalt)) + h.Write([]byte(requestKeySalt)) // Get hash bytes return h.Sum(nil) diff --git a/e2e/singleUse/transmitKey_test.go b/e2e/singleUse/requestKey_test.go similarity index 89% rename from e2e/singleUse/transmitKey_test.go rename to e2e/singleUse/requestKey_test.go index d6c5b9df3da3a273a1e4e7eb5a4f857d88fd0ad5..571e17f6264fb6f60c6ee12863b501c4e401f965 100644 --- a/e2e/singleUse/transmitKey_test.go +++ b/e2e/singleUse/requestKey_test.go @@ -16,7 +16,7 @@ import ( ) // Tests that the generated keys do not change. -func TestNewTransmitKey_Consistency(t *testing.T) { +func TestNewRequestKey_Consistency(t *testing.T) { expectedKeys := []string{ "4/q8XevjJmz2ectxCr/NseWS9cSzVD/SUW36m/gk5iA=", "zdF5z3ouPBE1LX8HGuKmlif9QXoURoB8SYvJ/hmrD78=", @@ -37,18 +37,18 @@ func TestNewTransmitKey_Consistency(t *testing.T) { pubKey := diffieHellman.GeneratePublicKey(privKey, getGrp()) dhKey := diffieHellman.GenerateSessionKey(privKey, pubKey, getGrp()) - testKey := NewTransmitKey(dhKey) + testKey := NewRequestKey(dhKey) testKeyBase64 := base64.StdEncoding.EncodeToString(testKey) if expectedKey != testKeyBase64 { - t.Errorf("NewTransmitKey did not return the expected key (%d)."+ + t.Errorf("NewRequestKey did not return the expected key (%d)."+ "\nexpected: %s\nreceived: %s", i, expectedKey, testKeyBase64) } } } // Tests that all generated keys are unique. -func TestNewTransmitKey_Unique(t *testing.T) { +func TestNewRequestKey_Unique(t *testing.T) { testRuns := 20 prng := rand.New(rand.NewSource(42)) keys := make(map[string]*cyclic.Int, 100) @@ -59,7 +59,7 @@ func TestNewTransmitKey_Unique(t *testing.T) { pubKey := diffieHellman.GeneratePublicKey(privKey, getGrp()) dhKey := diffieHellman.GenerateSessionKey(privKey, pubKey, getGrp()) - testKey := base64.StdEncoding.EncodeToString(NewTransmitKey(dhKey)) + testKey := base64.StdEncoding.EncodeToString(NewRequestKey(dhKey)) if keys[testKey] != nil { t.Errorf("Generated fingerprint from key %s collides with "+ diff --git a/e2e/singleUse/requestPartFingerprint.go b/e2e/singleUse/requestPartFingerprint.go new file mode 100644 index 0000000000000000000000000000000000000000..ff34b34f4bab7bcf2ab32306884fd82abc562672 --- /dev/null +++ b/e2e/singleUse/requestPartFingerprint.go @@ -0,0 +1,46 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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/binary" + jww "github.com/spf13/jwalterweatherman" + "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/crypto/hash" + "gitlab.com/elixxir/primitives/format" +) + +const requestPartFpSalt = "singleUseRequestFingerprintSalt" + +// NewRequestPartFingerprint generates the fingerprint for the request message +// for the given key number. +func NewRequestPartFingerprint(dhKey *cyclic.Int, keyNum uint64) format.Fingerprint { + // Create new hash + h, err := hash.NewCMixHash() + if err != nil { + jww.FATAL.Panicf("[SU] Failed to create new hash for single-use "+ + "request fingerprint: %+v", err) + } + + keyNumBytes := make([]byte, binary.MaxVarintLen64) + binary.BigEndian.PutUint64(keyNumBytes, keyNum) + + // Hash the DH key, key number, and salt + h.Write(dhKey.Bytes()) + h.Write(keyNumBytes) + h.Write([]byte(requestPartFpSalt)) + + // Get hash bytes + fp := format.Fingerprint{} + copy(fp[:], h.Sum(nil)) + + // Set the first bit as zero to ensure everything stays in the group + fp[0] &= 0b01111111 + + return fp +} diff --git a/e2e/singleUse/requestPartFingerprint_test.go b/e2e/singleUse/requestPartFingerprint_test.go new file mode 100644 index 0000000000000000000000000000000000000000..c810a51e59324649b9f0583e9f9b18f5cb4b5baf --- /dev/null +++ b/e2e/singleUse/requestPartFingerprint_test.go @@ -0,0 +1,111 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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" + "gitlab.com/elixxir/primitives/format" + "math/rand" + "testing" +) + +// Tests that the generated fingerprints do not change. +func TestNewRequestPartFingerprint_Consistency(t *testing.T) { + expectedFPs := []string{ + "PaTmC4OhL7KbVlkNIJicM4Sn9GU3bMKCPzJSlkxjG5w=", + "RwI/482PG2ACCCBkxLB7+F7C/ACoZV+7fCWOlGiCDug=", + "NHLoiQv/Yk/0n/yhkE2qoSrFd/xbLJHoLMZ4mObR7Bs=", + "QfA79KzBVFpK7fwpZ4+47qoNTmDysqgRI+20DMaGAxU=", + "Zw+9I09LbCth9V1MQtrfv0JyzJvi8ofTfzH77CLTRpg=", + "cYBGtTn2H72Iw/5L6uHuvx92f328cmx2WPMo1r80o5s=", + "f4dYVtCFDYg4b7CVShUFOQxDeZvENdBttQG1MuXmWL8=", + "NiJ9VBoQcex8kYj+1nZHmN/zo4TxcVtCA6ZDPB2jV88=", + "DK1W7deW13Es2tRwOvCx8W9anMvghj1ciXriKMfZyJk=", + "CK5iflM/XDHfhtRjYam3itcdqOnmyonAntJQyF4z4IY=", + } + prng := rand.New(rand.NewSource(42)) + + for i, expectedFP := range expectedFPs { + privKey := diffieHellman.GeneratePrivateKey( + diffieHellman.DefaultPrivateKeyLength, getGrp(), prng) + pubKey := diffieHellman.GeneratePublicKey(privKey, getGrp()) + dhKey := diffieHellman.GenerateSessionKey(privKey, pubKey, getGrp()) + + testFP := NewRequestPartFingerprint(dhKey, uint64(i)) + testFpBase64 := base64.StdEncoding.EncodeToString(testFP[:]) + + if expectedFP != testFpBase64 { + t.Errorf("NewRequestPartFingerprint did not return the expected "+ + "fingerprint (%d).\nexpected: %s\nreceived: %s", + i, expectedFP, testFpBase64) + } + } +} + +// Tests that all generated fingerprints are unique. +func TestNewRequestPartFingerprint_Unique(t *testing.T) { + testRuns := 20 + prng := rand.New(rand.NewSource(42)) + FPs := make(map[format.Fingerprint]struct { + dhKey *cyclic.Int + keyNum uint64 + }) + + // Test with same DH key but differing key numbers + for i := 0; i < testRuns; i++ { + privKey := diffieHellman.GeneratePrivateKey( + diffieHellman.DefaultPrivateKeyLength+i, getGrp(), prng) + pubKey := diffieHellman.GeneratePublicKey(privKey, getGrp()) + dhKey := diffieHellman.GenerateSessionKey(privKey, pubKey, getGrp()) + for j := 0; j < testRuns; j++ { + testFP := NewRequestPartFingerprint(dhKey, uint64(j)) + + if _, exists := FPs[testFP]; exists { + t.Errorf("Generated fingerprint collides with previously "+ + "generated fingerprint (%d, %d)."+ + "\ncurrent FP: dhKey: %s keyNum: %d"+ + "\npreviouse FP: dhKey: %s keyNum: %d"+ + "\nfingerprint: %s", i, j, dhKey.Text(10), j, + FPs[testFP].dhKey.Text(10), FPs[testFP].keyNum, testFP) + } else { + FPs[testFP] = struct { + dhKey *cyclic.Int + keyNum uint64 + }{dhKey, uint64(j)} + } + } + } + + // Test with same key numbers but differing DH keys + for i := 0; i < testRuns; i++ { + for j := 0; j < testRuns; j++ { + privKey := diffieHellman.GeneratePrivateKey( + diffieHellman.DefaultPrivateKeyLength+j, getGrp(), prng) + pubKey := diffieHellman.GeneratePublicKey(privKey, getGrp()) + dhKey := diffieHellman.GenerateSessionKey(privKey, pubKey, getGrp()) + testFP := NewRequestPartFingerprint(dhKey, uint64(i)) + + if _, exists := FPs[testFP]; exists { + t.Errorf("Generated fingerprint collides with previously "+ + "generated fingerprint (%d, %d)."+ + "\ncurrent FP: dhKey: %s keyNum: %d"+ + "\npreviouse FP: dhKey: %s keyNum: %d"+ + "\nFP: %s", i, j, + dhKey.Text(10), i, FPs[testFP].dhKey.Text(10), + FPs[testFP].keyNum, testFP) + } else { + FPs[testFP] = struct { + dhKey *cyclic.Int + keyNum uint64 + }{dhKey, uint64(i)} + } + } + } +} diff --git a/e2e/singleUse/requestPartKey.go b/e2e/singleUse/requestPartKey.go new file mode 100644 index 0000000000000000000000000000000000000000..18341fe6d5d570b7d27a04d5ea38ffbfc5920a3e --- /dev/null +++ b/e2e/singleUse/requestPartKey.go @@ -0,0 +1,32 @@ +package singleUse + +import ( + "encoding/binary" + jww "github.com/spf13/jwalterweatherman" + "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/crypto/hash" +) + +const requestPartKeySalt = "singleUseRequestKeySalt" + +// NewRequestPartKey generates the key for the request message that corresponds +// with the given key number. +func NewRequestPartKey(dhKey *cyclic.Int, keyNum uint64) []byte { + // Create new hash + h, err := hash.NewCMixHash() + if err != nil { + jww.ERROR.Panicf( + "[SU] Failed to create new hash for single-use request key: %v", err) + } + + keyNumBytes := make([]byte, binary.MaxVarintLen64) + binary.BigEndian.PutUint64(keyNumBytes, keyNum) + + // Hash the DH key, key number, and salt + h.Write(dhKey.Bytes()) + h.Write(keyNumBytes) + h.Write([]byte(requestPartKeySalt)) + + // Get hash bytes + return h.Sum(nil) +} diff --git a/e2e/singleUse/requestPartKey_test.go b/e2e/singleUse/requestPartKey_test.go new file mode 100644 index 0000000000000000000000000000000000000000..8fff70db1d0fc6936128509b72f4686afd79f1b3 --- /dev/null +++ b/e2e/singleUse/requestPartKey_test.go @@ -0,0 +1,112 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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 key does not change. +func TestNewRequestPartKey_Consistency(t *testing.T) { + expectedKeys := []string{ + "8XtqywBq3DkBgaNaMKL+kOlRtvqIbrVM/uqNR9RzOXY=", + "GbjOauzOwLkRmfXf20tzS8lI2SDB2axUpeTwm5cuZ+I=", + "+dD0KPb1mXqa3PwC1lKnl3CpFtBd8pkue+Rc8ldNUHo=", + "C+iAEWU9+UEN9qlPddc2N/Y+tz1j4+ESy6j69kdhvbU=", + "X0SKzdhUTprC7I7QhbHO/sfK29fPHoRyGnKv2TQtCzE=", + "g71Vjy5LyyHmC2d2rIqtQdACmUlmh2QB/sifsJn+xxg=", + "pXbguTkf+8xQ5u3Vv8PsG492HX+SloxbYmyarJZf9cY=", + "/4vreuoOfvFQXKCD+23MuZHuiwHUvpqua5F07Hwa6zw=", + "YuDVXt+BiBOBnLSLAgKytGLkdXrR6zMlJ+CWQ+b2lg0=", + "F/TNYF1lPR9uxk4TIHVzSOzFbizautINZmzUKb43P3k=", + } + prng := rand.New(rand.NewSource(42)) + + for i, expectedKey := range expectedKeys { + privKey := diffieHellman.GeneratePrivateKey( + diffieHellman.DefaultPrivateKeyLength, getGrp(), prng) + pubKey := diffieHellman.GeneratePublicKey(privKey, getGrp()) + dhKey := diffieHellman.GenerateSessionKey(privKey, pubKey, getGrp()) + + testKey := NewRequestPartKey(dhKey, uint64(i)) + testKeyBase64 := base64.StdEncoding.EncodeToString(testKey) + + if expectedKey != testKeyBase64 { + t.Errorf("NewRequestPartKey did not return the expected key (%d)."+ + "\nexpected: %s\nreceived: %s", i, expectedKey, testKeyBase64) + } + } +} + +// Tests that all generated keys are unique. +func TestNewRequestPartKey_Unique(t *testing.T) { + testRuns := 20 + prng := rand.New(rand.NewSource(42)) + keys := make(map[string]struct { + dhKey *cyclic.Int + keyNum uint64 + }) + + // Test with same DH key but differing key numbers + for i := 0; i < testRuns; i++ { + privKey := diffieHellman.GeneratePrivateKey( + diffieHellman.DefaultPrivateKeyLength+i, getGrp(), prng) + pubKey := diffieHellman.GeneratePublicKey(privKey, getGrp()) + dhKey := diffieHellman.GenerateSessionKey(privKey, pubKey, getGrp()) + for j := 0; j < testRuns; j++ { + testKey := NewRequestPartKey(dhKey, uint64(j)) + testKeyBase64 := base64.StdEncoding.EncodeToString(testKey) + + if _, exists := keys[testKeyBase64]; exists { + t.Errorf("Generated key collides with previously generated "+ + "key (%d, %d)."+ + "\ncurrent key: dhKey: %s keyNum: %d"+ + "\npreviouse key: dhKey: %s keyNum: %d"+ + "\nkey: %s", i, j, + dhKey.Text(10), j, keys[testKeyBase64].dhKey.Text(10), + keys[testKeyBase64].keyNum, testKeyBase64) + } else { + keys[testKeyBase64] = struct { + dhKey *cyclic.Int + keyNum uint64 + }{dhKey, uint64(j)} + } + } + } + + // Test with same key number but differing DH keys + for i := 0; i < testRuns; i++ { + for j := 0; j < testRuns; j++ { + privKey := diffieHellman.GeneratePrivateKey( + diffieHellman.DefaultPrivateKeyLength+j, getGrp(), prng) + pubKey := diffieHellman.GeneratePublicKey(privKey, getGrp()) + dhKey := diffieHellman.GenerateSessionKey(privKey, pubKey, getGrp()) + testKey := NewRequestPartKey(dhKey, uint64(i)) + testKeyBase64 := base64.StdEncoding.EncodeToString(testKey) + + if _, exists := keys[testKeyBase64]; exists { + t.Errorf("Generated key collides with previously generated "+ + "key (%d, %d)."+ + "\ncurrent key: dhKey: %s keyNum: %d"+ + "\npreviouse key: dhKey: %s keyNum: %d"+ + "\nkey: %s", i, j, + dhKey.Text(10), i, keys[testKeyBase64].dhKey.Text(10), + keys[testKeyBase64].keyNum, testKeyBase64) + } else { + keys[testKeyBase64] = struct { + dhKey *cyclic.Int + keyNum uint64 + }{dhKey, uint64(i)} + } + } + } +} diff --git a/e2e/singleUse/tagFingerprint.go b/e2e/singleUse/tagFingerprint.go index a5dad997fce770cad6cd8b6b1d76865f1c68fafe..6cf427164f6715ba2d74dd00c7f45775cd8cd19f 100644 --- a/e2e/singleUse/tagFingerprint.go +++ b/e2e/singleUse/tagFingerprint.go @@ -14,19 +14,21 @@ import ( ) const tagFpSalt = "singleUseTagFingerprintSalt" + +// TagFpSize is the size of the TagFP type. const TagFpSize = 16 +// TagFP uniquely identifies the module that the request message belongs to. type TagFP [TagFpSize]byte -// NewTagFP generates the tag fingerprint used to identify the module that the -// transmission message belongs to. The tag can be anything, but should be long -// enough so that it is unique. +// NewTagFP generates a new tag fingerprint with the given tag. The tag can be +// anything, but should be long enough so that it is unique. func NewTagFP(tag string) TagFP { // Create new hash h, err := hash.NewCMixHash() if err != nil { jww.FATAL.Panicf("[SU] Failed to create new hash for single-use "+ - "communication tag fingerprint: %+v", err) + "tag fingerprint: %+v", err) } // Hash tag and salt