aboutsummaryrefslogtreecommitdiffstats
path: root/swarm/storage/encryption/encryption.go
diff options
context:
space:
mode:
Diffstat (limited to 'swarm/storage/encryption/encryption.go')
-rw-r--r--swarm/storage/encryption/encryption.go116
1 files changed, 116 insertions, 0 deletions
diff --git a/swarm/storage/encryption/encryption.go b/swarm/storage/encryption/encryption.go
new file mode 100644
index 000000000..e50f2163d
--- /dev/null
+++ b/swarm/storage/encryption/encryption.go
@@ -0,0 +1,116 @@
+// Copyright 2018 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package encryption
+
+import (
+ "crypto/rand"
+ "encoding/binary"
+ "fmt"
+ "hash"
+)
+
+const KeyLength = 32
+
+type Key []byte
+
+type Encryption interface {
+ Encrypt(data []byte, key Key) ([]byte, error)
+ Decrypt(data []byte, key Key) ([]byte, error)
+}
+
+type encryption struct {
+ padding int
+ initCtr uint32
+ hashFunc func() hash.Hash
+}
+
+func New(padding int, initCtr uint32, hashFunc func() hash.Hash) *encryption {
+ return &encryption{
+ padding: padding,
+ initCtr: initCtr,
+ hashFunc: hashFunc,
+ }
+}
+
+func (e *encryption) Encrypt(data []byte, key Key) ([]byte, error) {
+ length := len(data)
+ isFixedPadding := e.padding > 0
+ if isFixedPadding && length > e.padding {
+ return nil, fmt.Errorf("Data length longer than padding, data length %v padding %v", length, e.padding)
+ }
+
+ paddedData := data
+ if isFixedPadding && length < e.padding {
+ paddedData = make([]byte, e.padding)
+ copy(paddedData[:length], data)
+ rand.Read(paddedData[length:])
+ }
+ return e.transform(paddedData, key), nil
+}
+
+func (e *encryption) Decrypt(data []byte, key Key) ([]byte, error) {
+ length := len(data)
+ if e.padding > 0 && length != e.padding {
+ return nil, fmt.Errorf("Data length different than padding, data length %v padding %v", length, e.padding)
+ }
+
+ return e.transform(data, key), nil
+}
+
+func (e *encryption) transform(data []byte, key Key) []byte {
+ dataLength := len(data)
+ transformedData := make([]byte, dataLength)
+ hasher := e.hashFunc()
+ ctr := e.initCtr
+ hashSize := hasher.Size()
+ for i := 0; i < dataLength; i += hashSize {
+ hasher.Write(key)
+
+ ctrBytes := make([]byte, 4)
+ binary.LittleEndian.PutUint32(ctrBytes, ctr)
+
+ hasher.Write(ctrBytes)
+
+ ctrHash := hasher.Sum(nil)
+ hasher.Reset()
+ hasher.Write(ctrHash)
+
+ segmentKey := hasher.Sum(nil)
+
+ hasher.Reset()
+
+ segmentSize := min(hashSize, dataLength-i)
+ for j := 0; j < segmentSize; j++ {
+ transformedData[i+j] = data[i+j] ^ segmentKey[j]
+ }
+ ctr++
+ }
+ return transformedData
+}
+
+func GenerateRandomKey() (Key, error) {
+ key := make([]byte, KeyLength)
+ _, err := rand.Read(key)
+ return key, err
+}
+
+func min(x, y int) int {
+ if x < y {
+ return x
+ }
+ return y
+}