github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/storage/encryption/encryption.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:49</date>
    10  //</624342680796663808>
    11  
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  //
    25  //
    26  //
    27  
    28  package encryption
    29  
    30  import (
    31  	"crypto/rand"
    32  	"encoding/binary"
    33  	"fmt"
    34  	"hash"
    35  )
    36  
    37  const KeyLength = 32
    38  
    39  type Key []byte
    40  
    41  type Encryption interface {
    42  	Encrypt(data []byte, key Key) ([]byte, error)
    43  	Decrypt(data []byte, key Key) ([]byte, error)
    44  }
    45  
    46  type encryption struct {
    47  	padding  int
    48  	initCtr  uint32
    49  	hashFunc func() hash.Hash
    50  }
    51  
    52  func New(padding int, initCtr uint32, hashFunc func() hash.Hash) *encryption {
    53  	return &encryption{
    54  		padding:  padding,
    55  		initCtr:  initCtr,
    56  		hashFunc: hashFunc,
    57  	}
    58  }
    59  
    60  func (e *encryption) Encrypt(data []byte, key Key) ([]byte, error) {
    61  	length := len(data)
    62  	isFixedPadding := e.padding > 0
    63  	if isFixedPadding && length > e.padding {
    64  		return nil, fmt.Errorf("Data length longer than padding, data length %v padding %v", length, e.padding)
    65  	}
    66  
    67  	paddedData := data
    68  	if isFixedPadding && length < e.padding {
    69  		paddedData = make([]byte, e.padding)
    70  		copy(paddedData[:length], data)
    71  		rand.Read(paddedData[length:])
    72  	}
    73  	return e.transform(paddedData, key), nil
    74  }
    75  
    76  func (e *encryption) Decrypt(data []byte, key Key) ([]byte, error) {
    77  	length := len(data)
    78  	if e.padding > 0 && length != e.padding {
    79  		return nil, fmt.Errorf("Data length different than padding, data length %v padding %v", length, e.padding)
    80  	}
    81  
    82  	return e.transform(data, key), nil
    83  }
    84  
    85  func (e *encryption) transform(data []byte, key Key) []byte {
    86  	dataLength := len(data)
    87  	transformedData := make([]byte, dataLength)
    88  	hasher := e.hashFunc()
    89  	ctr := e.initCtr
    90  	hashSize := hasher.Size()
    91  	for i := 0; i < dataLength; i += hashSize {
    92  		hasher.Write(key)
    93  
    94  		ctrBytes := make([]byte, 4)
    95  		binary.LittleEndian.PutUint32(ctrBytes, ctr)
    96  
    97  		hasher.Write(ctrBytes)
    98  
    99  		ctrHash := hasher.Sum(nil)
   100  		hasher.Reset()
   101  		hasher.Write(ctrHash)
   102  
   103  		segmentKey := hasher.Sum(nil)
   104  
   105  		hasher.Reset()
   106  
   107  		segmentSize := min(hashSize, dataLength-i)
   108  		for j := 0; j < segmentSize; j++ {
   109  			transformedData[i+j] = data[i+j] ^ segmentKey[j]
   110  		}
   111  		ctr++
   112  	}
   113  	return transformedData
   114  }
   115  
   116  func GenerateRandomKey() (Key, error) {
   117  	key := make([]byte, KeyLength)
   118  	_, err := rand.Read(key)
   119  	return key, err
   120  }
   121  
   122  func min(x, y int) int {
   123  	if x < y {
   124  		return x
   125  	}
   126  	return y
   127  }
   128