From ba03f463160d1c707be43c19fe6da618c7234db0 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 Jan 2021 16:47:35 +0300 Subject: [PATCH] [#290] util: Implement salting writer Implement wrapper over io.Writer that applies binary salt to written data. Signed-off-by: Leonard Lyubich --- pkg/util/salt.go | 44 +++++++++++++++++++++++++++++++++++++++++-- pkg/util/salt_test.go | 34 +++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 pkg/util/salt_test.go diff --git a/pkg/util/salt.go b/pkg/util/salt.go index 26a3fe3a..b97984e7 100644 --- a/pkg/util/salt.go +++ b/pkg/util/salt.go @@ -1,8 +1,18 @@ package util +import ( + "io" +) + // SaltXOR xors bits of data with salt // repeating salt if necessary. -func SaltXOR(data, salt []byte) (result []byte) { +func SaltXOR(data, salt []byte) []byte { + return SaltXOROffset(data, salt, 0) +} + +// SaltXOROffset xors bits of data with salt starting from off byte +// repeating salt if necessary. +func SaltXOROffset(data, salt []byte, off int) (result []byte) { result = make([]byte, len(data)) ls := len(salt) if ls == 0 { @@ -11,7 +21,37 @@ func SaltXOR(data, salt []byte) (result []byte) { } for i := range result { - result[i] = data[i] ^ salt[i%ls] + result[i] = data[i] ^ salt[(i+off)%ls] } return } + +type saltWriter struct { + w io.Writer + + off int + + salt []byte +} + +// NewSaltingWriter returns io.Writer instance that applies +// salt to written data and write the result to w. +func NewSaltingWriter(w io.Writer, salt []byte) io.Writer { + if len(salt) == 0 { + return w + } + + return &saltWriter{ + w: w, + salt: salt, + } +} + +func (w *saltWriter) Write(data []byte) (int, error) { + if dataLen := len(data); dataLen > 0 { + data = SaltXOROffset(data, w.salt, w.off) + w.off += dataLen + } + + return w.w.Write(data) +} diff --git a/pkg/util/salt_test.go b/pkg/util/salt_test.go new file mode 100644 index 00000000..4cee983a --- /dev/null +++ b/pkg/util/salt_test.go @@ -0,0 +1,34 @@ +package util_test + +import ( + "bytes" + "crypto/rand" + "testing" + + "github.com/nspcc-dev/neofs-node/pkg/util" + "github.com/stretchr/testify/require" +) + +func randData(sz int) []byte { + data := make([]byte, sz) + + _, _ = rand.Read(data) + + return data +} + +func TestSaltWriter_Write(t *testing.T) { + salt := randData(4) + data := randData(15) + buf := bytes.NewBuffer(nil) + + w := util.NewSaltingWriter(buf, salt) + + _, err := w.Write(data) + require.NoError(t, err) + + require.Equal(t, + buf.Bytes(), + util.SaltXOR(data, salt), + ) +}