diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 53b2621..da68a8f 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -294,7 +294,7 @@ func encryptFile(privateKey [32]byte, pubkeyList [][32]byte) bool { return false } - crypt4GHWriter, err := streaming.NewCrypt4GHWriter(outFile, privateKey, pubkeyList, nil) + crypt4GHWriter, err := streaming.NewCrypt4GHWriter(outFile, privateKey, pubkeyList, nil, nil) if err != nil { fmt.Println(aurora.Red(err)) diff --git a/model/headers/headers.go b/model/headers/headers.go index 3b80cd2..3b3eb03 100644 --- a/model/headers/headers.go +++ b/model/headers/headers.go @@ -59,6 +59,7 @@ type Header struct { Version uint32 HeaderPacketCount uint32 HeaderPackets []HeaderPacket + Nonces []*[chacha20poly1305.NonceSize]byte } type HeaderReaderError struct { @@ -199,7 +200,7 @@ func (h Header) GetDataEditListHeaderPacket() *DataEditListHeaderPacket { } // MarshalBinary implements method MarshalBinary.BinaryMarshaler. -func (h Header) MarshalBinary() (data []byte, err error) { +func (h *Header) MarshalBinary() (data []byte, err error) { buffer := bytes.Buffer{} err = binary.Write(&buffer, binary.LittleEndian, h.MagicNumber) if err != nil { @@ -214,10 +215,15 @@ func (h Header) MarshalBinary() (data []byte, err error) { return nil, err } for _, headerPacket := range h.HeaderPackets { + if h.Nonces != nil { + headerPacket.Nonce = h.Nonces[0] + h.Nonces = h.Nonces[1:] + } marshalledHeaderPacket, err := headerPacket.MarshalBinary() if err != nil { return nil, err } + h.Nonces = append(h.Nonces, headerPacket.Nonce) err = binary.Write(&buffer, binary.LittleEndian, marshalledHeaderPacket) if err != nil { return nil, err diff --git a/model/headers/headers_test.go b/model/headers/headers_test.go index e2d52fe..cec9bc8 100644 --- a/model/headers/headers_test.go +++ b/model/headers/headers_test.go @@ -109,7 +109,7 @@ func TestNewHeader(t *testing.T) { if err != nil { panic(err) } - if fmt.Sprintf("%v", header) != "&{[99 114 121 112 116 52 103 104] 1 2 [{[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 108 0 {65564 {0} 0 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]}} {[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 100 0 {{1} 3 [1 2 3]}}]}" { + if fmt.Sprintf("%v", header) != "&{[99 114 121 112 116 52 103 104] 1 2 [{[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 108 0 {65564 {0} 0 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]}} {[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 100 0 {{1} 3 [1 2 3]}}] []}" { t.Fail() } } @@ -294,7 +294,7 @@ func TestReEncryptedHeader(t *testing.T) { if err != nil { panic(err) } - if fmt.Sprintf("%v", header) != "&{[99 114 121 112 116 52 103 104] 1 1 [{[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 108 0 {65564 {0} 0 [58 52 140 253 170 28 13 219 92 105 115 137 71 195 249 252 122 199 180 1 92 81 30 102 15 185 66 179 83 189 234 57]}}]}" { + if fmt.Sprintf("%v", header) != "&{[99 114 121 112 116 52 103 104] 1 1 [{[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 108 0 {65564 {0} 0 [58 52 140 253 170 28 13 219 92 105 115 137 71 195 249 252 122 199 180 1 92 81 30 102 15 185 66 179 83 189 234 57]}}] []}" { t.Fail() } } diff --git a/streaming/out.go b/streaming/out.go index d72dd4e..c54680d 100644 --- a/streaming/out.go +++ b/streaming/out.go @@ -20,22 +20,41 @@ type Crypt4GHWriter struct { header headers.Header dataEncryptionParametersHeaderPacket headers.DataEncryptionParametersHeaderPacket buffer bytes.Buffer + Rands *WriterRands +} + +type WriterRands struct { + DataKey [chacha20poly1305.KeySize]byte + HeaderNonces []*[chacha20poly1305.NonceSize]byte + BodyNonces []*[chacha20poly1305.NonceSize]byte } // NewCrypt4GHWriter method constructs streaming.Crypt4GHWriter instance from io.Writer and corresponding keys. -func NewCrypt4GHWriter(writer io.Writer, writerPrivateKey [chacha20poly1305.KeySize]byte, readerPublicKeyList [][chacha20poly1305.KeySize]byte, dataEditList *headers.DataEditListHeaderPacket) (*Crypt4GHWriter, error) { +func NewCrypt4GHWriter( + writer io.Writer, + writerPrivateKey [chacha20poly1305.KeySize]byte, + readerPublicKeyList [][chacha20poly1305.KeySize]byte, + dataEditList *headers.DataEditListHeaderPacket, + rands *WriterRands, +) (*Crypt4GHWriter, error) { crypt4GHWriter := Crypt4GHWriter{} - var sharedKey [chacha20poly1305.KeySize]byte - _, err := rand.Read(sharedKey[:]) - if err != nil { - return nil, err + + if rands != nil { + crypt4GHWriter.Rands = rands + } else { + crypt4GHWriter.Rands = &WriterRands{} + _, err := rand.Read(crypt4GHWriter.Rands.DataKey[:]) + if err != nil { + return nil, err + } } + headerPackets := make([]headers.HeaderPacket, 0) crypt4GHWriter.dataEncryptionParametersHeaderPacket = headers.DataEncryptionParametersHeaderPacket{ EncryptedSegmentSize: chacha20poly1305.NonceSize + headers.UnencryptedDataSegmentSize + box.Overhead, PacketType: headers.PacketType{PacketType: headers.DataEncryptionParameters}, DataEncryptionMethod: headers.ChaCha20IETFPoly1305, - DataKey: sharedKey, + DataKey: crypt4GHWriter.Rands.DataKey, } for _, readerPublicKey := range readerPublicKeyList { @@ -61,11 +80,13 @@ func NewCrypt4GHWriter(writer io.Writer, writerPrivateKey [chacha20poly1305.KeyS Version: headers.Version, HeaderPacketCount: uint32(len(headerPackets)), HeaderPackets: headerPackets, + Nonces: crypt4GHWriter.Rands.HeaderNonces, } binaryHeader, err := crypt4GHWriter.header.MarshalBinary() if err != nil { return nil, err } + crypt4GHWriter.Rands.HeaderNonces = crypt4GHWriter.header.Nonces _, err = writer.Write(binaryHeader) if err != nil { return nil, err @@ -97,7 +118,7 @@ func ReCrypt4GHWriter(reader io.Reader, readerPrivateKey [chacha20poly1305.KeySi return out, nil } -// NewCrypt4GHWriter method constructs streaming.Crypt4GHWriter instance from io.Writer and reader's public key. +// NewCrypt4GHWriterWithoutPrivateKey method constructs streaming.Crypt4GHWriter instance from io.Writer and reader's public key. // Writer's public key is generated automatically. func NewCrypt4GHWriterWithoutPrivateKey(writer io.Writer, readerPublicKeyList [][chacha20poly1305.KeySize]byte, dataEditList *headers.DataEditListHeaderPacket) (*Crypt4GHWriter, error) { _, privateKey, err := keys.GenerateKeyPair() @@ -105,7 +126,7 @@ func NewCrypt4GHWriterWithoutPrivateKey(writer io.Writer, readerPublicKeyList [] return nil, err } - return NewCrypt4GHWriter(writer, privateKey, readerPublicKeyList, dataEditList) + return NewCrypt4GHWriter(writer, privateKey, readerPublicKeyList, dataEditList, nil) } // Write method implements io.Writer.Write. @@ -141,11 +162,16 @@ func (c *Crypt4GHWriter) flushBuffer() error { DataEncryptionParametersHeaderPackets: []headers.DataEncryptionParametersHeaderPacket{c.dataEncryptionParametersHeaderPacket}, UnencryptedData: c.buffer.Bytes(), } + if c.Rands.BodyNonces != nil { + segment.Nonce = c.Rands.BodyNonces[0] + c.Rands.BodyNonces = c.Rands.BodyNonces[1:] + } c.buffer.Reset() marshalledSegment, err := segment.MarshalBinary() if err != nil { return err } + c.Rands.BodyNonces = append(c.Rands.BodyNonces, segment.Nonce) _, err = c.writer.Write(marshalledSegment) if err != nil { return err diff --git a/streaming/streaming_test.go b/streaming/streaming_test.go index e28c890..02669f9 100644 --- a/streaming/streaming_test.go +++ b/streaming/streaming_test.go @@ -86,7 +86,7 @@ func TestReencryption(t *testing.T) { readerPublicKeyList := [][chacha20poly1305.KeySize]byte{} readerPublicKeyList = append(readerPublicKeyList, readerPublicKey) buffer := bytes.Buffer{} - writer, err := NewCrypt4GHWriter(&buffer, writerPrivateKey, readerPublicKeyList, nil) + writer, err := NewCrypt4GHWriter(&buffer, writerPrivateKey, readerPublicKeyList, nil, nil) if err != nil { t.Error(err) } @@ -166,7 +166,7 @@ func TestReencryptionWithDataEditListInCrypt4GHWriterNoDiscard(t *testing.T) { buffer := bytes.Buffer{} readerPublicKeyList := [][chacha20poly1305.KeySize]byte{} readerPublicKeyList = append(readerPublicKeyList, readerPublicKey) - writer, err := NewCrypt4GHWriter(&buffer, writerPrivateKey, readerPublicKeyList, &dataEditListHeaderPacket) + writer, err := NewCrypt4GHWriter(&buffer, writerPrivateKey, readerPublicKeyList, &dataEditListHeaderPacket, nil) if err != nil { t.Error(err) } @@ -223,7 +223,7 @@ func TestReencryptionWithDataEditListInCrypt4GHReaderNoDiscard(t *testing.T) { buffer := bytes.Buffer{} readerPublicKeyList := [][chacha20poly1305.KeySize]byte{} readerPublicKeyList = append(readerPublicKeyList, readerPublicKey) - writer, err := NewCrypt4GHWriter(&buffer, writerPrivateKey, readerPublicKeyList, nil) + writer, err := NewCrypt4GHWriter(&buffer, writerPrivateKey, readerPublicKeyList, nil, nil) if err != nil { t.Error(err) } @@ -287,7 +287,7 @@ func TestReencryptionWithDataEditListAndDiscard(t *testing.T) { buffer := bytes.Buffer{} readerPublicKeyList := [][chacha20poly1305.KeySize]byte{} readerPublicKeyList = append(readerPublicKeyList, readerPublicKey) - writer, err := NewCrypt4GHWriter(&buffer, writerPrivateKey, readerPublicKeyList, nil) + writer, err := NewCrypt4GHWriter(&buffer, writerPrivateKey, readerPublicKeyList, nil, nil) if err != nil { t.Error(err) } @@ -471,7 +471,7 @@ func TestFileReEncryption(t *testing.T) { buffer := bytes.Buffer{} readerPublicKeyList := [][chacha20poly1305.KeySize]byte{} readerPublicKeyList = append(readerPublicKeyList, readerPublicKey) - writer, err := NewCrypt4GHWriter(&buffer, writerPrivateKey, readerPublicKeyList, nil) + writer, err := NewCrypt4GHWriter(&buffer, writerPrivateKey, readerPublicKeyList, nil, nil) if err != nil { t.Error(err) }