github.com/ethersphere/bee/v2@v2.2.0/pkg/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 exposes functionalities needed for 18 // encryption and decryption operations in Bee. 19 package encryption 20 21 import ( 22 "crypto/rand" 23 "encoding/binary" 24 "fmt" 25 "hash" 26 ) 27 28 const ( 29 KeyLength = 32 30 ReferenceSize = 64 31 ) 32 33 type Key []byte 34 35 type Encrypter interface { 36 Key() Key 37 Encrypt(data []byte) ([]byte, error) 38 } 39 40 type Decrypter interface { 41 Key() Key 42 Decrypt(data []byte) ([]byte, error) 43 } 44 45 type Interface interface { 46 Encrypter 47 Decrypter 48 Reset() 49 } 50 51 type Encryption struct { 52 key Key // the encryption key (hashSize bytes long) 53 keyLen int // length of the key = length of blockcipher block 54 padding int // encryption will pad the data upto this if > 0 55 index int // counter index 56 initCtr uint32 // initial counter used for counter mode blockcipher 57 hashFunc func() hash.Hash // hasher constructor function 58 } 59 60 // New constructs a new encrypter/decrypter 61 func New(key Key, padding int, initCtr uint32, hashFunc func() hash.Hash) Interface { 62 return &Encryption{ 63 key: key, 64 keyLen: len(key), 65 padding: padding, 66 initCtr: initCtr, 67 hashFunc: hashFunc, 68 } 69 } 70 71 // Key returns the base key 72 func (e *Encryption) Key() Key { 73 return e.key 74 } 75 76 // Encrypt encrypts the data and does padding if specified 77 func (e *Encryption) Encrypt(data []byte) ([]byte, error) { 78 length := len(data) 79 outLength := length 80 isFixedPadding := e.padding > 0 81 if isFixedPadding { 82 if length > e.padding { 83 return nil, fmt.Errorf("data length longer than padding, data length %v padding %v", length, e.padding) 84 } 85 outLength = e.padding 86 } 87 out := make([]byte, outLength) 88 err := e.transform(data, out) 89 if err != nil { 90 return nil, err 91 } 92 return out, nil 93 } 94 95 // Decrypt decrypts the data, if padding was used caller must know original length and truncate 96 func (e *Encryption) Decrypt(data []byte) ([]byte, error) { 97 length := len(data) 98 if e.padding > 0 && length != e.padding { 99 return nil, fmt.Errorf("data length different than padding, data length %v padding %v", length, e.padding) 100 } 101 out := make([]byte, length) 102 err := e.transform(data, out) 103 if err != nil { 104 return nil, err 105 } 106 return out, nil 107 } 108 109 // Reset resets the counter. It is only safe to call after an encryption operation is completed 110 // After Reset is called, the Encryption object can be reused for other data 111 func (e *Encryption) Reset() { 112 e.index = 0 113 } 114 115 // split up input into keylength segments and encrypt sequentially 116 func (e *Encryption) transform(in, out []byte) error { 117 inLength := len(in) 118 119 for i := 0; i < inLength; i += e.keyLen { 120 l := min(e.keyLen, inLength-i) 121 err := e.Transcrypt(e.index, in[i:i+l], out[i:i+l]) 122 if err != nil { 123 return err 124 } 125 e.index++ 126 } 127 // pad the rest if out is longer 128 pad(out[inLength:]) 129 return nil 130 } 131 132 // used for segmentwise transformation 133 // if in is shorter than out, padding is used 134 func (e *Encryption) Transcrypt(i int, in, out []byte) error { 135 // first hash key with counter (initial counter + i) 136 hasher := e.hashFunc() 137 _, err := hasher.Write(e.key) 138 if err != nil { 139 return err 140 } 141 142 ctrBytes := make([]byte, 4) 143 binary.LittleEndian.PutUint32(ctrBytes, uint32(i)+e.initCtr) 144 _, err = hasher.Write(ctrBytes) 145 if err != nil { 146 return err 147 } 148 ctrHash := hasher.Sum(nil) 149 hasher.Reset() 150 151 // second round of hashing for selective disclosure 152 _, err = hasher.Write(ctrHash) 153 if err != nil { 154 return err 155 } 156 segmentKey := hasher.Sum(nil) 157 hasher.Reset() 158 159 // XOR bytes uptil length of in (out must be at least as long) 160 inLength := len(in) 161 for j := 0; j < inLength; j++ { 162 out[j] = in[j] ^ segmentKey[j] 163 } 164 // insert padding if out is longer 165 pad(out[inLength:]) 166 167 return nil 168 } 169 170 func pad(b []byte) { 171 l := len(b) 172 for total := 0; total < l; { 173 read, _ := rand.Read(b[total:]) 174 total += read 175 } 176 } 177 178 // GenerateRandomKey generates a random key of length l 179 func GenerateRandomKey(l int) Key { 180 key := make([]byte, l) 181 var total int 182 for total < l { 183 read, _ := rand.Read(key[total:]) 184 total += read 185 } 186 return key 187 }