github.com/gobitfly/go-ethereum@v1.8.12/swarm/storage/encryption/encryption.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package encryption
    18  
    19  import (
    20  	"crypto/rand"
    21  	"encoding/binary"
    22  	"fmt"
    23  	"hash"
    24  )
    25  
    26  const KeyLength = 32
    27  
    28  type Key []byte
    29  
    30  type Encryption interface {
    31  	Encrypt(data []byte, key Key) ([]byte, error)
    32  	Decrypt(data []byte, key Key) ([]byte, error)
    33  }
    34  
    35  type encryption struct {
    36  	padding  int
    37  	initCtr  uint32
    38  	hashFunc func() hash.Hash
    39  }
    40  
    41  func New(padding int, initCtr uint32, hashFunc func() hash.Hash) *encryption {
    42  	return &encryption{
    43  		padding:  padding,
    44  		initCtr:  initCtr,
    45  		hashFunc: hashFunc,
    46  	}
    47  }
    48  
    49  func (e *encryption) Encrypt(data []byte, key Key) ([]byte, error) {
    50  	length := len(data)
    51  	isFixedPadding := e.padding > 0
    52  	if isFixedPadding && length > e.padding {
    53  		return nil, fmt.Errorf("Data length longer than padding, data length %v padding %v", length, e.padding)
    54  	}
    55  
    56  	paddedData := data
    57  	if isFixedPadding && length < e.padding {
    58  		paddedData = make([]byte, e.padding)
    59  		copy(paddedData[:length], data)
    60  		rand.Read(paddedData[length:])
    61  	}
    62  	return e.transform(paddedData, key), nil
    63  }
    64  
    65  func (e *encryption) Decrypt(data []byte, key Key) ([]byte, error) {
    66  	length := len(data)
    67  	if e.padding > 0 && length != e.padding {
    68  		return nil, fmt.Errorf("Data length different than padding, data length %v padding %v", length, e.padding)
    69  	}
    70  
    71  	return e.transform(data, key), nil
    72  }
    73  
    74  func (e *encryption) transform(data []byte, key Key) []byte {
    75  	dataLength := len(data)
    76  	transformedData := make([]byte, dataLength)
    77  	hasher := e.hashFunc()
    78  	ctr := e.initCtr
    79  	hashSize := hasher.Size()
    80  	for i := 0; i < dataLength; i += hashSize {
    81  		hasher.Write(key)
    82  
    83  		ctrBytes := make([]byte, 4)
    84  		binary.LittleEndian.PutUint32(ctrBytes, ctr)
    85  
    86  		hasher.Write(ctrBytes)
    87  
    88  		ctrHash := hasher.Sum(nil)
    89  		hasher.Reset()
    90  		hasher.Write(ctrHash)
    91  
    92  		segmentKey := hasher.Sum(nil)
    93  
    94  		hasher.Reset()
    95  
    96  		segmentSize := min(hashSize, dataLength-i)
    97  		for j := 0; j < segmentSize; j++ {
    98  			transformedData[i+j] = data[i+j] ^ segmentKey[j]
    99  		}
   100  		ctr++
   101  	}
   102  	return transformedData
   103  }
   104  
   105  func GenerateRandomKey() (Key, error) {
   106  	key := make([]byte, KeyLength)
   107  	_, err := rand.Read(key)
   108  	return key, err
   109  }
   110  
   111  func min(x, y int) int {
   112  	if x < y {
   113  		return x
   114  	}
   115  	return y
   116  }