通过Go实现AES加密和解密工具
本文包含如下两个内容:
- AES加密介绍及实现原理
- Go实现AES加密和解密工具
AES加密介绍及实现原理
AES( advanced encryption standard)使用相同密钥进行加密和解密,也就是对称加密。其他的对称加密如DES,由于DES密钥长度只有56位如今的算力甚至可以在5分钟内破解,而AES最高级别达到了256位密钥长度,如果采用穷举法,目前来看AES是一种”无法“被破解的加密存在。
关于非对称加密我们在之前有一篇文章《理解https中的安全及其实现原理》进行了介绍,有兴趣的可翻看查看。
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 < int(forNum+1); i++ {
a := make([]byte, getLen)
n, err := f.Read(a)
if err != nil {
fmt.Println("文件读取错误")
return err
}
getByte, err := EncryptByAes(a[:n])
if err != nil {
fmt.Println("加密错误")
return err
}
getBytes := append([]byte(getByte), []byte("\n")...)
//写入
buf := bufio.NewWriter(ff)
buf.WriteString(string(getBytes[:]))
buf.Flush()
}
ffInfo, _ := ff.Stat()
fmt.Printf("加密后文件为:%s,文件大小为:%v Byte \n", ffInfo.Name(), ffInfo.Size())
return nil
}
通过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
通过博客查看:iqsing.github.io
通过改进此工具创建一个自己隐私文件加密和解密器。
通过Go实现AES加密和解密工具的更多相关文章
- AES加密、解密工具类
AES加密.解密工具类代码如下: package com.util; import java.io.IOException; import java.io.UnsupportedEncodingExc ...
- java独立小程序实现AES加密和解密
一.需求: web项目中配置文件配置的密码是明文的, 现在需要修改成密文, 加密方式采用AES, 于是写了个工具类用于加密和解密. 又因为这个密码是由客户来最终确定, 所以为了部署时方便起见, 写了个 ...
- java与C#、.NET AES加密、解密 解决方案
1.情景展示 Java提供的密钥,C#无法解密. 2.原因分析 在Java中,AES的实际密钥需要用到KeyGenerator 和 SecureRandom,但是C#和.NET 里面没有这2个类, ...
- java AES加密、解密(兼容windows和linux)
java AES加密.解密 CreationTime--2018年7月14日10点06分 Author:Marydon 1.准备工作 updateTime--2018年8月10日15点28分 up ...
- Php AES加密、解密与Java互操作的问题
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...
- 【Java】通过DES加密和解密工具,对字符串进行加密和解密操作
分享一个非常不错的字符串加密和解密的程序. 可以指定不同的密钥对同一字符串进行不同的加密操作,增强加密性能. Java代码如下: package com.app; import java.securi ...
- 探讨数据进行AES加密和解密以及.NET Core对加密和解密为我们提供了什么?
前言 对于数据加密和解密每次我都是从网上拷贝一份,无需有太多了解,由于在.net core中对加密和解密目前全部是统一了接口,只是做具体的实现,由于遇到过问题,所以将打算基本了解下其原理,知其然足矣, ...
- 探讨.NET Core中实现AES加密和解密以及.NET Core为我们提供了什么方便!
前言 对于数据加密和解密每次我都是从网上拷贝一份,无需有太多了解,由于在.net core中对加密和解密目前全部是统一了接口,只是做具体的实现,由于遇到过问题,所以将打算基本了解下其原理,知其然足矣, ...
- Oracle的AES加密与解密用法
Oracle的AES加密与解密用法2013年12月11日 11:50:35 iteye_751 阅读数:428--加密字符串create or replace function des3_enc( i ...
随机推荐
- Spring MVC 框架有什么用?
Spring Web MVC 框架提供 模型-视图-控制器 架构和随时可用的组件,用于开 发灵活且松散耦合的 Web 应用程序.MVC 模式有助于分离应用程序的不同方 面,如输入逻辑,业务逻辑和 UI ...
- 学习FastDfs(四)
1.简介 FastDFS 是一个开源的高性能分布式文件系统(DFS). 它的主要功能包括:文件存储,文件同步和文件访问,以及高容量和负载平衡.主要解决了海量数据存储问题,特别适合以中小文件(建议范围: ...
- Java根路径设置(在获取本地路径时会获取到这个文件夹,,这样就可以专门放配置文件了)
在获取本地路径时会获取到这个文件夹,,这样就可以专门放配置文件了
- (stm32f103学习总结)—独立看门狗(IWDG)
一.IWDG介绍 1.1 IWDG简介 STM32F1芯片内部含有两个看门狗外设,一个是独立看门狗IWDG,另 一个是窗口看门狗WWDG.两个看门狗外设(独立和窗口)均可用于检测 并解决由软件错误导致 ...
- 一个让我很不爽的外包项目——奔驰Smart2015新官网
七月份的下半个月,有幸做了奔驰 Smart 2015年新官网,包括手机端和PC端的宣传页,地址: PC端 手机端 这里,为了证明这个是一个事实,我还特意的留存了两张截图: 这里只想说明这么几个问题: ...
- PAT B1013 数素数
输入样例: 5 27 输出样例: 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 解题思路: 从2开始 ...
- 彻底理解synchronized
1. synchronized简介 在学习知识前,我们先来看一个现象: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public ...
- Servlet实现登录注册
1.注册页面register.html <!DOCTYPE html> <html lang="en"> <head> <meta cha ...
- SpringMVC的数据响应方式-页面跳转
1.返回字符串形式 直接返回字符串:此种方式会返回字符串与视图解析器的前后缀拼接后跳转 有关视图解析器的拼接请访问此地址 注意:WEB-INF下的资源一般不能访问,因为转发是服务器的操作所以可以访问到 ...
- 帝国CMS后台采集关键字的方法
小伙伴们知道帝国CMS后台的采集功能是不能采集关键字的,那么老墨今天给大家说一个变通方法,让后台能采集关键字!方法如下: 1.系统设置--管理数据表--管理字段--增加字段(字段名:keywords字 ...