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