Commit 082629c3 authored by Janoš Guljaš's avatar Janoš Guljaš Committed by GitHub

add encryption mock (#627)

parent e7c8c691
// Copyright 2020 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mock
import (
"errors"
"github.com/ethersphere/bee/pkg/encryption"
)
var _ encryption.Interface = (*Encryptor)(nil)
var (
// ErrNotImplemented is returned when a required Encryptor function is not set.
ErrNotImplemented = errors.New("not implemented")
// ErrInvalidXORKey is returned when the key for XOR encryption is not valid.
ErrInvalidXORKey = errors.New("invalid xor key")
)
// Encryptor implements encryption Interface in order to mock it in tests.
type Encryptor struct {
encryptFunc func(data []byte) ([]byte, error)
decryptFunc func(data []byte) ([]byte, error)
resetFunc func()
}
// New returns a new Encryptor configured with provided options.
func New(opts ...Option) *Encryptor {
e := new(Encryptor)
for _, o := range opts {
o(e)
}
return e
}
// Encrypt calls the configured encrypt function, or returns ErrNotImplemented
// if it is not set.
func (e *Encryptor) Encrypt(data []byte) ([]byte, error) {
if e.encryptFunc == nil {
return nil, ErrNotImplemented
}
return e.encryptFunc(data)
}
// Decrypt calls the configured decrypt function, or returns ErrNotImplemented
// if it is not set.
func (e *Encryptor) Decrypt(data []byte) ([]byte, error) {
if e.decryptFunc == nil {
return nil, ErrNotImplemented
}
return e.decryptFunc(data)
}
// Reset calls the configured reset function, if it is set.
func (e *Encryptor) Reset() {
if e.resetFunc == nil {
return
}
e.resetFunc()
}
// Option represents configures the Encryptor instance.
type Option func(*Encryptor)
// WithEncryptFunc sets the Encryptor Encrypt function.
func WithEncryptFunc(f func([]byte) ([]byte, error)) Option {
return func(e *Encryptor) {
e.encryptFunc = f
}
}
// WithDecryptFunc sets the Encryptor Decrypt function.
func WithDecryptFunc(f func([]byte) ([]byte, error)) Option {
return func(e *Encryptor) {
e.decryptFunc = f
}
}
// WithResetFunc sets the Encryptor Reset function.
func WithResetFunc(f func()) Option {
return func(e *Encryptor) {
e.resetFunc = f
}
}
// WithXOREncryption sets Encryptor Encrypt and Decrypt functions with XOR
// encryption function that uses the provided key for encryption.
func WithXOREncryption(key []byte) Option {
f := newXORFunc(key)
return func(e *Encryptor) {
e.encryptFunc = f
e.decryptFunc = f
}
}
func newXORFunc(key []byte) func([]byte) ([]byte, error) {
return func(data []byte) ([]byte, error) {
return xor(data, key)
}
}
func xor(input, key []byte) ([]byte, error) {
keyLen := len(key)
if keyLen == 0 {
return nil, ErrInvalidXORKey
}
inputLen := len(input)
output := make([]byte, inputLen)
for i := 0; i < inputLen; i++ {
output[i] = input[i] ^ key[i%keyLen]
}
return output, nil
}
// Copyright 2020 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mock_test
import (
"bytes"
"errors"
"testing"
"github.com/ethersphere/bee/pkg/encryption/mock"
)
var errTest = errors.New("test error")
func TestEncryptor_Encrypt(t *testing.T) {
for _, tc := range []struct {
name string
options []mock.Option
data []byte
want []byte
wantErr error
}{
{
name: "empty",
wantErr: mock.ErrNotImplemented,
},
{
name: "func constant",
options: []mock.Option{mock.WithEncryptFunc(func([]byte) ([]byte, error) {
return []byte("some random data"), nil
})},
want: []byte("some random data"),
},
{
name: "func identity",
data: []byte("input data"),
options: []mock.Option{mock.WithEncryptFunc(func(data []byte) ([]byte, error) {
return data, nil
})},
want: []byte("input data"),
},
{
name: "func err",
options: []mock.Option{mock.WithEncryptFunc(func([]byte) ([]byte, error) {
return nil, errTest
})},
wantErr: errTest,
},
{
name: "xor",
data: []byte("input data"),
options: []mock.Option{mock.WithXOREncryption([]byte("the key"))},
want: []byte{0x1d, 0x6, 0x15, 0x55, 0x1f, 0x45, 0x1d, 0x15, 0x1c, 0x4},
},
{
name: "xor error",
options: []mock.Option{mock.WithXOREncryption(nil)},
wantErr: mock.ErrInvalidXORKey,
},
} {
t.Run(tc.name, func(t *testing.T) {
got, err := mock.New(tc.options...).Encrypt(tc.data)
if err != tc.wantErr {
t.Fatalf("got error %v, want %v", err, tc.wantErr)
}
if !bytes.Equal(got, tc.want) {
t.Errorf("got data %#v, want %#v", got, tc.want)
}
})
}
}
func TestEncryptor_Decrypt(t *testing.T) {
for _, tc := range []struct {
name string
options []mock.Option
data []byte
want []byte
wantErr error
}{
{
name: "empty",
wantErr: mock.ErrNotImplemented,
},
{
name: "func constant",
options: []mock.Option{mock.WithDecryptFunc(func([]byte) ([]byte, error) {
return []byte("some random data"), nil
})},
want: []byte("some random data"),
},
{
name: "func identity",
data: []byte("input data"),
options: []mock.Option{mock.WithDecryptFunc(func(data []byte) ([]byte, error) {
return data, nil
})},
want: []byte("input data"),
},
{
name: "func err",
options: []mock.Option{mock.WithDecryptFunc(func([]byte) ([]byte, error) {
return nil, errTest
})},
wantErr: errTest,
},
{
name: "xor",
data: []byte("input data"),
options: []mock.Option{mock.WithXOREncryption([]byte("the key"))},
want: []byte{0x1d, 0x6, 0x15, 0x55, 0x1f, 0x45, 0x1d, 0x15, 0x1c, 0x4},
},
{
name: "xor error",
options: []mock.Option{mock.WithXOREncryption(nil)},
wantErr: mock.ErrInvalidXORKey,
},
} {
t.Run(tc.name, func(t *testing.T) {
got, err := mock.New(tc.options...).Decrypt(tc.data)
if err != tc.wantErr {
t.Fatalf("got error %v, want %v", err, tc.wantErr)
}
if !bytes.Equal(got, tc.want) {
t.Errorf("got data %#v, want %#v", got, tc.want)
}
})
}
}
func TestEncryptor_Reset(t *testing.T) {
t.Run("empty", func(t *testing.T) {
// should not panic
mock.New().Reset()
})
t.Run("func", func(t *testing.T) {
var called bool
mock.New(mock.WithResetFunc(func() {
called = true
})).Reset()
if !called {
t.Error("reset func not called")
}
})
}
func TestEncryptor_XOREncryption(t *testing.T) {
key := []byte("some strong key")
e := mock.New(mock.WithXOREncryption(key))
data := []byte("very secret data")
enc, err := e.Encrypt(data)
if err != nil {
t.Fatal(err)
}
if bytes.Equal(enc, data) {
t.Fatal("encrypted and input data must not be the same")
}
dec, err := e.Decrypt(enc)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(dec, data) {
t.Errorf("got decrypted data %#v, want %#v", dec, data)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment