github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/encrypt/crypto/aes.go (about) 1 package crypto 2 3 import ( 4 "bytes" 5 "crypto/aes" 6 "crypto/cipher" 7 "crypto/rand" 8 "crypto/sha256" 9 "io" 10 ) 11 12 const ( 13 gcmTagSize = 16 // crypto/cipher.gcmTagSize 14 gcmStandardNonceSize = 12 // crypto/cipher.gcmStandardNonceSize 15 ) 16 17 // GCMEncrypt encrypts plaintext with key using the GCM mode. 18 // The returned ciphertext contains the nonce, encrypted text and 19 // the additional data authentication tag. If additional data is not 20 // provided (as an Option), random data will be generated and used. 21 // 22 // GCM模式是CTR和GHASH的组合,GHASH操作定义为密文结果与密钥以及消息长度在GF(2^128)域上相乘。 23 // GCM比CCM的优势是在于更高并行度及更好的性能。 24 // TLS1.2标准使用的就是AES-GCM算法,并且Intel CPU提供了GHASH的硬件加速功能。 25 func GCMEncrypt(plaintext, key []byte, opts ...Option) (ciphertext []byte, err error) { 26 opt := (&options{}).apply(opts...) 27 key = KeyPadding(key) 28 nonceSize := defaultInt(opt.nonceSize, gcmStandardNonceSize) 29 nonce := make([]byte, nonceSize) 30 if _, err := io.ReadFull(rand.Reader, nonce); err != nil { 31 return nil, err 32 } 33 block, err := aes.NewCipher(key) 34 if err != nil { 35 return nil, err 36 } 37 gcm, err := cipher.NewGCMWithNonceSize(block, nonceSize) 38 if err != nil { 39 return nil, err 40 } 41 42 ciphertext = gcm.Seal(nil, nonce, plaintext, opt.additionalData) 43 ciphertext = append(nonce, ciphertext...) //nolint:makezero 44 ciphertext, err = opt.encode(ciphertext) 45 if err != nil { 46 return nil, err 47 } 48 return ciphertext, nil 49 } 50 51 // GCMEncryptNewKey creates a new key and encrypts plaintext with the 52 // new key using GCM mode. 53 // The returned ciphertext contains the nonce, encrypted text and 54 // the additional data authentication tag. If additional data is not 55 // provided (as an Option), random data will be generated and used. 56 func GCMEncryptNewKey(plaintext []byte, opts ...Option) ( 57 ciphertext, key, additional []byte, err error, 58 ) { 59 opt := (&options{}).apply(opts...) 60 keySize := defaultInt(opt.keySize, 2*aes.BlockSize) 61 nonceSize := defaultInt(opt.nonceSize, gcmStandardNonceSize) 62 additional = opt.additionalData 63 buflen := keySize + nonceSize 64 if len(additional) == 0 { 65 buflen += aes.BlockSize 66 } 67 buf := make([]byte, buflen) 68 if _, err = io.ReadFull(rand.Reader, buf); err != nil { 69 return nil, nil, nil, err 70 } 71 nonceEnd := keySize + nonceSize 72 key = buf[:keySize:keySize] 73 nonce := buf[keySize:nonceEnd:nonceEnd] 74 if len(additional) == 0 { 75 additional = buf[keySize+nonceSize:] 76 } 77 78 block, err := aes.NewCipher(key) 79 if err != nil { 80 return nil, nil, nil, err 81 } 82 gcm, err := cipher.NewGCMWithNonceSize(block, nonceSize) 83 if err != nil { 84 return nil, nil, nil, err 85 } 86 87 ciphertext = gcm.Seal(nil, nonce, plaintext, additional) 88 ciphertext = append(nonce, ciphertext...) 89 ciphertext, err = opt.encode(ciphertext) 90 if err != nil { 91 return nil, nil, nil, err 92 } 93 return ciphertext, key, additional, nil 94 } 95 96 // UnpackGCMCipherText unpacks cipher text returned by GCMEncrypt and 97 // GCMEncryptNewKey into encrypted text, nonce and authentication tag. 98 func UnpackGCMCipherText(ciphertext []byte, opts ...Option) (text, nonce, tag []byte) { 99 opt := (&options{}).apply(opts...) 100 nonceSize := defaultInt(opt.nonceSize, gcmStandardNonceSize) 101 tagOffset := len(ciphertext) - gcmTagSize 102 nonce = ciphertext[:nonceSize:nonceSize] 103 text = ciphertext[nonceSize:tagOffset:tagOffset] 104 tag = ciphertext[tagOffset:] 105 return 106 } 107 108 // GCMDecrypt decrypts ciphertext returned by GCMEncrypt and GCMEncryptNewKey 109 // into plain text. 110 func GCMDecrypt(ciphertext, key []byte, opts ...Option) (plaintext []byte, err error) { 111 opt := (&options{}).apply(opts...) 112 key = KeyPadding(key) 113 nonceSize := defaultInt(opt.nonceSize, gcmStandardNonceSize) 114 ciphertext, err = opt.decode(ciphertext) 115 if err != nil { 116 return nil, err 117 } 118 nonce := ciphertext[:nonceSize] 119 ciphertext = ciphertext[nonceSize:] 120 block, err := aes.NewCipher(key) 121 if err != nil { 122 return nil, err 123 } 124 gcm, err := cipher.NewGCMWithNonceSize(block, nonceSize) 125 if err != nil { 126 return nil, err 127 } 128 return gcm.Open(nil, nonce, ciphertext, opt.additionalData) 129 } 130 131 // CBCEncrypt encrypts plaintext with key using the CBC mode. 132 // The given plaintext will be padded following the PKCS#5 standard. 133 // The returned ciphertext contains the nonce and encrypted data. 134 // 135 // CBC - 密码分组链接模式,明文数据需要按分组大小对齐。 136 func CBCEncrypt(plaintext, key []byte, opts ...Option) (ciphertext []byte, err error) { 137 opt := (&options{}).apply(opts...) 138 key = KeyPadding(key) 139 140 block, err := aes.NewCipher(key) 141 if err != nil { 142 return nil, err 143 } 144 blockSize := block.BlockSize() 145 plaintext = PKCS5Padding(plaintext, blockSize) 146 buf := make([]byte, blockSize+len(plaintext)) 147 nonce := buf[:blockSize] 148 if _, err := io.ReadFull(rand.Reader, nonce); err != nil { 149 return nil, err 150 } 151 encrypter := cipher.NewCBCEncrypter(block, nonce) 152 encrypter.CryptBlocks(buf[len(nonce):], plaintext) 153 ciphertext, err = opt.encode(buf) 154 if err != nil { 155 return nil, err 156 } 157 return ciphertext, nil 158 } 159 160 // CBCDecrypt decrypts ciphertext returned by CBCEncrypt into plain text. 161 func CBCDecrypt(ciphertext, key []byte, opts ...Option) (plaintext []byte, err error) { 162 opt := (&options{}).apply(opts...) 163 key = KeyPadding(key) 164 ciphertext, err = opt.decode(ciphertext) 165 if err != nil { 166 return nil, err 167 } 168 block, err := aes.NewCipher(key) 169 if err != nil { 170 return nil, err 171 } 172 blockSize := block.BlockSize() 173 nonce := ciphertext[:blockSize] 174 ciphertext = ciphertext[blockSize:] 175 decrypter := cipher.NewCBCDecrypter(block, nonce) 176 plaintext = make([]byte, len(ciphertext)) 177 decrypter.CryptBlocks(plaintext, ciphertext) 178 plaintext = PKCS5UnPadding(plaintext) 179 return plaintext, nil 180 } 181 182 // CFBEncrypt encrypts plaintext with key using the CFB mode. 183 // The returned cipher text contains the nonce and encrypted data. 184 // 185 // CFB - 密文反馈模式,明文数据不需要按分组大小对齐。 186 func CFBEncrypt(plaintext, key []byte, opts ...Option) ([]byte, error) { 187 opt := (&options{}).apply(opts...) 188 key = KeyPadding(key) 189 190 block, err := aes.NewCipher(key) 191 if err != nil { 192 return nil, err 193 } 194 blockSize := block.BlockSize() 195 buf := make([]byte, blockSize+len(plaintext)) 196 nonce := buf[:blockSize] 197 if _, err := io.ReadFull(rand.Reader, nonce); err != nil { 198 return nil, err 199 } 200 encrypter := cipher.NewCFBEncrypter(block, nonce) 201 encrypter.XORKeyStream(buf[len(nonce):], plaintext) 202 ciphertext, err := opt.encode(buf) 203 if err != nil { 204 return nil, err 205 } 206 return ciphertext, nil 207 } 208 209 // CFBDecrypt decrypts ciphertext returned by CFBEncrypt. 210 func CFBDecrypt(ciphertext, key []byte, opts ...Option) ([]byte, error) { 211 opt := (&options{}).apply(opts...) 212 key = KeyPadding(key) 213 ciphertext, err := opt.decode(ciphertext) 214 if err != nil { 215 return nil, err 216 } 217 block, err := aes.NewCipher(key) 218 if err != nil { 219 return nil, err 220 } 221 blockSize := block.BlockSize() 222 nonce := ciphertext[:blockSize] 223 ciphertext = ciphertext[blockSize:] 224 decrypter := cipher.NewCFBDecrypter(block, nonce) 225 plaintext := make([]byte, len(ciphertext)) 226 decrypter.XORKeyStream(plaintext, ciphertext) 227 return plaintext, nil 228 } 229 230 // KeyPadding ensures a key's length is either 32, 24 or 16. 231 // If key's length is greater than 32, it returns the first 32 bytes of key. 232 // If key's length is not 32, 24 or 16, it appends additional data to key 233 // using sha256.Sum(key) to make it satisfies the minimal requirement. 234 func KeyPadding(key []byte) []byte { 235 length := len(key) 236 if length == 32 || length == 24 || length == 16 { 237 return key 238 } 239 if length > 32 { 240 return key[:32] 241 } 242 hash := sha256.Sum256(key) 243 switch { 244 case length > 24: 245 return append(key[:length:length], hash[:32-length]...) 246 case length > 16: 247 return append(key[:length:length], hash[:24-length]...) 248 default: 249 return append(key[:length:length], hash[:16-length]...) 250 } 251 } 252 253 // PKCS5Padding appends padding data to plaintext following the PKCS#5 standard. 254 func PKCS5Padding(plaintext []byte, blockSize int) []byte { 255 padding := blockSize - len(plaintext)%blockSize // 需要padding的数目 256 padText := bytes.Repeat([]byte{byte(padding)}, padding) // 生成填充文本 257 return append(plaintext, padText...) 258 } 259 260 // PKCS5UnPadding removes padding data from paddedText following the PKCS#5 standard. 261 func PKCS5UnPadding(paddedText []byte) []byte { 262 length := len(paddedText) 263 unPadding := int(paddedText[length-1]) 264 return paddedText[:(length - unPadding)] 265 } 266 267 func defaultInt(x, defaultValue int) int { 268 if x == 0 { 269 return defaultValue 270 } 271 return x 272 }