diff --git a/single/cypher.go b/single/cypher.go index f4365ddc92d28d5035db88691707671f6a352a00..7a2925b52d3378cd6f1f56353196830957046515 100644 --- a/single/cypher.go +++ b/single/cypher.go @@ -19,37 +19,37 @@ import ( // makeCyphers generates all fingerprints for a given number of messages. func makeCyphers(dhKey *cyclic.Int, messageCount uint8) []cypher { - cylist := make([]cypher, messageCount) + cypherList := make([]cypher, messageCount) for i := uint8(0); i < messageCount; i++ { - cylist[i] = cypher{ - dhkey: dhKey, + cypherList[i] = cypher{ + dhKey: dhKey, num: i, } } - return cylist + return cypherList } type cypher struct { - dhkey *cyclic.Int + dhKey *cyclic.Int num uint8 } func (rk *cypher) getKey() []byte { - return singleUse.NewResponseKey(rk.dhkey, uint64(rk.num)) + return singleUse.NewResponseKey(rk.dhKey, uint64(rk.num)) } func (rk *cypher) GetFingerprint() format.Fingerprint { - return singleUse.NewResponseFingerprint(rk.dhkey, uint64(rk.num)) + return singleUse.NewResponseFingerprint(rk.dhKey, uint64(rk.num)) } func (rk *cypher) Encrypt(rp message.ResponsePart) ( fp format.Fingerprint, encryptedPayload, mac []byte) { fp = rk.GetFingerprint() key := rk.getKey() - //fixme: encryption is identical to what is used by e2e.Crypt, lets make - //them the same codepath + // FIXME: Encryption is identical to what is used by e2e.Crypt, lets make + // them the same code path. encryptedPayload = cAuth.Crypt(key, fp[:24], rp.Marshal()) mac = singleUse.MakeMAC(key, encryptedPayload) return fp, encryptedPayload, mac @@ -65,6 +65,6 @@ func (rk *cypher) Decrypt(contents, mac []byte) ([]byte, error) { return nil, errors.New("failed to verify the single use mac") } - //decrypt the payload + // Decrypt the payload return cAuth.Crypt(key, fp[:24], contents), nil } diff --git a/single/listener.go b/single/listener.go index d2f17233abbe1985a6e89cc73add5818108a262e..7be020b5e8812bc3dc5503659051935ab1a2c661 100644 --- a/single/listener.go +++ b/single/listener.go @@ -25,24 +25,24 @@ type Listener interface { type listener struct { myId *id.ID - myPrivkey *cyclic.Int + myPrivKey *cyclic.Int tag string grp *cyclic.Group cb Receiver net cmix.Client } -// Listen allows a server to listen for single use requests. It will register -// a service relative to the tag and myID as the identifier. Only a single -// listener can be active for a tag-myID pair, and error will return if that -// is violated. When requests are receved, they will be called on the +// Listen allows a server to listen for single use requests. It will register a +// service relative to the tag and myID as the identifier. Only a single +// listener can be active for a tag-myID pair, and an error will be returned if +// that is violated. When requests are received, they will be called on the // Receiver interface. -func Listen(tag string, myId *id.ID, privkey *cyclic.Int, net cmix.Client, +func Listen(tag string, myId *id.ID, privKey *cyclic.Int, net cmix.Client, e2eGrp *cyclic.Group, cb Receiver) Listener { l := &listener{ myId: myId, - myPrivkey: privkey, + myPrivKey: privKey, tag: tag, grp: e2eGrp, cb: cb, @@ -61,22 +61,20 @@ func Listen(tag string, myId *id.ID, privkey *cyclic.Int, net cmix.Client, } func (l *listener) Process(ecrMsg format.Message, - receptionID receptionID.EphemeralIdentity, - round rounds.Round) { + receptionID receptionID.EphemeralIdentity, round rounds.Round) { // Unmarshal the CMIX message contents to a transmission message transmitMsg, err := message.UnmarshalRequest(ecrMsg.GetContents(), l.grp.GetP().ByteLen()) if err != nil { - jww.WARN.Printf("failed to unmarshal contents on single use "+ + jww.WARN.Printf("Failed to unmarshal contents on single use "+ "request to %s on tag %s: %+v", l.myId, l.tag, err) return } // Generate DH key and symmetric key senderPubkey := transmitMsg.GetPubKey(l.grp) - dhKey := l.grp.Exp(senderPubkey, l.myPrivkey, - l.grp.NewInt(1)) + dhKey := l.grp.Exp(senderPubkey, l.myPrivKey, l.grp.NewInt(1)) key := singleUse.NewTransmitKey(dhKey) // Verify the MAC diff --git a/single/message/collator.go b/single/message/collator.go index 842d404ed8e223f4f25ec72a5b187b0cec1ee3cc..04ee11ab0e535bacc22ab4bb6f23a0e6c374e927 100644 --- a/single/message/collator.go +++ b/single/message/collator.go @@ -6,7 +6,7 @@ import ( "sync" ) -// Initial value of the Collator maxNum that indicates it has yet to be set +// Initial value of the Collator maxNum that indicates it has yet to be set. const unsetCollatorMax = -1 // Collator stores the list of payloads in the correct order. @@ -27,11 +27,11 @@ func NewCollator(messageCount uint8) *Collator { } // Collate collects message payload parts. Once all parts are received, the full -// collated payload is returned along with true. Otherwise returns false. +// collated payload is returned along with true. Otherwise, returns false. func (c *Collator) Collate(payloadBytes []byte) ([]byte, bool, error) { payload, err := UnmarshalResponse(payloadBytes) if err != nil { - return nil, false, errors.Errorf("Failed to unmarshal response "+ + return nil, false, errors.Errorf("failed to unmarshal response "+ "payload: %+v", err) } @@ -39,7 +39,7 @@ func (c *Collator) Collate(payloadBytes []byte) ([]byte, bool, error) { defer c.Unlock() // If this is the first message received, then set the max number of - // messages expected to be received off its max number of parts. + // messages expected to be received off its max number of parts if c.maxNum == unsetCollatorMax { if int(payload.GetNumParts()) > len(c.payloads) { return nil, false, errors.Errorf("Max number of parts reported by "+ diff --git a/single/message/collator_test.go b/single/message/collator_test.go index 6d7888326288ae2c0e0b5ff84da95416be179dbd..37be27c59669ad08082ac26fcbb2fc59f611c30c 100644 --- a/single/message/collator_test.go +++ b/single/message/collator_test.go @@ -18,7 +18,7 @@ func Test_newCollator(t *testing.T) { c := NewCollator(messageCount) if !reflect.DeepEqual(expected, c) { - t.Errorf("NewCollator() failed to generated the expected Collator."+ + t.Errorf("NewCollator failed to generate the expected Collator."+ "\nexepcted: %+v\nreceived: %+v", expected, c) } } @@ -51,20 +51,20 @@ func TestCollator_collate(t *testing.T) { fullPayload, collated, err = c.Collate(part.Marshal()) if err != nil { - t.Errorf("Collate() returned an error for part #%d: %+v", j, err) + t.Errorf("Collate returned an error for part #%d: %+v", j, err) } if i == messageCount && (!collated || fullPayload == nil) { - t.Errorf("Collate() failed to Collate a completed payload."+ + t.Errorf("Collate failed to collate a completed payload."+ "\ncollated: %v\nfullPayload: %+v", collated, fullPayload) } else if i < messageCount && (collated || fullPayload != nil) { - t.Errorf("Collate() signaled it collated an unfinished payload."+ + t.Errorf("Collate signaled it collated an unfinished payload."+ "\ncollated: %v\nfullPayload: %+v", collated, fullPayload) } } if !bytes.Equal(expectedData, fullPayload) { - t.Errorf("Collate() failed to return the correct collated data."+ + t.Errorf("Collate failed to return the correct collated data."+ "\nexpected: %s\nreceived: %s", expectedData, fullPayload) } } @@ -74,31 +74,35 @@ func TestCollator_collate_UnmarshalError(t *testing.T) { payloadBytes := []byte{1} c := NewCollator(1) payload, collated, err := c.Collate(payloadBytes) + expectedErr := "unmarshal" - if err == nil || !strings.Contains(err.Error(), "unmarshal") { - t.Errorf("Collate() failed to return an error for failing to "+ - "unmarshal the payload.\nerror: %+v", err) + if err == nil || !strings.Contains(err.Error(), expectedErr) { + t.Errorf("Collate failed to return an error for failing to "+ + "unmarshal the payload.\nexpected: %s\nreceived: %+v", + expectedErr, err) } if payload != nil || collated { - t.Errorf("Collate() signaled the payload was collated on error."+ + t.Errorf("Collate signaled the payload was collated on error."+ "\npayload: %+v\ncollated: %+v", payload, collated) } } -// Error path: max reported parts by payload larger then set in Collator +// Error path: max reported parts by payload larger than set in Collator. func TestCollator_collate_MaxPartsError(t *testing.T) { payloadBytes := []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF} c := NewCollator(1) payload, collated, err := c.Collate(payloadBytes) + expectedErr := "Max number of parts" - if err == nil || !strings.Contains(err.Error(), "Max number of parts") { - t.Errorf("Collate() failed to return an error when the max number of "+ - "parts is larger than the payload size.\nerror: %+v", err) + if err == nil || !strings.Contains(err.Error(), expectedErr) { + t.Errorf("Collate failed to return an error when the max number of "+ + "parts is larger than the payload size."+ + "\nexpected: %s\nreceived: %+v", expectedErr, err) } if payload != nil || collated { - t.Errorf("Collate() signaled the payload was collated on error."+ + t.Errorf("Collate signaled the payload was collated on error."+ "\npayload: %+v\ncollated: %+v", payload, collated) } } @@ -107,16 +111,13 @@ func TestCollator_collate_MaxPartsError(t *testing.T) { func TestCollator_collate_PartNumTooLargeError(t *testing.T) { payloadBytes := []byte{25, 5, 5, 5, 5} c := NewCollator(5) - payload, collated, err := c.Collate(payloadBytes) - - if err == nil || !strings.Contains(err.Error(), "greater than max number of expected parts") { - t.Errorf("Collate() failed to return an error when the part number is "+ - "greater than the max number of parts.\nerror: %+v", err) - } + _, _, err := c.Collate(payloadBytes) + expectedErr := "greater than max number of expected parts" - if payload != nil || collated { - t.Errorf("Collate() signaled the payload was collated on error."+ - "\npayload: %+v\ncollated: %+v", payload, collated) + if err == nil || !strings.Contains(err.Error(), expectedErr) { + t.Errorf("Collate failed to return the expected error when the part "+ + "number is greater than the max number of parts."+ + "\nexpected: %s\nreceived: %+v", expectedErr, err) } } @@ -124,19 +125,15 @@ func TestCollator_collate_PartNumTooLargeError(t *testing.T) { func TestCollator_collate_PartExistsError(t *testing.T) { payloadBytes := []byte{0, 1, 5, 0, 1, 20} c := NewCollator(5) - payload, collated, err := c.Collate(payloadBytes) + _, _, err := c.Collate(payloadBytes) if err != nil { - t.Fatalf("Collate() returned an error: %+v", err) - } - - payload, collated, err = c.Collate(payloadBytes) - if err == nil || !strings.Contains(err.Error(), "A payload for the part number") { - t.Errorf("Collate() failed to return an error when the part number "+ - "already exists.\nerror: %+v", err) + t.Fatalf("Collate returned an error: %+v", err) } + expectedErr := "A payload for the part number" - if payload != nil || collated { - t.Errorf("Collate() signaled the payload was collated on error."+ - "\npayload: %+v\ncollated: %+v", payload, collated) + _, _, err = c.Collate(payloadBytes) + if err == nil || !strings.Contains(err.Error(), expectedErr) { + t.Errorf("Collate failed to return an error when the part number "+ + "already exists.\nexpected: %s\nreceived: %+v", expectedErr, err) } } diff --git a/single/message/request.go b/single/message/request.go index 60f372e8b3aa8deab89a315cd2f32b5d0e2044bd..d2b0280446998f67017823b9903051ba79974eb7 100644 --- a/single/message/request.go +++ b/single/message/request.go @@ -19,15 +19,15 @@ import ( ) /* -+------------------------------------------------------------------------------+ -| CMIX Message Contents | -+------------+-------------------------------------------- --------+ -| Version | pubKey | payload (RequestPayload) | -| 1 byte | pubKeySize | externalPayloadSize - pubKeySize | -+------------+------------+----------+---------+----------+---------+----------+ - | Tag FP | nonce | maxResponseParts | size | contents | - | 16 bytes | 8 bytes | 1 byte | 2 bytes | variable | - +----------+---------+----------+---------+----------+ ++-------------------------------------------------------------------------------------+ +| CMIX Message Contents | ++-----------+------------+------------------------------------------------------------+ +| Version | pubKey | payload (RequestPayload) | +| 1 byte | pubKeySize | externalPayloadSize - pubKeySize | ++-----------+------------+----------+---------+------------------+---------+----------+ + | Tag FP | nonce | maxResponseParts | size | contents | + | 16 bytes | 8 bytes | 1 byte | 2 bytes | variable | + +----------+---------+------------------+---------+----------+ */ const transmitMessageVersion = 0 @@ -138,9 +138,9 @@ const ( // RequestPayload is the structure of Request's payload. type RequestPayload struct { - data []byte // Serial of all contents e + data []byte // Serial of all contents nonce []byte - numRequestParts []byte //number fo parts in the request, currently always 1 + numRequestParts []byte // Number of parts in the request, currently always 1 maxResponseParts []byte // Max number of messages expected in response size []byte // Size of the contents contents []byte @@ -207,7 +207,7 @@ func (mp RequestPayload) GetRID(pubKey *cyclic.Int) *id.ID { return singleUse.NewRecipientID(pubKey, mp.Marshal()) } -// GetNonce returns the nonce as a uint64. +// GetNonce returns the nonce as an uint64. func (mp RequestPayload) GetNonce() uint64 { return binary.BigEndian.Uint64(mp.nonce) } diff --git a/single/message/request_test.go b/single/message/request_test.go index 0e4cd087855550ba691e67edf8fbe82638d5ed81..2e577729ce9fe23263dd508f83b692bf37104229 100644 --- a/single/message/request_test.go +++ b/single/message/request_test.go @@ -35,7 +35,7 @@ func Test_newTransmitMessage(t *testing.T) { m := NewRequest(externalPayloadSize, pubKeySize) if !reflect.DeepEqual(expected, m) { - t.Errorf("NewRequest() did not produce the expected Request."+ + t.Errorf("NewRequest did not produce the expected Request."+ "\nexpected: %#v\nreceived: %#v", expected, m) } } @@ -44,7 +44,7 @@ func Test_newTransmitMessage(t *testing.T) { func Test_newTransmitMessage_PubKeySizeError(t *testing.T) { defer func() { if r := recover(); r == nil || !strings.Contains(r.(string), "Payload size") { - t.Error("NewRequest() did not panic when the size of " + + t.Error("NewRequest did not panic when the size of " + "the payload is smaller than the size of the public key.") } }() @@ -69,17 +69,17 @@ func Test_mapTransmitMessage(t *testing.T) { m := mapRequest(data, pubKeySize) if !bytes.Equal(data, m.data) { - t.Errorf("mapRequest() failed to map the correct bytes for data."+ + t.Errorf("mapRequest failed to map the correct bytes for data."+ "\nexpected: %+v\nreceived: %+v", data, m.data) } if !bytes.Equal(pubKey, m.pubKey) { - t.Errorf("mapRequest() failed to map the correct bytes for pubKey."+ + t.Errorf("mapRequest failed to map the correct bytes for pubKey."+ "\nexpected: %+v\nreceived: %+v", pubKey, m.pubKey) } if !bytes.Equal(payload, m.payload) { - t.Errorf("mapRequest() failed to map the correct bytes for payload."+ + t.Errorf("mapRequest failed to map the correct bytes for payload."+ "\nexpected: %+v\nreceived: %+v", payload, m.payload) } } @@ -110,7 +110,7 @@ func TestTransmitMessage_Marshal_Unmarshal(t *testing.T) { func Test_unmarshalTransmitMessage_PubKeySizeError(t *testing.T) { _, err := UnmarshalRequest([]byte{1, 2, 3}, 5) if err == nil { - t.Error("unmarshalRequest() did not produce an error when the " + + t.Error("unmarshalRequest did not produce an error when the " + "byte slice is smaller than the public key size.") } } @@ -126,12 +126,12 @@ func TestTransmitMessage_SetPubKey_GetPubKey_GetPubKeySize(t *testing.T) { testPubKey := m.GetPubKey(grp) if pubKey.Cmp(testPubKey) != 0 { - t.Errorf("GetPubKey() failed to get correct public key."+ + t.Errorf("GetPubKey failed to get correct public key."+ "\nexpected: %s\nreceived: %s", pubKey.Text(10), testPubKey.Text(10)) } if pubKeySize != m.GetPubKeySize() { - t.Errorf("GetPubKeySize() failed to return the correct size."+ + t.Errorf("GetPubKeySize failed to return the correct size."+ "\nexpected: %d\nreceived: %d", pubKeySize, m.GetPubKeySize()) } } @@ -149,22 +149,25 @@ func TestTransmitMessage_SetPayload_GetPayload_GetPayloadSize(t *testing.T) { testPayload := m.GetPayload() if !bytes.Equal(payload, testPayload) { - t.Errorf("GetContents() returned incorrect payload."+ + t.Errorf("GetContents returned incorrect payload."+ "\nexpected: %+v\nreceived: %+v", payload, testPayload) } if payloadSize != m.GetPayloadSize() { - t.Errorf("GetContentsSize() returned incorrect content size."+ + t.Errorf("GetContentsSize returned incorrect content size."+ "\nexpected: %d\nreceived: %d", payloadSize, m.GetPayloadSize()) } } // Error path: supplied payload is not the same size as message payload. func TestTransmitMessage_SetPayload_PayloadSizeError(t *testing.T) { + expectedErr := "is not the same as the size" defer func() { - if r := recover(); r == nil || !strings.Contains(r.(string), "is not the same as the size") { - t.Error("SetContents() did not panic when the size of supplied " + - "contents is not the same size as message contents.") + if r := recover(); r == nil || !strings.Contains(r.(string), expectedErr) { + t.Errorf("SetContents did not panic with the expected error when "+ + "the size of supplied contents is not the same size as "+ + "message contents.\nexpected: %s\nreceived: %+v", + expectedErr, r) } }() @@ -187,24 +190,29 @@ func Test_newTransmitMessagePayload(t *testing.T) { expected.numRequestParts[0] = 1 binary.BigEndian.PutUint16(expected.size, uint16(payloadSize-transmitPlMinSize)) expected.SetMaxResponseParts(10) - expected.data = append(expected.nonce, append(expected.numRequestParts, append(expected.maxResponseParts, append(expected.size, expected.contents...)...)...)...) + expected.data = append(expected.nonce, + append(expected.numRequestParts, + append(expected.maxResponseParts, + append(expected.size, expected.contents...)...)...)...) payload := make([]byte, payloadSize-transmitPlMinSize) mp := NewRequestPayload(payloadSize, payload, 10) if !reflect.DeepEqual(expected, mp) { - t.Errorf("NewRequestPayload() did not produce the expected "+ + t.Errorf("NewRequestPayload did not produce the expected "+ "RequestPayload.\nexpected: %+v\nreceived: %+v", expected, mp) } } -// Error path: payload size is smaller than than rid size + maxResponseParts size. +// Error path: payload size is smaller than rid size + maxResponseParts size. func Test_newTransmitMessagePayload_PayloadSizeError(t *testing.T) { + expectedErr := "Size of single-use transmission message payload" defer func() { - if r := recover(); r == nil || !strings.Contains(r.(string), "Size of single-use transmission message payload") { - t.Error("NewRequestPayload() did not panic when the size " + - "of the payload is smaller than the size of the reception ID " + - "+ the message count.") + if r := recover(); r == nil || !strings.Contains(r.(string), expectedErr) { + t.Errorf("NewRequestPayload did not panic with the expected error "+ + "when the size of the payload is smaller than the size of the "+ + "reception ID + the message count.\nexpected: %s\nreceived: %+v", + expectedErr, r) } }() payloadSize := 10 @@ -237,17 +245,17 @@ func Test_mapTransmitMessagePayload(t *testing.T) { mp := mapRequestPayload(data) if !bytes.Equal(data, mp.data) { - t.Errorf("mapRequestPayload() failed to map the correct bytes "+ + t.Errorf("mapRequestPayload failed to map the correct bytes "+ "for data.\nexpected: %+v\nreceived: %+v", data, mp.data) } if !bytes.Equal(nonceBytes, mp.nonce) { - t.Errorf("mapRequestPayload() failed to map the correct bytes "+ + t.Errorf("mapRequestPayload failed to map the correct bytes "+ "for the nonce.\nexpected: %s\nreceived: %s", nonceBytes, mp.nonce) } if !bytes.Equal(numRequestParts, mp.numRequestParts) { - t.Errorf("mapRequestPayload() failed to map the correct bytes "+ + t.Errorf("mapRequestPayload failed to map the correct bytes "+ "for the numRequestParts.\nexpected: %s\nreceived: %s", nonceBytes, mp.nonce) } @@ -256,12 +264,12 @@ func Test_mapTransmitMessagePayload(t *testing.T) { } if !bytes.Equal(size, mp.size) { - t.Errorf("mapRequestPayload() failed to map the correct bytes "+ + t.Errorf("mapRequestPayload failed to map the correct bytes "+ "for size.\nexpected: %+v\nreceived: %+v", size, mp.size) } if !bytes.Equal(contents, mp.contents) { - t.Errorf("mapRequestPayload() failed to map the correct bytes "+ + t.Errorf("mapRequestPayload failed to map the correct bytes "+ "for contents.\nexpected: %+v\nreceived: %+v", contents, mp.contents) } } @@ -277,7 +285,7 @@ func TestTransmitMessagePayload_Marshal_Unmarshal(t *testing.T) { testPayload, err := UnmarshalRequestPayload(payloadBytes) if err != nil { - t.Errorf("UnmarshalRequestPayload() produced an error: %+v", err) + t.Errorf("UnmarshalRequestPayload produced an error: %+v", err) } if !reflect.DeepEqual(mp, testPayload) { @@ -290,7 +298,7 @@ func TestTransmitMessagePayload_Marshal_Unmarshal(t *testing.T) { func Test_unmarshalTransmitMessagePayload(t *testing.T) { _, err := UnmarshalRequestPayload([]byte{6}) if err == nil { - t.Error("UnmarshalRequestPayload() did not return an error " + + t.Error("UnmarshalRequestPayload did not return an error " + "when the supplied byte slice was too small.") } } @@ -311,7 +319,7 @@ func TestTransmitMessagePayload_GetRID(t *testing.T) { testRID := mp.GetRID(getGroup().NewInt(42)) if !expectedRID.Cmp(testRID) { - t.Errorf("GetRID() did not return the expected ID."+ + t.Errorf("GetRID did not return the expected ID."+ "\nexpected: %s\nreceived: %s", expectedRID, testRID) } } @@ -333,11 +341,11 @@ func Test_transmitMessagePayload_SetNonce_GetNonce(t *testing.T) { binary.BigEndian.PutUint64(expectedNonceBytes, expectedNonce) err = mp.SetNonce(strings.NewReader(string(expectedNonceBytes))) if err != nil { - t.Errorf("SetNonce() produced an error: %+v", err) + t.Errorf("SetNonce produced an error: %+v", err) } if expectedNonce != mp.GetNonce() { - t.Errorf("GetNonce() did not return the expected nonce."+ + t.Errorf("GetNonce did not return the expected nonce."+ "\nexpected: %d\nreceived: %d", expectedNonce, mp.GetNonce()) } } @@ -356,7 +364,7 @@ func Test_transmitMessagePayload_SetNonce_RngError(t *testing.T) { err = mp.SetNonce(strings.NewReader("")) if !check(err, "failed to generate nonce") { - t.Errorf("SetNonce() did not return an error when nonce generation "+ + t.Errorf("SetNonce did not return an error when nonce generation "+ "fails: %+v", err) } } @@ -378,7 +386,7 @@ func TestTransmitMessagePayload_SetMaxParts_GetMaxParts(t *testing.T) { testCount := mp.GetMaxResponseParts() if count != testCount { - t.Errorf("GetNumParts() did not return the expected count."+ + t.Errorf("GetNumParts did not return the expected count."+ "\nexpected: %d\nreceived: %d", count, testCount) } } @@ -395,27 +403,31 @@ func TestTransmitMessagePayload_SetContents_GetContents_GetContentsSize_GetMaxCo testContents := mp.GetContents() if !bytes.Equal(contents, testContents) { - t.Errorf("GetContents() did not return the expected contents."+ + t.Errorf("GetContents did not return the expected contents."+ "\nexpected: %+v\nreceived: %+v", contents, testContents) } if contentsSize != mp.GetContentsSize() { - t.Errorf("GetContentsSize() did not return the expected size."+ + t.Errorf("GetContentsSize did not return the expected size."+ "\nexpected: %d\nreceived: %d", contentsSize, mp.GetContentsSize()) } if format.MinimumPrimeSize-transmitPlMinSize != mp.GetMaxContentsSize() { - t.Errorf("GetMaxContentsSize() did not return the expected size."+ - "\nexpected: %d\nreceived: %d", format.MinimumPrimeSize-transmitPlMinSize, mp.GetMaxContentsSize()) + t.Errorf("GetMaxContentsSize did not return the expected size."+ + "\nexpected: %d\nreceived: %d", + format.MinimumPrimeSize-transmitPlMinSize, mp.GetMaxContentsSize()) } } // Error path: supplied bytes are smaller than payload contents. func TestTransmitMessagePayload_SetContents(t *testing.T) { + expectedErr := "max size of message content" defer func() { - if r := recover(); r == nil || !strings.Contains(r.(string), "max size of message content") { - t.Error("SetContents() did not panic when the size of the " + - "supplied bytes is not the same as the payload content size.") + if r := recover(); r == nil || !strings.Contains(r.(string), expectedErr) { + t.Errorf("SetContents did not panic with the expected error when "+ + "the size of the supplied bytes is not the same as the "+ + "payload content size.\nexpected: %s\nreceived: %+v", + expectedErr, r) } }() diff --git a/single/message/response.go b/single/message/response.go index 2fde98e94019e538b4fbf638d143079a363ecaae..55651e50d6f2d08e9b920d149563e6d30651201c 100644 --- a/single/message/response.go +++ b/single/message/response.go @@ -22,12 +22,12 @@ const ( ) /* -+---------------------------------------------------+ -| CMIX Message Contents | -+---------+----------+---------+---------+----------+ ++-----------------------------------------------------------+ +| CMIX Message Contents | ++---------+------------------+---------+---------+----------+ | version | maxResponseParts | size | partNum | contents | -| 1 bytes | 1 byte | 2 bytes | 1 bytes | variable | -+------------+----------+---------+------+----------+ +| 1 bytes | 1 byte | 2 bytes | 1 bytes | variable | ++---------+------------------+---------+---------+----------+ */ type ResponsePart struct { @@ -39,8 +39,7 @@ type ResponsePart struct { contents []byte // The encrypted contents } -// NewResponsePart generates a new response message part of the specified -// size. +// NewResponsePart generates a new response message part of the specified size. func NewResponsePart(externalPayloadSize int) ResponsePart { if externalPayloadSize < responseMinSize { jww.FATAL.Panicf("Failed to create new single-use response message "+ diff --git a/single/message/response_test.go b/single/message/response_test.go index 4d4e85fcb2c6bae21f48c85c6059615f6a65c969..13f1c1e2367476795a747de2398a23e4e7c67c9e 100644 --- a/single/message/response_test.go +++ b/single/message/response_test.go @@ -31,17 +31,19 @@ func Test_newResponseMessagePart(t *testing.T) { rmp := NewResponsePart(payloadSize) if !reflect.DeepEqual(expected, rmp) { - t.Errorf("NewResponsePart() did not return the expected "+ + t.Errorf("NewResponsePart did not return the expected "+ "ResponsePart.\nexpected: %+v\nreceived: %+v", expected, rmp) } } // Error path: provided contents size is not large enough. func Test_newResponseMessagePart_PayloadSizeError(t *testing.T) { + expectedErr := "size of external payload" defer func() { - if r := recover(); r == nil || !strings.Contains(r.(string), "size of external payload") { - t.Error("NewResponsePart() did not panic when the size of " + - "the payload is smaller than the required size.") + if r := recover(); r == nil || !strings.Contains(r.(string), expectedErr) { + t.Errorf("NewResponsePart did not panic with the expected error "+ + "when the size of the payload is smaller than the required "+ + "size.\nexpected: %s\nreceived: %+v", expectedErr, r) } }() @@ -65,22 +67,22 @@ func Test_mapResponseMessagePart(t *testing.T) { rmp := mapResponsePart(data) if expectedPartNum != rmp.partNum[0] { - t.Errorf("mapResponsePart() did not correctly map partNum."+ + t.Errorf("mapResponsePart did not correctly map partNum."+ "\nexpected: %d\nreceived: %d", expectedPartNum, rmp.partNum[0]) } if expectedMaxParts != rmp.maxParts[0] { - t.Errorf("mapResponsePart() did not correctly map maxResponseParts."+ + t.Errorf("mapResponsePart did not correctly map maxResponseParts."+ "\nexpected: %d\nreceived: %d", expectedMaxParts, rmp.maxParts[0]) } if !bytes.Equal(expectedContents, rmp.contents) { - t.Errorf("mapResponsePart() did not correctly map contents."+ + t.Errorf("mapResponsePart did not correctly map contents."+ "\nexpected: %+v\nreceived: %+v", expectedContents, rmp.contents) } if !bytes.Equal(data, rmp.data) { - t.Errorf("mapResponsePart() did not save the data correctly."+ + t.Errorf("mapResponsePart did not save the data correctly."+ "\nexpected: %+v\nreceived: %+v", data, rmp.data) } } @@ -96,11 +98,11 @@ func TestResponseMessagePart_Marshal_Unmarshal(t *testing.T) { newRmp, err := UnmarshalResponse(data) if err != nil { - t.Errorf("UnmarshalResponse() produced an error: %+v", err) + t.Errorf("UnmarshalResponse produced an error: %+v", err) } if !reflect.DeepEqual(rmp, newRmp) { - t.Errorf("Failed to Marshal() and unmarshal() the ResponsePart."+ + t.Errorf("Failed to Marshal and unmarshal the ResponsePart."+ "\nexpected: %+v\nrecieved: %+v", rmp, newRmp) } } @@ -109,7 +111,7 @@ func TestResponseMessagePart_Marshal_Unmarshal(t *testing.T) { func Test_unmarshalResponseMessage(t *testing.T) { _, err := UnmarshalResponse([]byte{1}) if err == nil { - t.Error("UnmarshalResponse() did not produce an error when the " + + t.Error("UnmarshalResponse did not produce an error when the " + "byte slice is smaller required.") } } @@ -123,7 +125,7 @@ func TestResponseMessagePart_SetPartNum_GetPartNum(t *testing.T) { rmp.SetPartNum(expectedPartNum) if expectedPartNum != rmp.GetPartNum() { - t.Errorf("GetPartNum() failed to return the expected part number."+ + t.Errorf("GetPartNum failed to return the expected part number."+ "\nexpected: %d\nrecieved: %d", expectedPartNum, rmp.GetPartNum()) } } @@ -137,7 +139,7 @@ func TestResponseMessagePart_SetMaxParts_GetMaxParts(t *testing.T) { rmp.SetNumParts(expectedMaxParts) if expectedMaxParts != rmp.GetNumParts() { - t.Errorf("GetNumParts() failed to return the expected max parts."+ + t.Errorf("GetNumParts failed to return the expected max parts."+ "\nexpected: %d\nrecieved: %d", expectedMaxParts, rmp.GetNumParts()) } } @@ -153,28 +155,30 @@ func TestResponseMessagePart_SetContents_GetContents_GetContentsSize_GetMaxConte rmp.SetContents(expectedContents) if !bytes.Equal(expectedContents, rmp.GetContents()) { - t.Errorf("GetContents() failed to return the expected contents."+ + t.Errorf("GetContents failed to return the expected contents."+ "\nexpected: %+v\nrecieved: %+v", expectedContents, rmp.GetContents()) } if contentSize != rmp.GetContentsSize() { - t.Errorf("GetContentsSize() failed to return the expected contents size."+ + t.Errorf("GetContentsSize failed to return the expected contents size."+ "\nexpected: %d\nrecieved: %d", contentSize, rmp.GetContentsSize()) } if externalPayloadSize-responseMinSize != rmp.GetMaxContentsSize() { - t.Errorf("GetMaxContentsSize() failed to return the expected max contents size."+ - "\nexpected: %d\nrecieved: %d", + t.Errorf("GetMaxContentsSize failed to return the expected max "+ + "contents size.\nexpected: %d\nrecieved: %d", externalPayloadSize-responseMinSize, rmp.GetMaxContentsSize()) } } // Error path: size of supplied contents does not match message contents size. func TestResponseMessagePart_SetContents_ContentsSizeError(t *testing.T) { + expectedErr := "max size of message contents" defer func() { - if r := recover(); r == nil || !strings.Contains(r.(string), "max size of message contents") { - t.Error("SetContents() did not panic when the size of the supplied " + - "bytes is larger than the content size.") + if r := recover(); r == nil || !strings.Contains(r.(string), expectedErr) { + t.Errorf("SetContents did not panic with the expected error when "+ + "the size of the supplied bytes is larger than the content "+ + "size.\nexpected: %s\nreceived: %+v", expectedErr, r) } }() diff --git a/single/receivedRequest.go b/single/receivedRequest.go index c425cc9dd2da4dd4f45d89b678778041d7a463d9..7de42ddcea880386e36d2590688c95bb1f58d6b6 100644 --- a/single/receivedRequest.go +++ b/single/receivedRequest.go @@ -67,9 +67,9 @@ func (r Request) String() string { } // Respond is used to respond to the request. It sends a payload up to -// r.GetMaxResponseLength(). It will chunk the message into multiple -// cmix messages if it is too long for a single message. It will fail -// If a single cmix message cannot be sent. +// Request.GetMaxResponseLength. It will chunk the message into multiple cMix +// messages if it is too long for a single message. It will fail if a single +// cMix message cannot be sent. func (r Request) Respond(payload []byte, cmixParams cmix.CMIXParams, timeout time.Duration) ([]id.Round, error) { // make sure this has only been run once @@ -79,7 +79,7 @@ func (r Request) Respond(payload []byte, cmixParams cmix.CMIXParams, "single-use response that has already been responded to.") } - //check that the payload isn't too long + // Check that the payload is not too long if len(payload) > r.GetMaxResponseLength() { return nil, errors.Errorf("length of provided "+ "payload too long for message payload capacity, max: %d, "+ @@ -87,10 +87,10 @@ func (r Request) Respond(payload []byte, cmixParams cmix.CMIXParams, len(payload)) } - //partition the payload + // Partition the payload parts := partitionResponse(payload, r.net.GetMaxMessageLength(), r.maxParts) - //encrypt and send the partitions + // Encrypt and send the partitions cyphers := makeCyphers(r.dhKey, uint8(len(parts))) rounds := make([]id.Round, len(parts)) sendResults := make(chan ds.EventReturn, len(parts)) @@ -104,7 +104,7 @@ func (r Request) Respond(payload []byte, cmixParams cmix.CMIXParams, svc := cmixMsg.Service{ Identifier: r.dhKey.Bytes(), - Tag: "single.response-dummyservice", + Tag: "single.response-dummyService", Metadata: nil, } @@ -136,7 +136,7 @@ func (r Request) Respond(payload []byte, cmixParams cmix.CMIXParams, if failed > 0 { return nil, errors.Errorf("One or more send failed for the " + - "response, the response will be handleable and will timeout") + "response, the response will be handleable and will time out") } jww.DEBUG.Printf("Sent %d single-use response CMIX messages to %s.", @@ -151,7 +151,8 @@ func (r Request) Respond(payload []byte, cmixParams cmix.CMIXParams, } // Wait until the result tracking responds - success, numRoundFail, numTimeOut := cmix.TrackResults(sendResults, len(roundMap)) + success, numRoundFail, numTimeOut := cmix.TrackResults( + sendResults, len(roundMap)) if !success { return nil, errors.Errorf("tracking results of %d rounds: %d round "+ @@ -159,12 +160,13 @@ func (r Request) Respond(payload []byte, cmixParams cmix.CMIXParams, len(rounds), numRoundFail, numTimeOut) } - jww.DEBUG.Printf("Tracked %d single-use response message round(s).", len(roundMap)) + jww.DEBUG.Printf("Tracked %d single-use response message round(s).", + len(roundMap)) return rounds, nil } -// partitionResponse breaks a payload into its sub payloads for sending +// partitionResponse breaks a payload into its sub payloads for sending. func partitionResponse(payload []byte, cmixMessageLength int, maxParts uint8) []message.ResponsePart { responseMsg := message.NewResponsePart(cmixMessageLength) diff --git a/single/request.go b/single/request.go index cd8a5c04a27857730205bccdc7633238bf3264d0..0db4f433469e5e5a4b8b5358da8de139b8c3a130 100644 --- a/single/request.go +++ b/single/request.go @@ -41,33 +41,31 @@ func GetDefaultRequestParams() RequestParams { } } -// GetMaxRequestSize returns the max size of a request payload +// GetMaxRequestSize returns the max size of a request payload. func GetMaxRequestSize(net cmix.Client, e2eGrp *cyclic.Group) uint { payloadSize := message.GetRequestPayloadSize(net.GetMaxMessageLength(), e2eGrp.GetP().ByteLen()) return message.GetRequestContentsSize(payloadSize) } -/* Single is a system which allows for an end to end encrypted anonymous - request to be sent to another cmix client, and for them to respond. The - system allows for communication over the mixnet without an interactive - key negotiation because the payload inherently carries the negotiation with - it. When sending a new request, a client create a new discreet log Dh keypair - as well as a new ID. As a result of the fact that the client never - identifies itself, the system allows the client to stay anonymous while - contacting the remote. +/* Single is a system which allows for an end-to-end encrypted anonymous request + to be sent to another cMix client, and for them to respond. The system allows + for communication over the mixnet without an interactive key negotiation + because the payload inherently carries the negotiation with it. When sending + a new request, a client create a new discreet log DH keypair as well as a new + ID. As a result of the fact that the client never identifies itself, the + system allows the client to stay anonymous while contacting the remote. */ -// TransmitRequest Sends a request to the recipient with the given tag containing -// the given payload. The request is identified as coming from a new user ID and -// the recipient of the request responds to that address. As a result, this request -// does not reveal the identity of the sender, -// the current implementation only allows for a cing cmix request payload. +// TransmitRequest sends a request to the recipient with the given tag +// containing the given payload. The request is identified as coming from a new +// user ID and the recipient of the request responds to that address. As a +// result, this request does not reveal the identity of the sender. +// The current implementation only allows for a single cMix request payload. // Because the request payload itself must include negotiation materials, it is // limited to just a few thousand bits of payload, and will return an error if -// the payload is too large. GetMaxRequestSize() can be used to get this max -// size -// The network follower must be running and healthy to transmit +// the payload is too large. GetMaxRequestSize can be used to get this max size. +// The network follower must be running and healthy to transmit. func TransmitRequest(recipient contact.Contact, tag string, payload []byte, callback Response, param RequestParams, net cmix.Client, rng csprng.Source, e2eGrp *cyclic.Group) (id.Round, receptionID.EphemeralIdentity, error) { @@ -76,7 +74,7 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte, "send singe use when network is not healthy") } - // get address ID address space size; this blocks until the address space + // Get address ID address space size; this blocks until the address space // size is set for the first time addressSize := net.GetAddressSpace() timeStart := netTime.Now() @@ -87,18 +85,19 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte, return 0, receptionID.EphemeralIdentity{}, err } - //build the message payload - request := message.NewRequest(net.GetMaxMessageLength(), - e2eGrp.GetP().ByteLen()) - requestPayload := message.NewRequestPayload(request.GetPayloadSize(), - payload, param.MaxResponseMessages) + // Build the message payload + request := message.NewRequest( + net.GetMaxMessageLength(), e2eGrp.GetP().ByteLen()) + requestPayload := message.NewRequestPayload( + request.GetPayloadSize(), payload, param.MaxResponseMessages) // Generate new user ID and address ID var sendingID receptionID.EphemeralIdentity - requestPayload, sendingID, err = makeIDs(requestPayload, publicKey, addressSize, param.Timeout, - timeStart, rng) + requestPayload, sendingID, err = makeIDs( + requestPayload, publicKey, addressSize, param.Timeout, timeStart, rng) if err != nil { - return 0, receptionID.EphemeralIdentity{}, errors.Errorf("failed to generate IDs: %+v", err) + return 0, receptionID.EphemeralIdentity{}, + errors.Errorf("failed to generate IDs: %+v", err) } // Encrypt payload @@ -109,11 +108,11 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte, // Generate CMIX message MAC mac := singleUse.MakeMAC(key, encryptedPayload) - //assemble the payload + // Assemble the payload request.SetPubKey(publicKey) request.SetPayload(encryptedPayload) - //register the response pickup + // Register the response pickup collator := message.NewCollator(param.MaxResponseMessages) timeoutKillChan := make(chan bool) callbackOnce := sync.Once{} @@ -123,6 +122,7 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte, case timeoutKillChan <- true: default: } + callbackOnce.Do(func() { net.DeleteClientFingerprints(sendingID.Source) go callback.Callback(payload, receptionID, round, err) @@ -132,7 +132,7 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte, cyphers := makeCyphers(dhKey, param.MaxResponseMessages) for i := uint8(0); i < param.MaxResponseMessages; i++ { - processor := responceProcessor{ + processor := responseProcessor{ sendingID: sendingID, c: collator, callback: wrapper, @@ -141,8 +141,9 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte, recipient: &recipient, } - if err = net.AddFingerprint(sendingID.Source, processor.cy.GetFingerprint(), - &processor); err != nil { + err = net.AddFingerprint( + sendingID.Source, processor.cy.GetFingerprint(), &processor) + if err != nil { return 0, receptionID.EphemeralIdentity{}, errors.Errorf("failed to add fingerprint %d IDs: %+v", i, err) } @@ -150,7 +151,7 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte, net.AddIdentity(sendingID.Source, timeStart.Add(param.Timeout), false) - //send the payload + // Send the payload svc := cmixMsg.Service{ Identifier: recipient.ID[:], Tag: tag, @@ -158,8 +159,8 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte, } param.CmixParam.Timeout = param.Timeout - rid, _, err := net.Send(recipient.ID, cmixMsg.RandomFingerprint(rng), svc, request.Marshal(), mac, - param.CmixParam) + rid, _, err := net.Send(recipient.ID, cmixMsg.RandomFingerprint(rng), svc, + request.Marshal(), mac, param.CmixParam) if err != nil { return 0, receptionID.EphemeralIdentity{}, err @@ -175,8 +176,8 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte, func generateDhKeys(grp *cyclic.Group, dhPubKey *cyclic.Int, rng io.Reader) (*cyclic.Int, *cyclic.Int, error) { // Generate private key - privKeyBytes, err := csprng.GenerateInGroup(grp.GetP().Bytes(), - grp.GetP().ByteLen(), rng) + privKeyBytes, err := csprng.GenerateInGroup( + grp.GetP().Bytes(), grp.GetP().ByteLen(), rng) if err != nil { return nil, nil, errors.Errorf("failed to generate key in group: %+v", err) @@ -191,12 +192,12 @@ func generateDhKeys(grp *cyclic.Group, dhPubKey *cyclic.Int, // makeIDs generates a new user ID and address ID with a start and end within // the given timout. The ID is generated from the unencrypted msg payload, which -// contains a nonce. If the generated address ID has a window that is not -// within +/- the given 2*Timeout from now, then the IDs are generated again -// using a new nonce. +// contains a nonce. If the generated address ID has a window that is not within +// +/- the given 2*Timeout from now, then the IDs are generated again using a +// new nonce. func makeIDs(msg message.RequestPayload, publicKey *cyclic.Int, - addressSize uint8, timeout time.Duration, timeNow time.Time, - rng io.Reader) (message.RequestPayload, receptionID.EphemeralIdentity, error) { + addressSize uint8, timeout time.Duration, timeNow time.Time, rng io.Reader) ( + message.RequestPayload, receptionID.EphemeralIdentity, error) { var rid *id.ID var ephID ephemeral.Id @@ -217,19 +218,20 @@ func makeIDs(msg message.RequestPayload, publicKey *cyclic.Int, rid = msg.GetRID(publicKey) // Generate the address ID - ephID, start, end, err = ephemeral.GetId(rid, uint(addressSize), - timeNow.UnixNano()) + ephID, start, end, err = ephemeral.GetId( + rid, uint(addressSize), timeNow.UnixNano()) if err != nil { return message.RequestPayload{}, receptionID.EphemeralIdentity{}, - errors.Errorf("failed to generate "+ - "address ID from newly generated ID: %+v", err) + errors.Errorf("failed to generate address ID from newly "+ + "generated ID: %+v", err) } jww.DEBUG.Printf("address.GetId(%s, %d, %d) = %d", rid, addressSize, timeNow.UnixNano(), ephID.Int64()) } - jww.INFO.Printf("generated by singe use sender reception id for single use: %s, "+ - "ephId: %d, pubkey: %x, msg: %s", rid, ephID.Int64(), publicKey.Bytes(), msg) + jww.INFO.Printf("generated by singe use sender reception ID for single "+ + "use: %s, ephId: %d, pubkey: %x, msg: %s", + rid, ephID.Int64(), publicKey.Bytes(), msg) return msg, receptionID.EphemeralIdentity{ EphId: ephID, @@ -237,8 +239,8 @@ func makeIDs(msg message.RequestPayload, publicKey *cyclic.Int, }, nil } -// waitForTimeout is a long running thread which handles timing out a request. -// It can be canceled by channel +// waitForTimeout is a long-running thread which handles timing out a request. +// It can be canceled by channel. func waitForTimeout(kill chan bool, callback callbackWrapper, timeout time.Duration) { timer := time.NewTimer(timeout) select { diff --git a/single/responseProcessor.go b/single/responseProcessor.go index 7fca2e88bbcc979be0c8c9753f720cb5ad938ccd..33b02298df7a82c55a5446208db5b26c2b2460b4 100644 --- a/single/responseProcessor.go +++ b/single/responseProcessor.go @@ -12,9 +12,9 @@ import ( type callbackWrapper func(payload []byte, receptionID receptionID.EphemeralIdentity, round rounds.Round, err error) -// responceProcessor Message.Processor interface registered with cmix.Client. -// One is registered for each potential fingerprint. -type responceProcessor struct { +// responseProcessor is registered for each potential fingerprint. Adheres to +// the message.Processor interface registered with cmix.Client +type responseProcessor struct { sendingID receptionID.EphemeralIdentity c *message.Collator callback callbackWrapper @@ -25,7 +25,7 @@ type responceProcessor struct { // Process decrypts a response part and adds it to the collator - returning // a full response to the callback when all parts are received. -func (rsp *responceProcessor) Process(ecrMsg format.Message, +func (rsp *responseProcessor) Process(ecrMsg format.Message, receptionID receptionID.EphemeralIdentity, round rounds.Round) {