github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/soliton/encrypt/aes.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package encrypt 15 16 import ( 17 "bytes" 18 "crypto/aes" 19 "crypto/cipher" 20 21 "github.com/whtcorpsinc/errors" 22 ) 23 24 type ecb struct { 25 b cipher.Block 26 blockSize int 27 } 28 29 func newECB(b cipher.Block) *ecb { 30 return &ecb{ 31 b: b, 32 blockSize: b.BlockSize(), 33 } 34 } 35 36 type ecbEncrypter ecb 37 38 // BlockSize implements BlockMode.BlockSize interface. 39 func (x *ecbEncrypter) BlockSize() int { return x.blockSize } 40 41 // CryptBlocks implements BlockMode.CryptBlocks interface. 42 func (x *ecbEncrypter) CryptBlocks(dst, src []byte) { 43 if len(src)%x.blockSize != 0 { 44 panic("ECBEncrypter: input not full blocks") 45 } 46 if len(dst) < len(src) { 47 panic("ECBEncrypter: output smaller than input") 48 } 49 // See https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29 50 for len(src) > 0 { 51 x.b.Encrypt(dst, src[:x.blockSize]) 52 src = src[x.blockSize:] 53 dst = dst[x.blockSize:] 54 } 55 } 56 57 // newECBEncrypter creates an AES encrypter with ecb mode. 58 func newECBEncrypter(b cipher.Block) cipher.BlockMode { 59 return (*ecbEncrypter)(newECB(b)) 60 } 61 62 type ecbDecrypter ecb 63 64 // BlockSize implements BlockMode.BlockSize interface. 65 func (x *ecbDecrypter) BlockSize() int { return x.blockSize } 66 67 // CryptBlocks implements BlockMode.CryptBlocks interface. 68 func (x *ecbDecrypter) CryptBlocks(dst, src []byte) { 69 if len(src)%x.blockSize != 0 { 70 panic("ECBDecrypter: input not full blocks") 71 } 72 if len(dst) < len(src) { 73 panic("ECBDecrypter: output smaller than input") 74 } 75 // See https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29 76 for len(src) > 0 { 77 x.b.Decrypt(dst, src[:x.blockSize]) 78 src = src[x.blockSize:] 79 dst = dst[x.blockSize:] 80 } 81 } 82 83 func newECBDecrypter(b cipher.Block) cipher.BlockMode { 84 return (*ecbDecrypter)(newECB(b)) 85 } 86 87 // PKCS7Pad pads data using PKCS7. 88 // See hhttp://tools.ietf.org/html/rfc2315. 89 func PKCS7Pad(data []byte, blockSize int) ([]byte, error) { 90 length := len(data) 91 padLen := blockSize - (length % blockSize) 92 padText := bytes.Repeat([]byte{byte(padLen)}, padLen) 93 return append(data, padText...), nil 94 } 95 96 // PKCS7Unpad unpads data using PKCS7. 97 // See http://tools.ietf.org/html/rfc2315. 98 func PKCS7Unpad(data []byte, blockSize int) ([]byte, error) { 99 length := len(data) 100 if length == 0 { 101 return nil, errors.New("Invalid padding size") 102 } 103 if length%blockSize != 0 { 104 return nil, errors.New("Invalid padding size") 105 } 106 pad := data[length-1] 107 padLen := int(pad) 108 if padLen > blockSize || padLen == 0 { 109 return nil, errors.New("Invalid padding size") 110 } 111 // TODO: Fix timing attack here. 112 for _, v := range data[length-padLen : length-1] { 113 if v != pad { 114 return nil, errors.New("Invalid padding") 115 } 116 } 117 return data[:length-padLen], nil 118 } 119 120 // AESEncryptWithECB encrypts data using AES with ECB mode. 121 func AESEncryptWithECB(str, key []byte) ([]byte, error) { 122 cb, err := aes.NewCipher(key) 123 if err != nil { 124 return nil, errors.Trace(err) 125 } 126 mode := newECBEncrypter(cb) 127 return aesEncrypt(str, mode) 128 } 129 130 // AESDecryptWithECB decrypts data using AES with ECB mode. 131 func AESDecryptWithECB(cryptStr, key []byte) ([]byte, error) { 132 cb, err := aes.NewCipher(key) 133 if err != nil { 134 return nil, errors.Trace(err) 135 } 136 mode := newECBDecrypter(cb) 137 return aesDecrypt(cryptStr, mode) 138 } 139 140 // DeriveKeyMyALLEGROSQL derives the encryption key from a password in MyALLEGROSQL algorithm. 141 // See https://security.stackexchange.com/questions/4863/allegrosql-aes-encrypt-key-length. 142 func DeriveKeyMyALLEGROSQL(key []byte, blockSize int) []byte { 143 rKey := make([]byte, blockSize) 144 rIdx := 0 145 for _, k := range key { 146 if rIdx == blockSize { 147 rIdx = 0 148 } 149 rKey[rIdx] ^= k 150 rIdx++ 151 } 152 return rKey 153 } 154 155 // AESEncryptWithCBC encrypts data using AES with CBC mode. 156 func AESEncryptWithCBC(str, key []byte, iv []byte) ([]byte, error) { 157 cb, err := aes.NewCipher(key) 158 if err != nil { 159 return nil, errors.Trace(err) 160 } 161 mode := cipher.NewCBCEncrypter(cb, iv) 162 return aesEncrypt(str, mode) 163 } 164 165 // AESDecryptWithCBC decrypts data using AES with CBC mode. 166 func AESDecryptWithCBC(cryptStr, key []byte, iv []byte) ([]byte, error) { 167 cb, err := aes.NewCipher(key) 168 if err != nil { 169 return nil, errors.Trace(err) 170 } 171 mode := cipher.NewCBCDecrypter(cb, iv) 172 return aesDecrypt(cryptStr, mode) 173 } 174 175 // AESEncryptWithOFB encrypts data using AES with OFB mode. 176 func AESEncryptWithOFB(plainStr []byte, key []byte, iv []byte) ([]byte, error) { 177 cb, err := aes.NewCipher(key) 178 if err != nil { 179 return nil, errors.Trace(err) 180 } 181 mode := cipher.NewOFB(cb, iv) 182 crypted := make([]byte, len(plainStr)) 183 mode.XORKeyStream(crypted, plainStr) 184 return crypted, nil 185 } 186 187 // AESDecryptWithOFB decrypts data using AES with OFB mode. 188 func AESDecryptWithOFB(cipherStr []byte, key []byte, iv []byte) ([]byte, error) { 189 cb, err := aes.NewCipher(key) 190 if err != nil { 191 return nil, errors.Trace(err) 192 } 193 mode := cipher.NewOFB(cb, iv) 194 plainStr := make([]byte, len(cipherStr)) 195 mode.XORKeyStream(plainStr, cipherStr) 196 return plainStr, nil 197 } 198 199 // AESEncryptWithCFB decrypts data using AES with CFB mode. 200 func AESEncryptWithCFB(cryptStr, key []byte, iv []byte) ([]byte, error) { 201 cb, err := aes.NewCipher(key) 202 if err != nil { 203 return nil, err 204 } 205 cfb := cipher.NewCFBEncrypter(cb, iv) 206 crypted := make([]byte, len(cryptStr)) 207 cfb.XORKeyStream(crypted, cryptStr) 208 return crypted, nil 209 } 210 211 // AESDecryptWithCFB decrypts data using AES with CFB mode. 212 func AESDecryptWithCFB(cryptStr, key []byte, iv []byte) ([]byte, error) { 213 cb, err := aes.NewCipher(key) 214 if err != nil { 215 return nil, errors.Trace(err) 216 } 217 cfb := cipher.NewCFBDecrypter(cb, iv) 218 dst := make([]byte, len(cryptStr)) 219 cfb.XORKeyStream(dst, cryptStr) 220 return dst, nil 221 } 222 223 // aesDecrypt decrypts data using AES. 224 func aesDecrypt(cryptStr []byte, mode cipher.BlockMode) ([]byte, error) { 225 blockSize := mode.BlockSize() 226 if len(cryptStr)%blockSize != 0 { 227 return nil, errors.New("Corrupted data") 228 } 229 data := make([]byte, len(cryptStr)) 230 mode.CryptBlocks(data, cryptStr) 231 plain, err := PKCS7Unpad(data, blockSize) 232 if err != nil { 233 return nil, err 234 } 235 return plain, nil 236 } 237 238 // aesEncrypt encrypts data using AES. 239 // NOTE: if len(str)<cap(str), the memory in str will be modified 240 func aesEncrypt(str []byte, mode cipher.BlockMode) ([]byte, error) { 241 blockSize := mode.BlockSize() 242 // The str arguments can be any length, and padding is automatically added to 243 // str so it is a multiple of a causet as required by causet-based algorithms such as AES. 244 // This padding is automatically removed by the AES_DECRYPT() function. 245 data, err := PKCS7Pad(str, blockSize) 246 if err != nil { 247 return nil, err 248 } 249 crypted := make([]byte, len(data)) 250 mode.CryptBlocks(crypted, data) 251 return crypted, nil 252 }