diff --git a/fileTransfer/fileMessage.go b/fileTransfer/fileMessage.go deleted file mode 100644 index b73b948c90cc4d99bad2d459be6a8f98df61f2a5..0000000000000000000000000000000000000000 --- a/fileTransfer/fileMessage.go +++ /dev/null @@ -1,130 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 xx network SEZC // -// // -// Use of this source code is governed by a license that can be found in the // -// LICENSE file // -/////////////////////////////////////////////////////////////////////////////// - -package fileTransfer - -import ( - "encoding/binary" - "github.com/pkg/errors" - ftCrypto "gitlab.com/elixxir/crypto/fileTransfer" -) - -// Size constants. -const ( - paddingLen = ftCrypto.NonceSize // The length of the padding in bytes - partNumLen = 2 // The length of the part number in bytes - fmMinSize = partNumLen + paddingLen // Minimum size for the partMessage -) - -// Error messages. -const ( - newFmSizeErr = "size of external payload (%d) must be greater than %d" - unmarshalFmSizeErr = "size of passed in bytes (%d) must be greater than %d" - setFileFmErr = "length of part bytes (%d) must be smaller than maximum payload size %d" -) - -/* -+-----------------------------------------+ -| CMIX Message Contents | -+---------+-------------+-----------------+ -| Padding | Part Number | File Data | -| 8 bytes | 2 bytes | remaining space | -+---------+-------------+-----------------+ -*/ - -// partMessage contains part of the data being transferred and 256-bit padding -// that is used as a nonce. -type partMessage struct { - data []byte // Serial of all contents - padding []byte // Random padding bytes - partNum []byte // The part number of the file - part []byte // File part data -} - -// newPartMessage generates a new part message that fits into the specified -// external payload size. An error is returned if the external payload size is -// too small to fit the part message. -func newPartMessage(externalPayloadSize int) (partMessage, error) { - if externalPayloadSize < fmMinSize { - return partMessage{}, - errors.Errorf(newFmSizeErr, externalPayloadSize, fmMinSize) - } - - return mapPartMessage(make([]byte, externalPayloadSize)), nil -} - -// mapPartMessage maps the data to the components of a partMessage. It is mapped -// by reference; a copy is not made. -func mapPartMessage(data []byte) partMessage { - return partMessage{ - data: data, - padding: data[:paddingLen], - partNum: data[paddingLen : paddingLen+partNumLen], - part: data[paddingLen+partNumLen:], - } -} - -// unmarshalPartMessage converts the bytes into a partMessage. An error is -// returned if the size of the data is too small for a partMessage. -func unmarshalPartMessage(b []byte) (partMessage, error) { - if len(b) < fmMinSize { - return partMessage{}, - errors.Errorf(unmarshalFmSizeErr, len(b), fmMinSize) - } - - return mapPartMessage(b), nil -} - -// marshal returns the byte representation of the partMessage. -func (m partMessage) marshal() []byte { - return m.data -} - -// getPadding returns the padding in the message. -func (m partMessage) getPadding() []byte { - return m.padding -} - -// setPadding sets the partMessage padding to the given bytes. Note that this -// padding should be random bytes generated via the appropriate crypto function. -func (m partMessage) setPadding(b []byte) { - copy(m.padding, b) -} - -// getPartNum returns the file part number. -func (m partMessage) getPartNum() uint16 { - return binary.LittleEndian.Uint16(m.partNum) -} - -// setPartNum sets the file part number. -func (m partMessage) setPartNum(num uint16) { - b := make([]byte, partNumLen) - binary.LittleEndian.PutUint16(b, num) - copy(m.partNum, b) -} - -// getPart returns the file part data from the message. -func (m partMessage) getPart() []byte { - return m.part -} - -// setPart sets the partMessage part to the given bytes. An error is returned if -// the size of the provided part data is too large to store. -func (m partMessage) setPart(b []byte) error { - if len(b) > len(m.part) { - return errors.Errorf(setFileFmErr, len(b), len(m.part)) - } - - copy(m.part, b) - - return nil -} - -// getPartSize returns the number of bytes available to store part data. -func (m partMessage) getPartSize() int { - return len(m.part) -} diff --git a/fileTransfer/manager_test.go b/fileTransfer/manager_test.go index c1133aa32a8f0f0e2fa09139678cdfd224e44fa2..2d6c1fc119653fd3371c345648f23f3c6409bd20 100644 --- a/fileTransfer/manager_test.go +++ b/fileTransfer/manager_test.go @@ -388,7 +388,6 @@ func TestManager_Resend_NoFingerprints(t *testing.T) { func TestManager_CloseSend_NoFingerprints(t *testing.T) { m, sti, _ := newTestManagerWithTransfers( []uint16{16}, false, false, nil, nil, nil, t) - prng := NewPrng(42) partSize, _ := m.getPartSize() // Use up all the fingerprints in the transfer diff --git a/fileTransfer/receive.go b/fileTransfer/receive.go index 9a70f5853212bae431653c096d9168d567008b2a..3552fdf5635a819f66cbecfb9945ca01ab529846 100644 --- a/fileTransfer/receive.go +++ b/fileTransfer/receive.go @@ -8,7 +8,6 @@ package fileTransfer import ( - "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/interfaces/message" "gitlab.com/elixxir/client/stoppable" @@ -64,16 +63,8 @@ func (m *Manager) readMessage(msg message.Receive) (format.Message, error) { return cMixMsg, err } - // Unmarshal cMix message contents into a file part message - partMsg, err := unmarshalPartMessage(cMixMsg.GetContents()) - if err != nil { - return cMixMsg, errors.Errorf(unmarshalPartMessageErr, err) - } - // Add part to received transfer - rt, tid, completed, err := m.received.AddPart(partMsg.getPart(), - partMsg.getPadding(), cMixMsg.GetMac(), partMsg.getPartNum(), - cMixMsg.GetKeyFP()) + rt, tid, completed, err := m.received.AddPart(cMixMsg) if err != nil { return cMixMsg, err } diff --git a/fileTransfer/receiveNew_test.go b/fileTransfer/receiveNew_test.go index 872012beee4ed019a035212c85f45a16ea7a1926..4aea311faa6e0fedadf6f627e8f4b43eb544753e 100644 --- a/fileTransfer/receiveNew_test.go +++ b/fileTransfer/receiveNew_test.go @@ -51,7 +51,7 @@ func TestManager_receiveNewFileTransfer(t *testing.T) { } marshalledMsg, err := proto.Marshal(protoMsg) if err != nil { - t.Errorf("Failed to marshal proto message: %+v", err) + t.Errorf("Failed to Marshal proto message: %+v", err) } receiveMsg := message.Receive{ Payload: marshalledMsg, @@ -120,7 +120,7 @@ func TestManager_receiveNewFileTransfer_Stop(t *testing.T) { } marshalledMsg, err := proto.Marshal(protoMsg) if err != nil { - t.Errorf("Failed to marshal proto message: %+v", err) + t.Errorf("Failed to Marshal proto message: %+v", err) } receiveMsg := message.Receive{ Payload: marshalledMsg, diff --git a/fileTransfer/send.go b/fileTransfer/send.go index d954811cd8495906b8c5519f8d07911f54113240..daeca373c1cba813f000840f39f747049db6262d 100644 --- a/fileTransfer/send.go +++ b/fileTransfer/send.go @@ -364,30 +364,14 @@ func (m *Manager) newCmixMessage(transfer *ftStorage.SentTransfer, // Create new empty cMix message cmixMsg := format.NewMessage(m.store.Cmix().GetGroup().GetP().ByteLen()) - // Create new empty file part message of size equal to the available payload - // size in the cMix message - partMsg, err := newPartMessage(cmixMsg.ContentsSize()) - if err != nil { - return cmixMsg, err - } - - // Get encrypted file part, file part MAC, padding (nonce), and fingerprint - encPart, mac, padding, fp, err := transfer.GetEncryptedPart( - partNum, partMsg.getPartSize(), rng) - if err != nil { - return cmixMsg, err - } - - // Construct file part message from padding ( - partMsg.setPadding(padding) - partMsg.setPartNum(partNum) - err = partMsg.setPart(encPart) + // Get encrypted file part, file part MAC, nonce (nonce), and fingerprint + encPart, mac, fp, err := transfer.GetEncryptedPart(partNum, cmixMsg.ContentsSize()) if err != nil { - return cmixMsg, err + return format.Message{}, err } // Construct cMix message - cmixMsg.SetContents(partMsg.marshal()) + cmixMsg.SetContents(encPart) cmixMsg.SetKeyFP(fp) cmixMsg.SetMac(mac) @@ -566,12 +550,12 @@ func (m *Manager) getPartSize() (int, error) { // Create new empty file part message of size equal to the available payload // size in the cMix message - partMsg, err := newPartMessage(cmixMsg.ContentsSize()) + partMsg, err := ftStorage.NewPartMessage(cmixMsg.ContentsSize()) if err != nil { return 0, err } - return partMsg.getPartSize(), nil + return partMsg.GetPartSize(), nil } // partitionFile splits the file into parts of the specified part size. diff --git a/fileTransfer/send_test.go b/fileTransfer/send_test.go index ee10658b1fe6c190cbaa9a04879c72829a726787..29a0e0853e26db79e0042a7f0296cb2a39ea439a 100644 --- a/fileTransfer/send_test.go +++ b/fileTransfer/send_test.go @@ -662,13 +662,13 @@ func TestManager_newCmixMessage(t *testing.T) { "\nexpected: %s\nrecieved: %s", fp, cmixMsg.GetKeyFP()) } - partMsg, err := unmarshalPartMessage(cmixMsg.GetContents()) + partMsg, err := ftStorage.UnmarshalPartMessage(cmixMsg.GetContents()) if err != nil { t.Errorf("Failed to unmarshal part message: %+v", err) } - decrPart, err := ftCrypto.DecryptPart(key, partMsg.getPart(), - partMsg.getPadding(), cmixMsg.GetMac(), partMsg.getPartNum()) + decrPart, err := ftCrypto.DecryptPart(key, partMsg.GetPart(), + partMsg.getNonce(), cmixMsg.GetMac(), partMsg.GetPartNum()) if err != nil { t.Errorf("Failed to decrypt file part: %+v", err) } @@ -998,7 +998,7 @@ func Test_makeListOfPartNums(t *testing.T) { } } -// Tests that the part size returned by Manager.getPartSize matches the manually +// Tests that the part size returned by Manager.GetPartSize matches the manually // calculated part size. func TestManager_getPartSize(t *testing.T) { m := newTestManager(false, nil, nil, nil, nil, t) @@ -1006,13 +1006,13 @@ func TestManager_getPartSize(t *testing.T) { // Calculate the expected part size primeByteLen := m.store.Cmix().GetGroup().GetP().ByteLen() cmixMsgUsedLen := format.AssociatedDataSize - filePartMsgUsedLen := fmMinSize + filePartMsgUsedLen := ftStorage.fmMinSize expected := 2*primeByteLen - cmixMsgUsedLen - filePartMsgUsedLen-1 // Get the part size partSize, err := m.getPartSize() if err != nil { - t.Errorf("getPartSize returned an error: %+v", err) + t.Errorf("GetPartSize returned an error: %+v", err) } if expected != partSize { diff --git a/go.mod b/go.mod index a0f5409a9057faaac33ef1c6855c1c256b1269b0..d66dd9d3ef9b9b602c4470501c236dee00fa4160 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/spf13/viper v1.7.1 gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228 gitlab.com/elixxir/comms v0.0.4-0.20220104174855-044783c5c1e6 - gitlab.com/elixxir/crypto v0.0.7-0.20220104174238-dbd761b30553 + gitlab.com/elixxir/crypto v0.0.7-0.20220108004933-8da1344a8e69 gitlab.com/elixxir/ekv v0.1.6 gitlab.com/elixxir/primitives v0.0.3-0.20220104173924-275cb9d7834f gitlab.com/xx_network/comms v0.0.4-0.20211227194445-c099754b3cda diff --git a/go.sum b/go.sum index 2b6c2766a664eb94c9e04c459af8aa099c8cdd77..52d03aac87a21e29aa6d58d5db4da1e7713a1046 100644 --- a/go.sum +++ b/go.sum @@ -277,6 +277,8 @@ gitlab.com/elixxir/crypto v0.0.3/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp0 gitlab.com/elixxir/crypto v0.0.7-0.20211230230452-bca020488964/go.mod h1:fexaw14nwGMlT6vL9eIJ1ixgiomyAp88hSHl0Yx0/xU= gitlab.com/elixxir/crypto v0.0.7-0.20220104174238-dbd761b30553 h1:BPwepGZspxgiY4QMUwVFMgVIEs8ziuMcT/uXmPQQ9Gs= gitlab.com/elixxir/crypto v0.0.7-0.20220104174238-dbd761b30553/go.mod h1:fexaw14nwGMlT6vL9eIJ1ixgiomyAp88hSHl0Yx0/xU= +gitlab.com/elixxir/crypto v0.0.7-0.20220108004933-8da1344a8e69 h1:MweUKTjmKvTxWswRhgAyV5cGZubqzlLQ+thdOpUPG+c= +gitlab.com/elixxir/crypto v0.0.7-0.20220108004933-8da1344a8e69/go.mod h1:qmW0OGPB21GcaGg1Jvt527/qUw7ke6W8DKCiYBfsx48= gitlab.com/elixxir/ekv v0.1.5 h1:R8M1PA5zRU1HVnTyrtwybdABh7gUJSCvt1JZwUSeTzk= gitlab.com/elixxir/ekv v0.1.5/go.mod h1:e6WPUt97taFZe5PFLPb1Dupk7tqmDCTQu1kkstqJvw4= gitlab.com/elixxir/ekv v0.1.6 h1:M2hUSNhH/ChxDd+s8xBqSEKgoPtmE6hOEBqQ73KbN6A= diff --git a/keyExchange/confirm.go b/keyExchange/confirm.go index d754acc1da040efed8e55227d623c0cc5c414342..4c21f77db86638f24a50fcf65b65001e71e081c9 100644 --- a/keyExchange/confirm.go +++ b/keyExchange/confirm.go @@ -61,7 +61,7 @@ func handleConfirm(sess *storage.Session, confirmation message.Receive) { confirmedSession := partner.GetSendSession(confimedSessionID) if confirmedSession == nil { jww.ERROR.Printf("[REKEY] Failed to find confirmed session %s from "+ - "partner %s: %s", confimedSessionID, confirmation.Sender, err) + "partner %s", confimedSessionID, confirmation.Sender) return } diff --git a/storage/fileTransfer/fileMessage.go b/storage/fileTransfer/fileMessage.go new file mode 100644 index 0000000000000000000000000000000000000000..6718bcfd8d41a204fb784a98e4951462f8d88485 --- /dev/null +++ b/storage/fileTransfer/fileMessage.go @@ -0,0 +1,119 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +/////////////////////////////////////////////////////////////////////////////// + +package fileTransfer + +import ( + "encoding/binary" + "github.com/pkg/errors" +) + +// Size constants. +const ( + partNumLen = 2 // The length of the part number in bytes + fmMinSize = partNumLen // Minimum size for the PartMessage +) + +// Error messages. +const ( + newFmSizeErr = "size of external payload (%d) must be greater than %d" + unmarshalFmSizeErr = "size of passed in bytes (%d) must be greater than %d" + setFileFmErr = "length of part bytes (%d) must be smaller than maximum payload size %d" +) + +/* ++-----------------------------------------+ +| CMIX Message Contents | ++---------+-------------+-----------------+ +| Padding | Part Number | File Data | +| 8 bytes | 2 bytes | remaining space | ++---------+-------------+-----------------+ +*/ + +// PartMessage contains part of the data being transferred and 256-bit nonce +// that is used as a nonce. +type PartMessage struct { + data []byte // Serial of all contents + partNum []byte // The part number of the file + part []byte // File part data +} + +// NewPartMessage generates a new part message that fits into the specified +// external payload size. An error is returned if the external payload size is +// too small to fit the part message. +func NewPartMessage(externalPayloadSize int) (PartMessage, error) { + if externalPayloadSize < fmMinSize { + return PartMessage{}, + errors.Errorf(newFmSizeErr, externalPayloadSize, fmMinSize) + } + + return MapPartMessage(make([]byte, externalPayloadSize)), nil +} + +// MapPartMessage maps the data to the components of a PartMessage. It is mapped +// by reference; a copy is not made. +func MapPartMessage(data []byte) PartMessage { + return PartMessage{ + data: data, + partNum: data[:partNumLen], + part: data[partNumLen:], + } +} + +// UnmarshalPartMessage converts the bytes into a PartMessage. An error is +// returned if the size of the data is too small for a PartMessage. +func UnmarshalPartMessage(b []byte) (PartMessage, error) { + if len(b) < fmMinSize { + return PartMessage{}, + errors.Errorf(unmarshalFmSizeErr, len(b), fmMinSize) + } + + return MapPartMessage(b), nil +} + +// Marshal returns the byte representation of the PartMessage. +func (m PartMessage) Marshal() []byte { + b := make([]byte, len(m.data)) + copy(b,m.data) + return b +} + +// GetPartNum returns the file part number. +func (m PartMessage) GetPartNum() uint16 { + return binary.LittleEndian.Uint16(m.partNum) +} + +// SetPartNum sets the file part number. +func (m PartMessage) SetPartNum(num uint16) { + b := make([]byte, partNumLen) + binary.LittleEndian.PutUint16(b, num) + copy(m.partNum, b) +} + +// GetPart returns the file part data from the message. +func (m PartMessage) GetPart() []byte { + b := make([]byte, len(m.part)) + copy(b,m.part) + return b +} + +// SetPart sets the PartMessage part to the given bytes. An error is returned if +// the size of the provided part data is too large to store. +func (m PartMessage) SetPart(b []byte) error { + if len(b) > len(m.part) { + return errors.Errorf(setFileFmErr, len(b), len(m.part)) + } + + copy(m.part, b) + + return nil +} + +// GetPartSize returns the number of bytes available to store part data. +func (m PartMessage) GetPartSize() int { + return len(m.part) +} diff --git a/fileTransfer/fileMessage_test.go b/storage/fileTransfer/fileMessage_test.go similarity index 50% rename from fileTransfer/fileMessage_test.go rename to storage/fileTransfer/fileMessage_test.go index 77b72eac9fa78a04d6c4c36aceda9a0effbd8a3e..498e7568f47848c8c01b357676ac8346c7425be3 100644 --- a/fileTransfer/fileMessage_test.go +++ b/storage/fileTransfer/fileMessage_test.go @@ -15,54 +15,49 @@ import ( "testing" ) -// Tests that newPartMessage returns a partMessage of the expected size. +// Tests that NewPartMessage returns a PartMessage of the expected size. func Test_newPartMessage(t *testing.T) { externalPayloadSize := 256 - fm, err := newPartMessage(externalPayloadSize) + fm, err := NewPartMessage(externalPayloadSize) if err != nil { - t.Errorf("newPartMessage returned an error: %+v", err) + t.Errorf("NewPartMessage returned an error: %+v", err) } if len(fm.data) != externalPayloadSize { - t.Errorf("Size of partMessage data does not match payload size."+ + t.Errorf("Size of PartMessage data does not match payload size."+ "\nexpected: %d\nreceived: %d", externalPayloadSize, len(fm.data)) } } -// Error path: tests that newPartMessage returns the expected error when the +// Error path: tests that NewPartMessage returns the expected error when the // external payload size is too small. func Test_newPartMessage_SmallPayloadSizeError(t *testing.T) { externalPayloadSize := fmMinSize - 1 expectedErr := fmt.Sprintf(newFmSizeErr, externalPayloadSize, fmMinSize) - _, err := newPartMessage(externalPayloadSize) + _, err := NewPartMessage(externalPayloadSize) if err == nil || err.Error() != expectedErr { - t.Errorf("newPartMessage did not return the expected error when the "+ + t.Errorf("NewPartMessage did not return the expected error when the "+ "given external payload size is too small."+ "\nexpected: %s\nreceived: %+v", expectedErr, err) } } -// Tests that mapPartMessage maps the data to the correct parts of the -// partMessage. +// Tests that MapPartMessage maps the data to the correct parts of the +// PartMessage. func Test_mapPartMessage(t *testing.T) { // Generate expected values - _, expectedData, expectedPadding, expectedPartNum, expectedFile := + _, expectedData, expectedPartNum, expectedFile := newRandomFileMessage() - fm := mapPartMessage(expectedData) + fm := MapPartMessage(expectedData) if !bytes.Equal(expectedData, fm.data) { t.Errorf("Incorrect data.\nexpected: %q\nreceived: %q", expectedData, fm.data) } - if !bytes.Equal(expectedPadding, fm.padding) { - t.Errorf("Incorrect padding data.\nexpected: %q\nreceived: %q", - expectedPadding, fm.padding) - } - if !bytes.Equal(expectedPartNum, fm.partNum) { t.Errorf("Incorrect part number.\nexpected: %q\nreceived: %q", expectedPartNum, fm.partNum) @@ -75,16 +70,16 @@ func Test_mapPartMessage(t *testing.T) { } -// Tests that unmarshalPartMessage returns a partMessage with the expected +// Tests that UnmarshalPartMessage returns a PartMessage with the expected // values. func Test_unmarshalPartMessage(t *testing.T) { // Generate expected values - _, expectedData, expectedPadding, expectedPartNumb, expectedFile := + _, expectedData, expectedPartNumb, expectedFile := newRandomFileMessage() - fm, err := unmarshalPartMessage(expectedData) + fm, err := UnmarshalPartMessage(expectedData) if err != nil { - t.Errorf("unmarshalPartMessage return an error: %+v", err) + t.Errorf("UnmarshalPartMessage return an error: %+v", err) } if !bytes.Equal(expectedData, fm.data) { @@ -92,11 +87,6 @@ func Test_unmarshalPartMessage(t *testing.T) { expectedData, fm.data) } - if !bytes.Equal(expectedPadding, fm.padding) { - t.Errorf("Incorrect padding data.\nexpected: %q\nreceived: %q", - expectedPadding, fm.padding) - } - if !bytes.Equal(expectedPartNumb, fm.partNum) { t.Errorf("Incorrect part number.\nexpected: %q\nreceived: %q", expectedPartNumb, fm.partNum) @@ -108,25 +98,25 @@ func Test_unmarshalPartMessage(t *testing.T) { } } -// Error path: tests that unmarshalPartMessage returns the expected error when -// the provided data is too small to be unmarshalled into a partMessage. +// Error path: tests that UnmarshalPartMessage returns the expected error when +// the provided data is too small to be unmarshalled into a PartMessage. func Test_unmarshalPartMessage_SizeError(t *testing.T) { data := make([]byte, fmMinSize-1) expectedErr := fmt.Sprintf(unmarshalFmSizeErr, len(data), fmMinSize) - _, err := unmarshalPartMessage(data) + _, err := UnmarshalPartMessage(data) if err == nil || err.Error() != expectedErr { - t.Errorf("unmarshalPartMessage did not return the expected error when "+ - "the given bytes are too small to be a partMessage."+ + t.Errorf("UnmarshalPartMessage did not return the expected error when "+ + "the given bytes are too small to be a PartMessage."+ "\nexpected: %s\nreceived: %+v", expectedErr, err) } } -// Tests that partMessage.marshal returns the correct data. +// Tests that PartMessage.Marshal returns the correct data. func Test_fileMessage_marshal(t *testing.T) { - fm, expectedData, _, _, _ := newRandomFileMessage() + fm, expectedData, _, _ := newRandomFileMessage() - data := fm.marshal() + data := fm.Marshal() if !bytes.Equal(expectedData, data) { t.Errorf("Marshalled data does not match expected."+ @@ -134,41 +124,11 @@ func Test_fileMessage_marshal(t *testing.T) { } } -// Tests that partMessage.getPadding returns the correct padding data. -func Test_fileMessage_getPadding(t *testing.T) { - fm, _, expectedPadding, _, _ := newRandomFileMessage() - - padding := fm.getPadding() - - if !bytes.Equal(expectedPadding, padding) { - t.Errorf("Padding data does not match expected."+ - "\nexpected: %q\nreceived: %q", expectedPadding, padding) - } -} - -// Tests that partMessage.setPadding sets the correct data. -func Test_fileMessage_setPadding(t *testing.T) { - fm, err := newPartMessage(256) - if err != nil { - t.Errorf("Failed to create new partMessage: %+v", err) - } - - expectedPadding := make([]byte, paddingLen) - rand.New(rand.NewSource(42)).Read(expectedPadding) - - fm.setPadding(expectedPadding) - - if !bytes.Equal(expectedPadding, fm.getPadding()) { - t.Errorf("Failed to set correct padding.\nexpected: %q\nreceived: %q", - expectedPadding, fm.getPadding()) - } -} - -// Tests that partMessage.getPartNum returns the correct part number. +// Tests that PartMessage.GetPartNum returns the correct part number. func Test_fileMessage_getPartNum(t *testing.T) { - fm, _, _, expectedPartNum, _ := newRandomFileMessage() + fm, _, expectedPartNum, _ := newRandomFileMessage() - partNum := fm.getPartNum() + partNum := fm.GetPartNum() expected := binary.LittleEndian.Uint16(expectedPartNum) if expected != partNum { @@ -177,30 +137,30 @@ func Test_fileMessage_getPartNum(t *testing.T) { } } -// Tests that partMessage.setPartNum sets the correct part number. +// Tests that PartMessage.SetPartNum sets the correct part number. func Test_fileMessage_setPartNum(t *testing.T) { - fm, err := newPartMessage(256) + fm, err := NewPartMessage(256) if err != nil { - t.Errorf("Failed to create new partMessage: %+v", err) + t.Errorf("Failed to create new PartMessage: %+v", err) } expectedPartNum := make([]byte, partNumLen) rand.New(rand.NewSource(42)).Read(expectedPartNum) expected := binary.LittleEndian.Uint16(expectedPartNum) - fm.setPartNum(expected) + fm.SetPartNum(expected) - if expected != fm.getPartNum() { + if expected != fm.GetPartNum() { t.Errorf("Failed to set correct part number.\nexpected: %d\nreceived: %d", - expected, fm.getPartNum()) + expected, fm.GetPartNum()) } } -// Tests that partMessage.getPart returns the correct part data. +// Tests that PartMessage.GetPart returns the correct part data. func Test_fileMessage_getFile(t *testing.T) { - fm, _, _, _, expectedFile := newRandomFileMessage() + fm, _, _, expectedFile := newRandomFileMessage() - file := fm.getPart() + file := fm.GetPart() if !bytes.Equal(expectedFile, file) { t.Errorf("File data does not match expected."+ @@ -208,76 +168,74 @@ func Test_fileMessage_getFile(t *testing.T) { } } -// Tests that partMessage.setPart sets the correct part data. +// Tests that PartMessage.SetPart sets the correct part data. func Test_fileMessage_setFile(t *testing.T) { - fm, err := newPartMessage(256) + fm, err := NewPartMessage(256) if err != nil { - t.Errorf("Failed to create new partMessage: %+v", err) + t.Errorf("Failed to create new PartMessage: %+v", err) } fileData := make([]byte, 64) rand.New(rand.NewSource(42)).Read(fileData) - expectedFile := make([]byte, fm.getPartSize()) + expectedFile := make([]byte, fm.GetPartSize()) copy(expectedFile, fileData) - err = fm.setPart(expectedFile) + err = fm.SetPart(expectedFile) if err != nil { - t.Errorf("setPart returned an error: %+v", err) + t.Errorf("SetPart returned an error: %+v", err) } - if !bytes.Equal(expectedFile, fm.getPart()) { + if !bytes.Equal(expectedFile, fm.GetPart()) { t.Errorf("Failed to set correct part data.\nexpected: %q\nreceived: %q", - expectedFile, fm.getPart()) + expectedFile, fm.GetPart()) } } -// Error path: tests that partMessage.setPart returns the expected error when +// Error path: tests that PartMessage.SetPart returns the expected error when // the provided part data is too large for the message. func Test_fileMessage_setFile_FileTooLargeError(t *testing.T) { - fm, err := newPartMessage(fmMinSize + 1) + fm, err := NewPartMessage(fmMinSize + 1) if err != nil { - t.Errorf("Failed to create new partMessage: %+v", err) + t.Errorf("Failed to create new PartMessage: %+v", err) } - expectedErr := fmt.Sprintf(setFileFmErr, fm.getPartSize()+1, fm.getPartSize()) + expectedErr := fmt.Sprintf(setFileFmErr, fm.GetPartSize()+1, fm.GetPartSize()) - err = fm.setPart(make([]byte, fm.getPartSize()+1)) + err = fm.SetPart(make([]byte, fm.GetPartSize()+1)) if err == nil || err.Error() != expectedErr { - t.Errorf("setPart did not return the expected error when the given "+ - "part data is too large to fit in the partMessage."+ + t.Errorf("SetPart did not return the expected error when the given "+ + "part data is too large to fit in the PartMessage."+ "\nexpected: %s\nreceived: %+v", expectedErr, err) } } -// Tests that partMessage.getPartSize returns the expected available space for +// Tests that PartMessage.GetPartSize returns the expected available space for // the part data. func Test_fileMessage_getFileSize(t *testing.T) { expectedSize := 256 - fm, err := newPartMessage(fmMinSize + expectedSize) + fm, err := NewPartMessage(fmMinSize + expectedSize) if err != nil { - t.Errorf("Failed to create new partMessage: %+v", err) + t.Errorf("Failed to create new PartMessage: %+v", err) } - if expectedSize != fm.getPartSize() { + if expectedSize != fm.GetPartSize() { t.Errorf("File size incorrect.\nexpected: %d\nreceived: %d", - expectedSize, fm.getPartSize()) + expectedSize, fm.GetPartSize()) } } -// newRandomFileMessage generates a new partMessage filled with random data and -// return the partMessage and its individual parts. -func newRandomFileMessage() (partMessage, []byte, []byte, []byte, []byte) { +// newRandomFileMessage generates a new PartMessage filled with random data and +// return the PartMessage and its individual parts. +func newRandomFileMessage() (PartMessage, []byte, []byte, []byte) { prng := rand.New(rand.NewSource(42)) - padding := make([]byte, paddingLen) - prng.Read(padding) partNum := make([]byte, partNumLen) prng.Read(partNum) part := make([]byte, 64) prng.Read(part) - data := append(append(padding, partNum...), part...) + data := append(partNum, part...) - fm := mapPartMessage(data) + fm := MapPartMessage(data) - return fm, data, padding, partNum, part + return fm, data, partNum, part } diff --git a/storage/fileTransfer/receiveFileTransfers.go b/storage/fileTransfer/receiveFileTransfers.go index ac9f262e6b2f6920fad1cf17a0453e3f89ace8c2..a504676a604ab30e2ba30b34992cbf6778e70dc8 100644 --- a/storage/fileTransfer/receiveFileTransfers.go +++ b/storage/fileTransfer/receiveFileTransfers.go @@ -176,17 +176,18 @@ func (rft *ReceivedFileTransfersStore) DeleteTransfer(tid ftCrypto.TransferID) e // transfer that the part was added to so that a progress callback can be // called. Returns the transfer ID so that it can be used for logging. Also // returns of the transfer is complete after adding the part. -func (rft *ReceivedFileTransfersStore) AddPart(encryptedPart, padding, - mac []byte, partNum uint16, fp format.Fingerprint) (*ReceivedTransfer, +func (rft *ReceivedFileTransfersStore) AddPart(cmixMsg format.Message) (*ReceivedTransfer, ftCrypto.TransferID, bool, error) { rft.mux.Lock() defer rft.mux.Unlock() + keyfp := cmixMsg.GetKeyFP() + // Lookup the part info for the given fingerprint - info, exists := rft.info[fp] + info, exists := rft.info[cmixMsg.GetKeyFP()] if !exists { return nil, ftCrypto.TransferID{}, false, - errors.Errorf(noFingerprintErr, fp) + errors.Errorf(noFingerprintErr, keyfp) } // Lookup the transfer with the ID in the part info @@ -197,15 +198,14 @@ func (rft *ReceivedFileTransfersStore) AddPart(encryptedPart, padding, } // Add the part to the transfer - completed, err := transfer.AddPart( - encryptedPart, padding, mac, partNum, info.fpNum) + completed, err := transfer.AddPart(cmixMsg, info.fpNum) if err != nil { return transfer, info.id, false, errors.Errorf( - addPartErr, partNum, transfer.numParts, info.id, err) + addPartErr, transfer.numParts, info.id, err) } // Remove the part info from the map - delete(rft.info, fp) + delete(rft.info, keyfp) return transfer, info.id, completed, nil } diff --git a/storage/fileTransfer/receiveFileTransfers_test.go b/storage/fileTransfer/receiveFileTransfers_test.go index 0c048246023069538f20870b89a8a2dbb60d1d47..99f4a503df697e80342ff3b41611db9c90b5e5bd 100644 --- a/storage/fileTransfer/receiveFileTransfers_test.go +++ b/storage/fileTransfer/receiveFileTransfers_test.go @@ -391,9 +391,12 @@ func TestReceivedFileTransfersStore_AddPart_NoFingerprintError(t *testing.T) { // Create encrypted part fp := format.NewFingerprint([]byte("invalidTransferKey")) + msg := format.NewMessage(1000) + msg.SetKeyFP(fp) + // Add encrypted part expectedErr := fmt.Sprintf(noFingerprintErr, fp) - _, _, _, err = rft.AddPart([]byte{}, []byte{}, []byte{}, 0, fp) + _, _, _, err = rft.AddPart(msg) if err == nil || err.Error() != expectedErr { t.Errorf("AddPart did not return the expected error when no part for "+ "the fingerprint exists.\nexpected: %s\nreceived: %+v", @@ -425,9 +428,12 @@ func TestReceivedFileTransfersStore_AddPart_NoTransferError(t *testing.T) { invalidTid, _ := ftCrypto.NewTransferID(prng) rft.info[fp].id = invalidTid + msg := format.NewMessage(1000) + msg.SetKeyFP(fp) + // Add encrypted part expectedErr := fmt.Sprintf(getReceivedTransferErr, invalidTid) - _, _, _, err = rft.AddPart([]byte{}, []byte{}, []byte{}, 0, fp) + _, _, _, err = rft.AddPart(msg) if err == nil || err.Error() != expectedErr { t.Errorf("AddPart did not return the expected error when no transfer "+ "for the ID exists.\nexpected: %s\nreceived: %+v", expectedErr, err) diff --git a/storage/fileTransfer/receiveTransfer.go b/storage/fileTransfer/receiveTransfer.go index df4bad66163245c9593bfbbc949d73ccf04b5bc3..b3e387a750d4cb6ba398c28195add01ec5b5763e 100644 --- a/storage/fileTransfer/receiveTransfer.go +++ b/storage/fileTransfer/receiveTransfer.go @@ -16,6 +16,7 @@ import ( "gitlab.com/elixxir/client/storage/utility" "gitlab.com/elixxir/client/storage/versioned" ftCrypto "gitlab.com/elixxir/crypto/fileTransfer" + "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/netTime" "sync" "time" @@ -276,20 +277,25 @@ func (rt *ReceivedTransfer) AddProgressCB( // AddPart decrypts an encrypted file part, adds it to the list of received // parts and marks its fingerprint as used. Returns true if the part added was // the last in the transfer. -func (rt *ReceivedTransfer) AddPart(encryptedPart, padding, mac []byte, partNum, +func (rt *ReceivedTransfer) AddPart(cmixMsg format.Message, fpNum uint16) (bool, error) { rt.mux.Lock() defer rt.mux.Unlock() // Decrypt the encrypted file part - decryptedPart, err := ftCrypto.DecryptPart( - rt.key, encryptedPart, padding, mac, fpNum) + decryptedPart, err := ftCrypto.DecryptPart(rt.key, + cmixMsg.GetContents(), cmixMsg.GetMac(), fpNum, cmixMsg.GetKeyFP()) + if err != nil { + return false, err + } + + part, err := UnmarshalPartMessage(decryptedPart) if err != nil { return false, err } // Add the part to the list of parts - err = rt.receivedParts.addPart(decryptedPart, partNum) + err = rt.receivedParts.addPart(part.GetPart(), part.GetPartNum()) if err != nil { return false, err } @@ -298,7 +304,7 @@ func (rt *ReceivedTransfer) AddPart(encryptedPart, padding, mac []byte, partNum, rt.fpVector.Use(uint32(fpNum)) // Mark part as received - rt.receivedStatus.Use(uint32(partNum)) + rt.receivedStatus.Use(uint32(part.GetPartNum())) if rt.receivedStatus.GetNumUsed() >= uint32(rt.numParts) { return true, nil diff --git a/storage/fileTransfer/sentTransfer.go b/storage/fileTransfer/sentTransfer.go index 35b8a450f738d78c8aaef199d858d7e1f21abaf3..cdffaaeca6807c4025b9bf90925130e6be9cbcb5 100644 --- a/storage/fileTransfer/sentTransfer.go +++ b/storage/fileTransfer/sentTransfer.go @@ -17,7 +17,6 @@ import ( "gitlab.com/elixxir/client/storage/versioned" ftCrypto "gitlab.com/elixxir/crypto/fileTransfer" "gitlab.com/elixxir/primitives/format" - "gitlab.com/xx_network/crypto/csprng" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/netTime" "sync" @@ -427,31 +426,44 @@ func (st *SentTransfer) AddProgressCB(cb interfaces.SentProgressCallback, // GetEncryptedPart gets the specified part, encrypts it, and returns the // encrypted part along with its MAC, padding, and fingerprint. -func (st *SentTransfer) GetEncryptedPart(partNum uint16, partSize int, - rng csprng.Source) (encPart, mac, padding []byte, fp format.Fingerprint, - err error) { +func (st *SentTransfer) GetEncryptedPart(partNum uint16, contentsSize int) (encPart, mac []byte, + fp format.Fingerprint, err error) { st.mux.Lock() defer st.mux.Unlock() + // Create new empty file part message of size equal to the available payload + // size in the cMix message + partMsg, err := NewPartMessage(contentsSize) + if err != nil { + return nil, nil, format.Fingerprint{}, err + } + + partMsg.SetPartNum(partNum) + // Lookup part part, exists := st.sentParts.getPart(partNum) if !exists { - return nil, nil, nil, format.Fingerprint{}, + return nil, nil, format.Fingerprint{}, errors.Errorf(noPartNumErr, partNum) } + if err = partMsg.SetPart(part); err != nil{ + return nil, nil, format.Fingerprint{}, + err + } + // If all fingerprints have been used but parts still remain, then change // the status to stopping and return an error specifying that all the // retries have been used if st.fpVector.GetNumAvailable() < 1 { st.status = Stopping - return nil, nil, nil, format.Fingerprint{}, MaxRetriesErr + return nil, nil, format.Fingerprint{}, MaxRetriesErr } // Get next unused fingerprint number and mark it as used nextKey, err := st.fpVector.Next() if err != nil { - return nil, nil, nil, format.Fingerprint{}, + return nil, nil, format.Fingerprint{}, errors.Errorf(fingerprintErr, err) } fpNum := uint16(nextKey) @@ -460,16 +472,13 @@ func (st *SentTransfer) GetEncryptedPart(partNum uint16, partSize int, fp = ftCrypto.GenerateFingerprint(st.key, fpNum) // Encrypt the file part and generate the file part MAC and padding (nonce) - maxLengthPart := make([]byte, partSize) - copy(maxLengthPart, part) - encPart, mac, padding, err = ftCrypto.EncryptPart( - st.key, maxLengthPart, fpNum, rng) + encPart, mac, err = ftCrypto.EncryptPart(st.key, partMsg.Marshal(), fpNum, fp) if err != nil { - return nil, nil, nil, format.Fingerprint{}, + return nil, nil, format.Fingerprint{}, errors.Errorf(encryptPartErr, partNum, err) } - return encPart, mac, padding, fp, err + return encPart, mac, fp, err } // SetInProgress adds the specified file part numbers to the in-progress