github.com/binbinly/pkg@v0.0.11-0.20240321014439-f4fbf666eb0f/util/xcrypto/aes.go (about) 1 package xcrypto 2 3 import ( 4 "bytes" 5 "crypto/aes" 6 "crypto/cipher" 7 "errors" 8 "io" 9 ) 10 11 // AesCBCEncrypt 加密 12 func AesCBCEncrypt(originText, key, iv []byte) ([]byte, error) { 13 14 // 创建一个cipher.Block。参数key为密钥,长度只能是16、24、32字节,用以选择AES-128、AES-192、AES-256 15 block, err := aes.NewCipher(key) 16 if err != nil { 17 return nil, err 18 } 19 20 // 返回加密字节块的大小 21 blockSize := block.BlockSize() 22 23 // PKCS5填充需加密内容 24 originText = pKCS5Padding(originText, blockSize) 25 26 // 返回一个密码分组链接模式的、底层用Block加密的cipher.BlockMode,初始向量iv的长度必须等于Block的块尺寸(Block块尺寸等于密钥尺寸) 27 blockMode := cipher.NewCBCEncrypter(block, iv) 28 29 // 根据 需加密内容[]byte长度,初始化一个新的byte数组,返回byte数组内存地址 30 cipherText := make([]byte, len(originText)) 31 32 // 加密或解密连续的数据块,将加密内容存储到dst中,src需加密内容的长度必须是块大小的整数倍,src和dst可指向同一内存地址 33 blockMode.CryptBlocks(cipherText, originText) 34 35 return cipherText, nil 36 } 37 38 // AesCBCDecrypt 解密 39 func AesCBCDecrypt(cipherText, key, iv []byte) ([]byte, error) { 40 41 // 创建一个cipher.Block。参数key为密钥,长度只能是16、24、32字节,用以选择AES-128、AES-192、AES-256 42 block, err := aes.NewCipher(key) 43 if err != nil { 44 return nil, err 45 } 46 47 // 返回一个密码分组链接模式的、底层用b解密的cipher.BlockMode,初始向量iv必须和加密时使用的iv相同 48 blockMode := cipher.NewCBCDecrypter(block, iv) 49 50 // 根据 密文[]byte长度,初始化一个新的byte数组,返回byte数组内存地址 51 originText := make([]byte, len(cipherText)) 52 53 // 加密或解密连续的数据块,将解密内容存储到dst中,src需加密内容的长度必须是块大小的整数倍,src和dst可指向同一内存地址 54 blockMode.CryptBlocks(originText, cipherText) 55 56 // PKCS5反填充解密内容 57 originText = pKCS5UnPadding(originText) 58 return originText, nil 59 } 60 61 // AesCFBEncrypt 加密 62 func AesCFBEncrypt(originText, key, iv []byte) ([]byte, error) { 63 64 // 创建一个cipher.Block。参数key为密钥,长度只能是16、24、32字节,用以选择AES-128、AES-192、AES-256 65 block, err := aes.NewCipher(key) 66 if err != nil { 67 return nil, err 68 } 69 70 // 根据 需加密内容[]byte长度,初始化一个新的byte数组,返回byte数组内存地址 71 cipherText := make([]byte, aes.BlockSize+len(originText)) 72 73 // 返回一个密码反馈模式的、底层用block加密的cipher.Stream,初始向量iv的长度必须等于block的块尺寸 74 stream := cipher.NewCFBEncrypter(block, iv) 75 76 // 从加密器的key流和src中依次取出字节二者xor后写入dst,src和dst可指向同一内存地址 77 // cipherText[:aes.BlockSize]为iv值,所以只写入cipherText后面部分 78 stream.XORKeyStream(cipherText[aes.BlockSize:], originText) 79 80 return cipherText, nil 81 } 82 83 // AesCFBDecrypt 解密 84 func AesCFBDecrypt(cipherText, key, iv []byte) ([]byte, error) { 85 86 // 创建一个cipher.Block。参数key为密钥,长度只能是16、24、32字节,用以选择AES-128、AES-192、AES-256 87 block, err := aes.NewCipher(key) 88 if err != nil { 89 return nil, err 90 } 91 92 if len(cipherText) < aes.BlockSize { 93 return nil, errors.New("cipherText too short") 94 } 95 96 // 只使用cipherText除去iv部分 97 cipherText = cipherText[aes.BlockSize:] 98 99 // 返回一个密码反馈模式的、底层用block解密的cipher.Stream,初始向量iv必须和加密时使用的iv相同 100 stream := cipher.NewCFBDecrypter(block, iv) 101 102 // 从加密器的key流和src中依次取出字节二者xor后写入dst,src和dst可指向同一内存地址 103 stream.XORKeyStream(cipherText, cipherText) 104 105 return cipherText, nil 106 } 107 108 // AesCTREncrypt 加密 109 func AesCTREncrypt(originText, key, iv []byte) ([]byte, error) { 110 111 // 创建一个cipher.Block。参数key为密钥,长度只能是16、24、32字节,用以选择AES-128、AES-192、AES-256 112 block, err := aes.NewCipher(key) 113 if err != nil { 114 return nil, err 115 } 116 117 // 根据 需加密内容[]byte长度,初始化一个新的byte数组,返回byte数组内存地址 118 cipherText := make([]byte, aes.BlockSize+len(originText)) 119 120 // 返回一个计数器模式的、底层采用block生成key流的cipher.Stream,初始向量iv的长度必须等于block的块尺寸 121 stream := cipher.NewCTR(block, iv) 122 123 // 从加密器的key流和src中依次取出字节二者xor后写入dst,src和dst可指向同一内存地址 124 // cipherText[:aes.BlockSize]为iv值,所以只写入cipherText后面部分 125 stream.XORKeyStream(cipherText[aes.BlockSize:], originText) 126 127 return cipherText, nil 128 } 129 130 // AesCTRDecrypt 解密 131 func AesCTRDecrypt(cipherText, key, iv []byte) ([]byte, error) { 132 133 // 创建一个cipher.Block。参数key为密钥,长度只能是16、24、32字节,用以选择AES-128、AES-192、AES-256 134 block, err := aes.NewCipher(key) 135 if err != nil { 136 return nil, err 137 } 138 139 // 只使用cipherText除去iv部分 140 cipherText = cipherText[aes.BlockSize:] 141 142 // 返回一个计数器模式的、底层采用block生成key流的cipher.Stream,初始向量iv的长度必须等于block的块尺寸 143 stream := cipher.NewCTR(block, iv) 144 145 // 从加密器的key流和src中依次取出字节二者xor后写入dst,src和dst可指向同一内存地址 146 stream.XORKeyStream(cipherText, cipherText) 147 148 return cipherText, nil 149 } 150 151 // AesGCMEncrypt 加密 152 func AesGCMEncrypt(originText, key, nonce []byte) ([]byte, error) { 153 154 // 创建一个cipher.Block。参数key为密钥,长度只能是16、24、32字节,用以选择AES-128、AES-192、AES-256 155 block, err := aes.NewCipher(key) 156 if err != nil { 157 return nil, err 158 } 159 160 // 函数用迦洛瓦计数器模式包装提供的128位Block接口,并返回cipher.AEAD 161 g, err := cipher.NewGCM(block) 162 if err != nil { 163 return nil, err 164 } 165 166 // 返回加密结果。认证附加的additionalData,将加密结果添加到dst生成新的加密结果,nonce的长度必须是NonceSize()字节,且对给定的key和时间都是独一无二的 167 cipherText := g.Seal(nil, nonce, originText, nil) 168 169 return cipherText, nil 170 } 171 172 // AesGCMDecrypt 解密 173 func AesGCMDecrypt(cipherText, key, nonce []byte) ([]byte, error) { 174 175 // 创建一个cipher.Block。参数key为密钥,长度只能是16、24、32字节,用以选择AES-128、AES-192、AES-256 176 block, err := aes.NewCipher(key) 177 if err != nil { 178 return nil, err 179 } 180 181 // 函数用迦洛瓦计数器模式包装提供的128位Block接口,并返回cipher.AEAD 182 astc, err := cipher.NewGCM(block) 183 if err != nil { 184 return nil, err 185 } 186 187 // 返回解密结果。认证附加的additionalData,将解密结果添加到dst生成新的加密结果,nonce的长度必须是NonceSize()字节,nonce和data都必须和加密时使用的相同 188 return astc.Open(nil, nonce, cipherText, nil) 189 } 190 191 // AesOFBEncrypt 加密 192 func AesOFBEncrypt(originText, key, iv []byte) ([]byte, error) { 193 194 // 创建一个cipher.Block。参数key为密钥,长度只能是16、24、32字节,用以选择AES-128、AES-192、AES-256 195 block, err := aes.NewCipher(key) 196 if err != nil { 197 return nil, err 198 } 199 200 // 根据 需加密内容[]byte长度,初始化一个新的byte数组,返回byte数组内存地址 201 cipherText := make([]byte, aes.BlockSize+len(originText)) 202 203 // 返回一个输出反馈模式的、底层采用b生成key流的cipher.Stream,初始向量iv的长度必须等于b的块尺寸 204 stream := cipher.NewOFB(block, iv) 205 206 // 从加密器的key流和src中依次取出字节二者xor后写入dst,src和dst可指向同一内存地址 207 // cipherText[:aes.BlockSize]为iv值,所以只写入cipherText后面部分 208 stream.XORKeyStream(cipherText[aes.BlockSize:], originText) 209 210 return cipherText, nil 211 } 212 213 // AesOFBDecrypt 解密 214 func AesOFBDecrypt(cipherText, key, iv []byte) ([]byte, error) { 215 216 // 创建一个cipher.Block。参数key为密钥,长度只能是16、24、32字节,用以选择AES-128、AES-192、AES-256 217 block, err := aes.NewCipher(key) 218 if err != nil { 219 return nil, err 220 } 221 222 // 只使用cipherText除去iv部分 223 cipherText = cipherText[aes.BlockSize:] 224 225 // 返回一个输出反馈模式的、底层采用b生成key流的cipher.Stream,初始向量iv的长度必须等于b的块尺寸 226 stream := cipher.NewOFB(block, iv) 227 228 // 从加密器的key流和src中依次取出字节二者xor后写入dst,src和dst可指向同一内存地址 229 stream.XORKeyStream(cipherText, cipherText) 230 231 return cipherText, nil 232 } 233 234 // AesOFBEncryptStreamReader 加密 235 func AesOFBEncryptStreamReader(originText, key, iv []byte) ([]byte, error) { 236 237 // 创建一个cipher.Block。参数key为密钥,长度只能是16、24、32字节,用以选择AES-128、AES-192、AES-256 238 block, err := aes.NewCipher(key) 239 if err != nil { 240 return nil, err 241 } 242 243 // 返回一个输出反馈模式的、底层采用b生成key流的cipher.Stream,初始向量iv的长度必须等于b的块尺寸 244 stream := cipher.NewOFB(block, iv) 245 246 // 初始化cipher.StreamReader。将一个cipher.Stream与一个io.Reader关联起来,Read方法会调用XORKeyStream方法来处理获取的所有切片 247 reader := &cipher.StreamReader{ 248 S: stream, 249 R: bytes.NewReader(originText), 250 } 251 252 return io.ReadAll(reader) 253 } 254 255 // AesOFBDecryptStreamWriter 解密 256 func AesOFBDecryptStreamWriter(cipherText, key, iv []byte) ([]byte, error) { 257 258 // 创建一个cipher.Block。参数key为密钥,长度只能是16、24、32字节,用以选择AES-128、AES-192、AES-256 259 block, err := aes.NewCipher(key) 260 if err != nil { 261 return nil, err 262 } 263 264 // 返回一个输出反馈模式的、底层采用b生成key流的cipher.Stream,初始向量iv的长度必须等于b的块尺寸 265 stream := cipher.NewOFB(block, iv) 266 267 // 声明buffer 268 var originText bytes.Buffer 269 270 // 初始化cipher.StreamWriter。将一个cipher.Stream与一个io.Writer接口关联起来,Write方法会调用XORKeyStream方法来处理提供的所有切片 271 // 如果Write方法返回的n小于提供的切片的长度,则表示StreamWriter不同步,必须丢弃。StreamWriter没有内建的缓存,不需要调用Close方法去清空缓存 272 writer := &cipher.StreamWriter{ 273 S: stream, 274 W: &originText, 275 } 276 277 // 把reader内容拷贝到writer, writer会调用write方法写入内容 278 if _, err = io.Copy(writer, bytes.NewReader(cipherText)); err != nil { 279 return nil, err 280 } 281 282 return originText.Bytes(), nil 283 }