github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/swarm/storage/encryption/encryption.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //
    10  //
    11  //
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  
    25  package encryption
    26  
    27  import (
    28  	"crypto/rand"
    29  	"encoding/binary"
    30  	"fmt"
    31  	"hash"
    32  )
    33  
    34  const KeyLength = 32
    35  
    36  type Key []byte
    37  
    38  type Encryption interface {
    39  	Encrypt(data []byte, key Key) ([]byte, error)
    40  	Decrypt(data []byte, key Key) ([]byte, error)
    41  }
    42  
    43  type encryption struct {
    44  	padding  int
    45  	initCtr  uint32
    46  	hashFunc func() hash.Hash
    47  }
    48  
    49  func New(padding int, initCtr uint32, hashFunc func() hash.Hash) *encryption {
    50  	return &encryption{
    51  		padding:  padding,
    52  		initCtr:  initCtr,
    53  		hashFunc: hashFunc,
    54  	}
    55  }
    56  
    57  func (e *encryption) Encrypt(data []byte, key Key) ([]byte, error) {
    58  	length := len(data)
    59  	isFixedPadding := e.padding > 0
    60  	if isFixedPadding && length > e.padding {
    61  		return nil, fmt.Errorf("Data length longer than padding, data length %v padding %v", length, e.padding)
    62  	}
    63  
    64  	paddedData := data
    65  	if isFixedPadding && length < e.padding {
    66  		paddedData = make([]byte, e.padding)
    67  		copy(paddedData[:length], data)
    68  		rand.Read(paddedData[length:])
    69  	}
    70  	return e.transform(paddedData, key), nil
    71  }
    72  
    73  func (e *encryption) Decrypt(data []byte, key Key) ([]byte, error) {
    74  	length := len(data)
    75  	if e.padding > 0 && length != e.padding {
    76  		return nil, fmt.Errorf("Data length different than padding, data length %v padding %v", length, e.padding)
    77  	}
    78  
    79  	return e.transform(data, key), nil
    80  }
    81  
    82  func (e *encryption) transform(data []byte, key Key) []byte {
    83  	dataLength := len(data)
    84  	transformedData := make([]byte, dataLength)
    85  	hasher := e.hashFunc()
    86  	ctr := e.initCtr
    87  	hashSize := hasher.Size()
    88  	for i := 0; i < dataLength; i += hashSize {
    89  		hasher.Write(key)
    90  
    91  		ctrBytes := make([]byte, 4)
    92  		binary.LittleEndian.PutUint32(ctrBytes, ctr)
    93  
    94  		hasher.Write(ctrBytes)
    95  
    96  		ctrHash := hasher.Sum(nil)
    97  		hasher.Reset()
    98  		hasher.Write(ctrHash)
    99  
   100  		segmentKey := hasher.Sum(nil)
   101  
   102  		hasher.Reset()
   103  
   104  		segmentSize := min(hashSize, dataLength-i)
   105  		for j := 0; j < segmentSize; j++ {
   106  			transformedData[i+j] = data[i+j] ^ segmentKey[j]
   107  		}
   108  		ctr++
   109  	}
   110  	return transformedData
   111  }
   112  
   113  func GenerateRandomKey() (Key, error) {
   114  	key := make([]byte, KeyLength)
   115  	_, err := rand.Read(key)
   116  	return key, err
   117  }
   118  
   119  func min(x, y int) int {
   120  	if x < y {
   121  		return x
   122  	}
   123  	return y
   124  }