golang实现AES有五种加密模式函数,Encrypt加解密字符串输出

/*
   AES有五种加密模式
       电码本模式(Electronic Codebook Book (ECB))、
   密码分组链接模式(Cipher Block Chaining (CBC))、
   计算器模式(Counter (CTR))、
   密码反馈模式(Cipher FeedBack (CFB))
   输出反馈模式(Output FeedBack (OFB))
*/
package libs

import (
   "bytes"
   "crypto/aes"
   "crypto/cipher"
   "encoding/base64"
   "encoding/hex"
   "strings"
   "errors"
)
/***************CBC加密***************************
func main() {
   orig := "hello world"
   key := "0123456789012345"
   fmt.Println("原文:", orig)
   encryptCode := AesEncryptCBC(orig, key)
   fmt.Println("密文:" , encryptCode)
   decryptCode := AesDecryptCBC(encryptCode, key)
   fmt.Println("解密结果:", decryptCode)
}
**************************************************/
func AesEncryptCBC(orig string, key string) string {
   // 转成字节数组
   origData := []byte(orig)
   k := []byte(key)
   // 分组秘钥
   // NewCipher该函数限制了输入k的长度必须为16, 24或者32
   block, _ := aes.NewCipher(k)
   // 获取秘钥块的长度
   blockSize := block.BlockSize()
   // 补全码
   origData = PKCS7Padding(origData, blockSize)
   // 加密模式
   blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
   // 创建数组
   cryted := make([]byte, len(origData))
   // 加密
   blockMode.CryptBlocks(cryted, origData)
   return base64.StdEncoding.EncodeToString(cryted)
}
func AesDecryptCBC(cryted string, key string) string {
   // 转成字节数组
   crytedByte, _ := base64.StdEncoding.DecodeString(cryted)
   k := []byte(key)
   // 分组秘钥
   block, _ := aes.NewCipher(k)
   // 获取秘钥块的长度
   blockSize := block.BlockSize()
   // 加密模式
   blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
   // 创建数组
   orig := make([]byte, len(crytedByte))
   // 解密
   blockMode.CryptBlocks(orig, crytedByte)
   // 去补全码
   orig = PKCS7UnPadding(orig)
   return string(orig)
}
//补码
//AES加密数据块分组长度必须为128bit(byte[16]),密钥长度可以是128bit(byte[16])、192bit(byte[24])、256bit(byte[32])中的任意一个。
func PKCS7Padding(ciphertext []byte, blocksize int) []byte {
   padding := blocksize - len(ciphertext)%blocksize
   padtext := bytes.Repeat([]byte{byte(padding)}, padding)
   return append(ciphertext, padtext...)
}
//去码
func PKCS7UnPadding(origData []byte) []byte {
   length := len(origData)
   unpadding := int(origData[length-1])
   return origData[:(length - unpadding)]
}


/***************AESEncryptECBStr加解密案列*********
func main() {
   source:="asdasadgsdhfasf"
   fmt.Println("原字符:",source)
   //16byte密钥
   key:="sdddd"

   encryptCode:=AESEncryptECBStr(source,key)
   fmt.Println("密文:",encryptCode)
   decryptCode:=AESDecryptECBStr(encryptCode,key)
   fmt.Println("解密:",decryptCode)
}
**************************************************/
func AESEncryptECBStr(source string, keys string)  string {
   // 字符串转换成切片
   src := []byte(source)
   key := []byte(keys)
   cipher, _ := aes.NewCipher(generateKeys(key))
   length := (len(src) + aes.BlockSize) / aes.BlockSize
   plain := make([]byte, length*aes.BlockSize)
   copy(plain, src)
   pad := byte(len(plain) - len(src))
   for i := len(src); i < len(plain); i++ {
      plain[i] = pad
   }
   encrypted := make([]byte, len(plain))
   // 分组分块加密
   for bs, be := 0, cipher.BlockSize(); bs <= len(src); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
      cipher.Encrypt(encrypted[bs:be], plain[bs:be])
   }

   //return encrypted
   encryptstr :=strings.ToUpper(hex.EncodeToString(encrypted))
   return encryptstr
}

func AESDecryptECBStr(encrypteds string, keys string) string {
   // 字符串转换成切片
   //encrypted := []byte(encrypteds)
   encrypted, _ := hex.DecodeString(encrypteds)
   key := []byte(keys)

   cipher, _ := aes.NewCipher(generateKeys(key))
   decrypted := make([]byte, len(encrypted))
   //
   for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
      cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
   }

   trim := 0
   if len(decrypted) > 0 {
      trim = len(decrypted) - int(decrypted[len(decrypted)-1])
   }
   return  string(decrypted[:trim])
}

func generateKeys(key []byte) (genKey []byte) {
   genKey = make([]byte, 16)
   copy(genKey, key)
   for i := 16; i < len(key); {
      for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
         genKey[j] ^= key[i]
      }
   }
   return genKey
}

// 为了方便,声明该函数,省去错误处理

// 测试解码
//const testStr = "R2/or63oqIDnvJbnqIs="
//str :=mustDecode(base64.StdEncoding,testStr)    // 打印:R2/or63oqIDnvJbnqIs=
//fmt.Println(str)

func Base64DecodeStr(enc *base64.Encoding, str string) string {
   data, err := enc.DecodeString(str)
   if err != nil {
      panic(err)
   }
   return string(data)
}

// 该函数测试编解码
// enc为要测试的Encoding对象,str为要测试的字符串
//const testStr = "Go语言编程"

// 测试StdEncoding,注意打印结果里的/为URL中的特殊字符,最后有一个padding,mysql的base64加密
//testEncoding(base64.StdEncoding, testStr)    // 打印:R2/or63oqIDnvJbnqIs=

 测试URLEncoding,可以看到/被替换为_
//testEncoding(base64.URLEncoding, testStr)    // 打印:R2_or63oqIDnvJbnqIs=
//
 测试RawStdEncoding,可以看到去掉了padding
//testEncoding(base64.RawStdEncoding, testStr) // 打印:R2/or63oqIDnvJbnqIs
//
 测试RawURLEncoding,可以看到/被替换Wie_,并且却掉了padding
//testEncoding(base64.RawURLEncoding, testStr) // 打印:R2_or63oqIDnvJbnqIs
func Base64EncodeStr(enc *base64.Encoding, str string) string {
   // 编码
   encStr := enc.EncodeToString([]byte(str))
   // 解码
   decStr := Base64DecodeStr(enc, encStr)
   if decStr != str {  // 编码后再解码应该与原始字符串相同
      // 这里判断如果不同,则panic
      panic(errors.New("unequal!"))
   }
   return encStr
}

/**************************加密介绍
mysql的AES_DECRYPT方法,欲使用golang实现该方法, 但是研究发现golang当前默认支持CBC的方式,但是mysql当前使用的是ECB模式,
SELECT HEX(AES_ENCRYPT('hello world', '1443flfsaWfdas'));
SELECT AES_DECRYPT(UNHEX('ef845a0501a6f76da2de6fba84546f8b'),'1443flfsaWfdas')
Go语言的string模块包含了ToLower和ToUpper函数,用于将字符串转换成小写和大写,mysql都是返回大写

对称加密, 加解密都使用的是同一个密钥, 其中的代表就是AES
非对加解密, 加解密使用不同的密钥, 其中的代表就是RSA
签名算法, 如MD5、SHA1、HMAC等, 主要用于验证,防止信息被修改, 如:文件校验、数字签名、鉴权协议

AES:高级加密标准(Advanced Encryption Standard),又称Rijndael加密法,这个标准用来替代原先的DES。
AES加密数据块分组长度必须为128bit(byte[16]),密钥长度可以是128bit(byte[16])、192bit(byte[24])、256bit(byte[32])中的任意一个。

块:对明文进行加密的时候,先要将明文按照128bit进行划分。

填充方式:因为明文的长度不一定总是128的整数倍,所以要进行补位,我们这里采用的是PKCS7填充方式

AES实现的方式多样, 其中包括ECB、CBC、CFB、OFB等

1.电码本模式(Electronic Codebook Book (ECB))
将明文分组加密之后的结果直接称为密文分组。

2.密码分组链接模式(Cipher Block Chaining (CBC))
将明文分组与前一个密文分组进行XOR运算,然后再进行加密。每个分组的加解密都依赖于前一个分组。而第一个分组没有前一个分组,
因此需要一个初始化向量

3.计算器模式(Counter (CTR))

4.密码反馈模式(Cipher FeedBack (CFB))
前一个密文分组会被送回到密码算法的输入端。
在CBC和EBC模式中,明文分组都是通过密码算法进行加密的。而在CFB模式中,明文分组并没有通过加密算法直接进行加密,
明文分组和密文分组之间只有一个XOR。

加密模式   对应加解密方法
CBC       NewCBCDecrypter, NewCBCEncrypter
CTR       NewCTR
CFB       NewCFBDecrypter, NewCFBEncrypter
OFB       NewOFB
 ***********************************/
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个使用golang中的crypto库进行AES GCM模式加密文件的示例代码: ```go package main import ( "crypto/aes" "crypto/cipher" "crypto/rand" "fmt" "io" "io/ioutil" "os" ) func main() { // 读取原始文件 data, err := ioutil.ReadFile("plaintext.txt") if err != nil { panic(err) } // 随机生成16字节的密钥 key := make([]byte, 16) if _, err := io.ReadFull(rand.Reader, key); err != nil { panic(err) } // 创建GCM加密器 block, err := aes.NewCipher(key) if err != nil { panic(err) } aesgcm, err := cipher.NewGCM(block) if err != nil { panic(err) } // 随机生成12字节的IV iv := make([]byte, 12) if _, err := io.ReadFull(rand.Reader, iv); err != nil { panic(err) } // 使用GCM加密数据 ciphertext := aesgcm.Seal(nil, iv, data, nil) // 将密钥和IV写入文件开头 output := append(key, iv...) // 将加密数据写入文件尾部 output = append(output, ciphertext...) // 将加密结果写入文件 err = ioutil.WriteFile("ciphertext.bin", output, 0644) if err != nil { panic(err) } fmt.Println("Encryption complete.") } ``` 这个示例代码中,我们首先读取要加密的文件的内容。然后,我们使用crypto库中提供的`aes.NewCipher`函数创建一个AES加密器,并使用这个加密器创建一个GCM加密器。接下来,我们随机生成一个16字节的密钥和一个12字节的IV,然后使用GCM加密器对原始数据进行加密。最后,我们将密钥和IV写入加密文件的开头,将加密数据写入文件的尾部。 注意,在实际应用中,我们应该使用更加安全的方式来生成密钥和IV,例如使用密码学安全的伪随机数生成器。此外,我们也应该对加密文件进行适当的保护,例如使用密码或者其他的访问控制措施。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值