通过Golang编写一个AES加密解密工具
来源:脚本之家
时间:2022-12-30 14:42:32 373浏览 收藏
在Golang实战开发的过程中,我们经常会遇到一些这样那样的问题,然后要卡好半天,等问题解决了才发现原来一些细节知识点还是没有掌握好。今天golang学习网就整理分享《通过Golang编写一个AES加密解密工具》,聊聊加密、解密、AES,希望可以帮助到正在努力赚钱的你。
AES加密介绍及实现原理
Go实现AES加密和解密工具
AES加密介绍及实现原理
AES( advanced encryption standard)使用相同密钥进行加密和解密,也就是对称加密。其他的对称加密如DES,由于DES密钥长度只有56位如今的算力甚至可以在5分钟内破解,而AES最高级别达到了256位密钥长度,如果采用穷举法,目前来看AES是一种”无法“被破解的加密存在。
AES用在哪里
如果你正在浏览本文,那么你就在使用AES(https协议中一部分使用了对称加密)。
- 绿色上网:通过加密安全地连接到另一台搬石头砸脚的服务器。
- 无线网络WIFI:和WAP2一起使用。
- 应用程序:wechat、JD、Alipay等使用 AES 加密照片和消息或支付信息。
- 存档和压缩工具:7z、WinZip 和 RAR。
- 操作系统组件:一些操作系统组件(如文件系统)使用高级加密标准来确保安全性。
- 编程语言库: Go、Python 和 C++ 等编码库实现了的AES加密(等会使用到)。
AES加密是如何实现的
参考:
What is AES encryption and how does it work?
Block cipher mode of operation
从宏观上来看AES加密过程中的一轮(根据不同的密钥长度,轮数不一样,下面会说到)如下:
1.数据分块
首先把明文按照128bit拆分成若干个明文块(图上黄色块),一个字节包含 8 位,布局为 4×4矩阵(上图黄色部分),对最后一块填充至128bit,填充方式有PKCS7Padding(采用)/PKCS5Padding/ZeroPadding,无论咋填充最后解密时都要去除这些多余的填充。
2.密钥扩展
AES通过Rijndael's key schedule 将密钥被扩展为 (n+1) 个密钥,其中 n 是加密过程中要遵循的轮数。AES每个标准规定了所要加密的轮数,对于128位密钥,轮数是 10,要生成的密钥个数为 10+1,总共 11 个密钥。
标准 | 密钥长度 | 轮数 | 分组长度 |
---|---|---|---|
AES-128 | 128位(16字节) | 10 | 128位(16字节) |
AES-192 | 192位(24字节) | 12 | 128位(16字节) |
AES-256 | 256位(32字节) | 14 | 128位(16字节) |
每一轮所要做的包括:字节替代(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)、加轮密钥(AddRoundKey)
3.字节替代(SubBytes)
每轮开始,首先进行SubBytes,字节根据预定义的 Rijndael S-box(可以简单认为是一个转换表)规定的规则进行替换。对a[i,j]中的每个字节进行一次转换后得到b[i,j]
4.行移位(ShiftRows)
对上一步得到矩阵进行ShiftRows,第一行不变,第二行移动1位,第三行2位,第四行3位。
5.列混淆(MixColumns)
再对矩阵的每一列和修补矩阵fixed matrix的二维常量数组做矩阵相乘,得到对应的输出列。
6.加轮密钥(AddRoundKey)
先将扩展密钥Kn排列成4×4矩阵,然后让输入数组的每一个字节a[i,j]与密钥对应位置的字节k[i,j]异或一次,得到输出b[i,j]。最后一轮不参与AddRoundKey
经过如上的10轮操作之后,得到了一个明文块的加密字符。解密则进行反向加密。
AES加密模式
ECB
在上面加密过程中每一个明文块都是独立进行加密的,简单且高效,但是如果一个段数据存在相关的明文块,则加密后的密文也会相同,对安全性也有一定影响。
CBC
CBC加密模式如下图所示,初始向量IV和明文异或,每个块的密文作为后续块的“向量”,让每一个密文独一无二。我们待会采用这种模式。
Go实现AES加密工具scode
ok,上面大致了解AES加密是如何工作起来的,接下来通过Go中的crypto/aes和crypto/cipher包实现的AES加密解密工具。
PKCS7Padding将待补足字节数作为填充的字节
// pkcs7Padding 填充 func pkcs7Padding(data []byte, blockSize int) []byte { //判断缺少几位长度。最少1,最多 blockSize padding := blockSize - len(data)%blockSize //补足位数。把切片[]byte{byte(padding)}复制padding个 padText := bytes.Repeat([]byte{byte(padding)}, padding) return append(data, padText...) } // pkcs7UnPadding 移除 func pkcs7UnPadding(data []byte) ([]byte, error) { length := len(data) if length == 0 { return nil, errors.New("加密字符串错误!") } //获取填充的个数 unPadding := int(data[length-1]) return data[:(length - unPadding)], nil }
使用 cipher的CBC模式对block加密和解密
// AesEncrypt 加密 func AesEncrypt(data []byte, key []byte) ([]byte, error) { // NewCipher creates and returns a new cipher.Block. The key argument should be the AES key, either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256. block, err := aes.NewCipher(key) if err != nil { return nil, err } //判断加密快的大小 blockSize := block.BlockSize() //填充 encryptBytes := pkcs7Padding(data, blockSize) //初始化加密数据接收切片 crypted := make([]byte, len(encryptBytes)) //使用cbc加密模式 blockMode := cipher.NewCBCEncrypter(block, key[:blockSize]) //执行加密 blockMode.CryptBlocks(crypted, encryptBytes) return crypted, nil } // AesDecrypt 解密 func AesDecrypt(data []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } //获取块的大小 blockSize := block.BlockSize() //使用cbc blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) //初始化解密数据接收切片 crypted := make([]byte, len(data)) //执行解密 blockMode.CryptBlocks(crypted, data) //去填充 crypted, err = pkcs7UnPadding(crypted) if err != nil { return nil, err } return crypted, nil }
循环从文件中读取100mb源数据用于加密后将密文写入文件,解密则读取密文解密后将源数据写入文件。
func EncryptFile(fileName string) (err error) { f, err := os.Open(fileName) if err != nil { fmt.Println("未找到文件") return } defer f.Close() fInfo, _ := f.Stat() fLen := fInfo.Size() fmt.Println("待处理文件大小:", fLen) maxLen := 1024 * 1024 * 100 //100mb 每 100mb 进行加密一次 var forNum int64 = 0 getLen := fLen if fLen > int64(maxLen) { getLen = int64(maxLen) forNum = fLen / int64(maxLen) fmt.Println("需要加密次数:", forNum+1) } // encryptd to file ff, err := os.OpenFile("en_"+fileName, os.O_RDWR|os.O_CREATE, 0666) if err != nil { fmt.Println("文件写入错误") return err } defer ff.Close() //循环加密,并写入文件 for i := 0; i参考:Golang实现AES加密和解密的示例代码
通过cobra添加命令后,创建命令的匿名函数
func(cmd *cobra.Command, args []string) { copy(PwdKey, readPass()) Pwd := []byte("csgo!gogo") if ByteSliceEqual(PwdKey, Pwd) { //16字节key PwdKey = append(PwdKey, 7, 3, 5, 5, 6, 0, 8) if err := DecryptFile(args[0]); err != nil { panic(err) } } else { fmt.Println("密码错误") os.Exit(1) } }使用方式看起来如下:
scode工具包含2个命令encode和decode,解密文件需要密码。
# ./scode encode xpower.tar.gz 待处理文件大小: 3397 加密后文件为:en_xpower.tar.gz,文件大小为:4545 Byte # ./scode decode en_xpower.tar.gz ENTER PASSWORD: 密码错误 # ./scode decode en_xpower.tar.gz ENTER PASSWORD: 待处理文件大小: 4545 解密后文件为:de_en_xpower.tar.gz,文件大小为:3159 Byte完整代码:source
以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于Golang的相关知识,也可关注golang学习网公众号。
-
319 收藏
-
327 收藏
-
322 收藏
-
307 收藏
-
385 收藏
-
419 收藏
-
234 收藏
-
155 收藏
-
457 收藏
-
309 收藏
-
225 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 欢喜的导师
- 这篇博文真是及时雨啊,太全面了,受益颇多,码住,关注博主了!希望博主能多写Golang相关的文章。
- 2023-02-14 12:51:51
-
- 傻傻的舞蹈
- 很有用,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢师傅分享技术文章!
- 2023-02-06 08:45:44
-
- 包容的鼠标
- 写的不错,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢作者分享文章内容!
- 2023-02-01 22:26:22
-
- 强健的镜子
- 太细致了,码起来,感谢作者的这篇技术文章,我会继续支持!
- 2023-01-24 17:48:55
-
- 粗暴的小懒猪
- 这篇文章内容真是及时雨啊,很详细,很有用,已收藏,关注作者大大了!希望作者大大能多写Golang相关的文章。
- 2023-01-23 13:43:03
-
- 开放的万宝路
- 这篇文章内容出现的刚刚好,老哥加油!
- 2023-01-23 03:02:51
-
- 坚定的棒棒糖
- 太详细了,已加入收藏夹了,感谢作者的这篇博文,我会继续支持!
- 2023-01-20 01:50:01
-
- 忧伤的路人
- 真优秀,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢up主分享文章内容!
- 2023-01-17 15:04:29
-
- 玩命的台灯
- 太给力了,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢博主分享博文!
- 2023-01-16 18:18:06
-
- 朴实的玉米
- 这篇博文出现的刚刚好,博主加油!
- 2023-01-10 07:05:39
-
- 机智的鸡
- 这篇技术文章出现的刚刚好,很详细,很棒,收藏了,关注up主了!希望up主能多写Golang相关的文章。
- 2023-01-09 06:21:39
-
- 哭泣的小蚂蚁
- 太全面了,已加入收藏夹了,感谢老哥的这篇博文,我会继续支持!
- 2023-01-06 05:54:14
-
- 愤怒的樱桃
- 这篇技术贴真是及时雨啊,细节满满,很好,收藏了,关注师傅了!希望师傅能多写Golang相关的文章。
- 2023-01-02 19:00:24