关于加密解密:加解密概要
单项散列算法MD5SHASM3(国产哈希算法)对称加密RC4(速度达DES的10倍)(最平安之一)TEA(分组加密算法)IDEA(基于DES)(美国之外)BlowFish(对称加密块算法)AES(代替原先的DES)SM4分组明码(中国政府采纳的分组明码规范)非对称加密(公钥私钥)RSAElGamal公钥算法(国内公认较现实的公钥明码体制)DSA数字签名椭圆曲线明码编码学SMI算法(国密局,是椭圆曲线公钥明码算法,较RSA先进)
单项散列算法MD5SHASM3(国产哈希算法)对称加密RC4(速度达DES的10倍)(最平安之一)TEA(分组加密算法)IDEA(基于DES)(美国之外)BlowFish(对称加密块算法)AES(代替原先的DES)SM4分组明码(中国政府采纳的分组明码规范)非对称加密(公钥私钥)RSAElGamal公钥算法(国内公认较现实的公钥明码体制)DSA数字签名椭圆曲线明码编码学SMI算法(国密局,是椭圆曲线公钥明码算法,较RSA先进)
指标APP:91短视频 之前发过一篇蚂蚁加速器刷邀请的文章,这次的APP就是和蚂蚁加速器一家的,加密算法根本一样,不提供下载。0x00 工具筹备Fiddler(代理抓包)Xposed(hook框架) Inspeckage(通用hook插件,备选算法助手)HEX编码转换(base64转HEX)雷电模拟器(雷电3绿化版)ProxyDroid(代理转发工具,用Gitee一键编译的)工具安装包及配置好的雷电模拟器零碎备份下载:https://lanzoui.com/b0eknupng 明码:4vpf各工具应用办法介绍等具体内容可参考各自文档或百度。 0x01 现实的剖析过程新建模拟器,装置好指标APP及工具,先不要关上指标APP。 1、用ProxyDroid解决抓不到包的问题关上ProxyDroid按下图示例填好代理服务器IP、端口,协定选HTTP(就算抓HTTPS,也选HTTP) 下滑能够抉择用全局代理还是分利用代理,这里间接全局代理了。 代理服务器IP、端口为Fiddler中的代理,默认8888端口,IP为局域网IP,在Fiddler右上角有如下所示的图标,能够在下面悬停鼠标,就会显示局域网地址,个别为192.168..。 2、用Inspeckage主动hook加密算法及hash关上Inspeckage,抉择指标APP,界面如下。 依据图中提醒转发8008端口到电脑,即在模拟器运行目录下关上cmd,再输出: '''adb forward tcp:8008 tcp:8008''' 此时在电脑浏览器中关上http://127.0.0.1:8008/即可看到Inspeckage网页界面。 点开设置,将不须要的都关掉,只留Crypto和Hash两个,关上主动刷新。 3、开始剖析工具都配置好后,关上指标APP,直到胜利绑定邀请码。(或者在开屏广告停留一下,查看Inspeckage的Crypto,出后果后敞开主动刷新,因为不晓得为什么这里会主动革除记录,偏偏刚启动会有个注册的包要用到。) 分析方法是依据Fiddler中数据包参数去Inspeckage中寻找对应的加解密输入输出。 点开绑定邀请码的包,绑定邀请码的时候看着Fiddler,很好确定是哪个包,不出意外的话就是指标域名在Fiddler中最下方倒数第二个。能够看到发送参数有3个,一个工夫戳,一个HEX格局的data,一个MD5的sign。在Inspeckage的Crypto中搜寻本人输出的邀请码,没搜到就把折叠起来的加密数据点开再搜,明文在前的是加密,base64在前的是解密。这里能够确定: 加密算法是AES,key是h3PV8o444kNybrx77icyiriQ2q0uTjqUSsFRfaynkT8=(base64编码),iv是DrRMfzwgpjgI1sIjfW8aXw==(base64编码),解密模式是AES/CFB/NoPadding,加密数据格式为{"mod":"user","build_id":"a1000","token":"","oauth_id":"xxxxx","oauth_type":"android","aff":"xxxxx","app_status":"xxxx:2","version":"4.5.5","apiV2":"v2","app_type":"local","code":"invitation"}把加密后果用HEX编码转换转为HEX,发现和data中去除前32个字符之后对的上。依据上一篇文章的教训,这32个字符应该是IV。把刚刚失去的iv即DrRMfzwgpjgI1sIjfW8aXw==转为HEX,发现正好和data前32位相等。这里能够确定:发送的data是iv与加密数据的HEX编码拼接而成。再用同样的办法,去Hash界面中搜抓到的sign,能够看到是一长串hash进行MD5加密。持续搜这一长串hash,发现正好是上面一条SHA256加密的后果。加密字符串格局为data={}xtamp={}132f1537f85sjdpcm59f7e318b9epa51这时候拿去验证SHA256,发现后果对不上。认真看一下,发现timestamp没齐全显示,预计出了点问题,手动补全为data={}×tamp={}132f1537f85sjdpcm59f7e318b9epa51,再次验证发现没问题了。加密的数据曾经差不多弄清楚了,那返回的data解密应该也是一样的。将后面失去的key和iv拿去解密,发现不对。这个时候依据后面的教训,猜想返data也是前32位为iv,前面为待解密数据,一试发现果然如此。因为各种AES加解密工具都把输入输出格局固定死了,很少有反对HEX或base64编码的输出以及key、iv,所以倡议写代码验证或者应用其余工具,或者手动转换编码再去用工具验证,这里是将待解密数据[HEX转为base64][],将key、iv转为HEX,再用工具验证到这里只看了绑定邀请码的包,当初再去看看注册的包,毕竟不注册没方法刷邀请。依据Fiddler中先后顺序,顺次将发包的data解密查看,后果没有发现注册字样,且多个data完全相同。所以能够猜想,要么是没抓到注册包,要么是这些数据包主动实现了注册。剖析局部到这里就能够完结了,有key、有iv、有加解密数据模板、有sign模板,能够间接写代码了。 4、怎么全是猜想?看到这里,我也纳闷,怎么都是猜的,间接剖析能猜到这些吗? 预计还真不好猜。 因为理论剖析过程并不是这么顺利,所以两头反编译看了源码,同时联合上一次剖析蚂蚁加速器的教训,所以很多货色都一眼看进去了,这两个APP加密基本相同。 如果有切实看不明确怎么猜到的,看一看上一篇蚂蚁加速器刷邀请的文章,外面有反编译剖析的局部。 0x02 理论剖析过程这里应用雷电3,即安卓5,因为安卓7装置证书麻烦。绿化版来自派大星模拟器多开助手网站。 开局先抓包,关上Fiddler、模拟器中设置好代理、装置证书、关上APP。 一顿操作猛如虎,一看后果啥也没有,而且APP能失常关上失常应用。这时候就能够猜想,APP禁用了代理。 个别防抓包措施自行理解。抓不到包的时候,如果APP闪退或者不能拜访网络,则有可能是检测了代理;如果APP失常应用,那应该是禁用了代理。 这里能够应用抓包精灵、小黄鸟等手机端的抓包工具,或者用代理工具转发流量到Fiddler,因为手机端不不便操作,所以这里用ProxyDroid来转发流量。 用其余工具能够,比方Drony、Postern、socksdroid,不过我举荐用ProxyDroid,代理模式齐全,设置过程简略明确。 用了代理工具,后果还是没有抓到想要的包,有点不对劲,我开始狐疑它不是HTTP协定,可能用了ws或者tcp。 这里就没脉络了,所以只能去看Inspeckage的后果,而后反编译(没加壳)找算法,找半天找到了。这个时候能够用frida取hook到后果了,然而我还是想试试能不能抓到包。 之后陆续尝试了用Inspeckage增加代理、用socks代理,都没胜利。 最初无心中发现,新建模拟器后第一次关上这个APP的时候用ProxyDroid能够抓到包,之后测试屡次,无论什么姿态,除了第一次关上之外都抓不到包,难道除了第一次之外都改用了tcp? 不过好在还是抓到了包,这时候联合Inspeckage中hook到的加密算法和hash,就能够拼接出申请的数据包了,详情见上方。 还是想不通为什么,心愿有晓得的大佬能解惑。 Python代码# -*- encoding: utf-8 -*-'''@File : 91.py@Time : 2022年01月04日 20:24:32 星期二@Author : erma0@Version : 1.0@Link : https://erma0.cn@Desc : 91短视频刷邀请'''import requestsimport timeimport jsonfrom base64 import b64decodefrom hashlib import sha256, md5from Crypto.Cipher import AESfrom Crypto.Random import get_random_bytes# from Crypto.Hash import SHA256, MD5 # 和hashlib库一样class Aff(object): """ 91短视频刷邀请 """ def __init__(self, aff: str = "gcKyA"): self.aff = aff self.oauth_id = '' self.timestamp = '' self.url = 'http://api.91apiapi.com/api.php' # self.url = 'http://v2.my10api.com:8080/api.php' self.headers = { # 加不加header都能够 'Accept-Language': 'zh-CN,zh;q=0.8', 'User-Agent': 'Mozilla/5.0 (Linux; U; Android 5.1.1; zh-cn; M973Q Build/LMY49I) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30', 'Content-Type': 'application/x-www-form-urlencoded' } # self.b64key = 'h3PV8o444kNybrx77icyiriQ2q0uTjqUSsFRfaynkT8=' # self.b64iv = 'DrRMfzwgpjgI1sIjfW8aXw==' self.key = b64decode('h3PV8o444kNybrx77icyiriQ2q0uTjqUSsFRfaynkT8=') self.iv = b64decode('DrRMfzwgpjgI1sIjfW8aXw==') @staticmethod def get_timestamp(long: int = 10): """ 取工夫戳,默认10位 """ return str(time.time_ns())[:long] def decrypt(self, data: str): """ aes解密 """ ct_iv = bytes.fromhex(data[:32]) ct_bytes = bytes.fromhex(data[32:]) ciper = AES.new(self.key, AES.MODE_CFB, iv=ct_iv, segment_size=128) # CFB模式,iv指定,块大小为128(默认为8,需填8的倍数,貌似AES规范区块大小就是128,和密钥大小128/192/256无关) plaintext = ciper.decrypt(ct_bytes) return plaintext.decode() def encrypt(self, data: str): """ aes加密 """ ciper = AES.new(self.key, AES.MODE_CFB, iv=self.iv, segment_size=128) ct_bytes = self.iv + ciper.encrypt(data.encode()) # iv+加密后果合并 return ct_bytes.hex().upper() # hex编码 def get_sign(self): """ 生成sign """ template = 'data={}×tamp={}132f1537f85sjdpcm59f7e318b9epa51'.format( self.encrypt_data, self.timestamp) # sha256 sha = sha256() sha.update(template.encode()) res = sha.hexdigest() # md5 m = md5() m.update(res.encode()) res = m.hexdigest() return res def request(self, d: dict): """ 申请封包 """ plaintext = { "build_id": "a1000", "token": "", "oauth_type": "android", "app_status": "A72B8E7B0E661AAEEB5280AAC3993DC6F4A2D8C0:2", "version": "4.5.5", "apiV2": "v2", "app_type": "local" } d.update(plaintext) self.timestamp = self.get_timestamp(10) self.encrypt_data = self.encrypt(json.dumps(d, separators=(',', ':'))) sign = self.get_sign() data = {"timestamp": self.timestamp, "data": self.encrypt_data, "sign": sign} res = requests.post(url=self.url, data=data, headers=self.headers) resj = res.json() res = self.decrypt(resj.get('data')) print(res) return res def get_user(self): """ 生成新用户 """ # 取随机md5 m = md5() m.update(get_random_bytes(16)) oauth_id = m.hexdigest() data = {"mod": "system", "oauth_id": oauth_id, "code": "index"} self.request(data) self.oauth_id = oauth_id print(oauth_id) def invite(self): """ 刷邀请,邀请码:self.aff """ self.get_user() data = {"mod": "user", "oauth_id": self.oauth_id, "aff": self.aff, "code": "invitation"} self.request(data)if __name__ == "__main__": aff = Aff('gcKyA') aff.invite() # data = 'x' # print(aff.decrypt(data))
指标APP:91短视频 之前发过一篇蚂蚁加速器刷邀请的文章,这次的APP就是和蚂蚁加速器一家的,加密算法根本一样,不提供下载。0x00 工具筹备Fiddler(代理抓包)Xposed(hook框架) Inspeckage(通用hook插件,备选算法助手)HEX编码转换(base64转HEX)雷电模拟器(雷电3绿化版)ProxyDroid(代理转发工具,用Gitee一键编译的)工具安装包及配置好的雷电模拟器零碎备份下载:https://lanzoui.com/b0eknupng 明码:4vpf各工具应用办法介绍等具体内容可参考各自文档或百度。 0x01 现实的剖析过程新建模拟器,装置好指标APP及工具,先不要关上指标APP。 1、用ProxyDroid解决抓不到包的问题关上ProxyDroid按下图示例填好代理服务器IP、端口,协定选HTTP(就算抓HTTPS,也选HTTP) 下滑能够抉择用全局代理还是分利用代理,这里间接全局代理了。 代理服务器IP、端口为Fiddler中的代理,默认8888端口,IP为局域网IP,在Fiddler右上角有如下所示的图标,能够在下面悬停鼠标,就会显示局域网地址,个别为192.168..。 2、用Inspeckage主动hook加密算法及hash关上Inspeckage,抉择指标APP,界面如下。 依据图中提醒转发8008端口到电脑,即在模拟器运行目录下关上cmd,再输出: adb forward tcp:8008 tcp:8008此时在电脑浏览器中关上http://127.0.0.1:8008/即可看到Inspeckage网页界面。 点开设置,将不须要的都关掉,只留Crypto和Hash两个,关上主动刷新。 3、开始剖析工具都配置好后,关上指标APP,直到胜利绑定邀请码。(或者在开屏广告停留一下,查看Inspeckage的Crypto,出后果后敞开主动刷新,因为不晓得为什么这里会主动革除记录,偏偏刚启动会有个注册的包要用到。) 分析方法是依据Fiddler中数据包参数去Inspeckage中寻找对应的加解密输入输出。 点开绑定邀请码的包,绑定邀请码的时候看着Fiddler,很好确定是哪个包,不出意外的话就是指标域名在Fiddler中最下方倒数第二个。能够看到发送参数有3个,一个工夫戳,一个HEX格局的data,一个MD5的sign。在Inspeckage的Crypto中搜寻本人输出的邀请码,没搜到就把折叠起来的加密数据点开再搜,明文在前的是加密,base64在前的是解密。这里能够确定: 加密算法是AES,key是h3PV8o444kNybrx77icyiriQ2q0uTjqUSsFRfaynkT8=(base64编码),iv是DrRMfzwgpjgI1sIjfW8aXw==(base64编码),解密模式是AES/CFB/NoPadding,加密数据格式为{"mod":"user","build_id":"a1000","token":"","oauth_id":"xxxxx","oauth_type":"android","aff":"xxxxx","app_status":"xxxx:2","version":"4.5.5","apiV2":"v2","app_type":"local","code":"invitation"}把加密后果用HEX编码转换转为HEX,发现和data中去除前32个字符之后对的上。依据上一篇文章的教训,这32个字符应该是IV。把刚刚失去的iv即DrRMfzwgpjgI1sIjfW8aXw==转为HEX,发现正好和data前32位相等。这里能够确定:发送的data是iv与加密数据的HEX编码拼接而成。再用同样的办法,去Hash界面中搜抓到的sign,能够看到是一长串hash进行MD5加密。持续搜这一长串hash,发现正好是上面一条SHA256加密的后果。加密字符串格局为data={}xtamp={}132f1537f85sjdpcm59f7e318b9epa51这时候拿去验证SHA256,发现后果对不上。认真看一下,发现timestamp没齐全显示,预计出了点问题,手动补全为data={}×tamp={}132f1537f85sjdpcm59f7e318b9epa51,再次验证发现没问题了。加密的数据曾经差不多弄清楚了,那返回的data解密应该也是一样的。将后面失去的key和iv拿去解密,发现不对。这个时候依据后面的教训,猜想返data也是前32位为iv,前面为待解密数据,一试发现果然如此。因为各种AES加解密工具都把输入输出格局固定死了,很少有反对HEX或base64编码的输出以及key、iv,所以倡议写代码验证或者应用其余工具,或者手动转换编码再去用工具验证,这里是将待解密数据[HEX转为base64][],将key、iv转为HEX,再用工具验证到这里只看了绑定邀请码的包,当初再去看看注册的包,毕竟不注册没方法刷邀请。依据Fiddler中先后顺序,顺次将发包的data解密查看,后果没有发现注册字样,且多个data完全相同。所以能够猜想,要么是没抓到注册包,要么是这些数据包主动实现了注册。剖析局部到这里就能够完结了,有key、有iv、有加解密数据模板、有sign模板,能够间接写代码了。 4、怎么全是猜想?看到这里,我也纳闷,怎么都是猜的,间接剖析能猜到这些吗? 预计还真不好猜。 因为理论剖析过程并不是这么顺利,所以两头反编译看了源码,同时联合上一次剖析蚂蚁加速器的教训,所以很多货色都一眼看进去了,这两个APP加密基本相同。 如果有切实看不明确怎么猜到的,看一看上一篇蚂蚁加速器刷邀请的文章,外面有反编译剖析的局部。 0x02 理论剖析过程这里应用雷电3,即安卓5,因为安卓7装置证书麻烦。绿化版来自派大星模拟器多开助手网站。 开局先抓包,关上Fiddler、模拟器中设置好代理、装置证书、关上APP。 一顿操作猛如虎,一看后果啥也没有,而且APP能失常关上失常应用。这时候就能够猜想,APP禁用了代理。 个别防抓包措施自行理解。抓不到包的时候,如果APP闪退或者不能拜访网络,则有可能是检测了代理;如果APP失常应用,那应该是禁用了代理。 这里能够应用抓包精灵、小黄鸟等手机端的抓包工具,或者用代理工具转发流量到Fiddler,因为手机端不不便操作,所以这里用ProxyDroid来转发流量。 用其余工具能够,比方Drony、Postern、socksdroid,不过我举荐用ProxyDroid,代理模式齐全,设置过程简略明确。 用了代理工具,后果还是没有抓到想要的包,有点不对劲,我开始狐疑它不是HTTP协定,可能用了ws或者tcp。 这里就没脉络了,所以只能去看Inspeckage的后果,而后反编译(没加壳)找算法,找半天找到了。这个时候能够用frida取hook到后果了,然而我还是想试试能不能抓到包。 之后陆续尝试了用Inspeckage增加代理、用socks代理,都没胜利。 最初无心中发现,新建模拟器后第一次关上这个APP的时候用ProxyDroid能够抓到包,之后测试屡次,无论什么姿态,除了第一次关上之外都抓不到包,难道除了第一次之外都改用了tcp? 不过好在还是抓到了包,这时候联合Inspeckage中hook到的加密算法和hash,就能够拼接出申请的数据包了,详情见上方。 还是想不通为什么,心愿有晓得的大佬能解惑。 Python代码# -*- encoding: utf-8 -*-'''@File : 91.py@Time : 2022年01月04日 20:24:32 星期二@Author : erma0@Version : 1.0@Link : https://erma0.cn@Desc : 91短视频刷邀请'''import requestsimport timeimport jsonfrom base64 import b64decodefrom hashlib import sha256, md5from Crypto.Cipher import AESfrom Crypto.Random import get_random_bytes# from Crypto.Hash import SHA256, MD5 # 和hashlib库一样class Aff(object): """ 91短视频刷邀请 """ def __init__(self, aff: str = "gcKyA"): self.aff = aff self.oauth_id = '' self.timestamp = '' self.url = 'http://api.91apiapi.com/api.php' # self.url = 'http://v2.my10api.com:8080/api.php' self.headers = { # 加不加header都能够 'Accept-Language': 'zh-CN,zh;q=0.8', 'User-Agent': 'Mozilla/5.0 (Linux; U; Android 5.1.1; zh-cn; M973Q Build/LMY49I) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30', 'Content-Type': 'application/x-www-form-urlencoded' } # self.b64key = 'h3PV8o444kNybrx77icyiriQ2q0uTjqUSsFRfaynkT8=' # self.b64iv = 'DrRMfzwgpjgI1sIjfW8aXw==' self.key = b64decode('h3PV8o444kNybrx77icyiriQ2q0uTjqUSsFRfaynkT8=') self.iv = b64decode('DrRMfzwgpjgI1sIjfW8aXw==') @staticmethod def get_timestamp(long: int = 10): """ 取工夫戳,默认10位 """ return str(time.time_ns())[:long] def decrypt(self, data: str): """ aes解密 """ ct_iv = bytes.fromhex(data[:32]) ct_bytes = bytes.fromhex(data[32:]) ciper = AES.new(self.key, AES.MODE_CFB, iv=ct_iv, segment_size=128) # CFB模式,iv指定,块大小为128(默认为8,需填8的倍数,貌似AES规范区块大小就是128,和密钥大小128/192/256无关) plaintext = ciper.decrypt(ct_bytes) return plaintext.decode() def encrypt(self, data: str): """ aes加密 """ ciper = AES.new(self.key, AES.MODE_CFB, iv=self.iv, segment_size=128) ct_bytes = self.iv + ciper.encrypt(data.encode()) # iv+加密后果合并 return ct_bytes.hex().upper() # hex编码 def get_sign(self): """ 生成sign """ template = 'data={}×tamp={}132f1537f85sjdpcm59f7e318b9epa51'.format( self.encrypt_data, self.timestamp) # sha256 sha = sha256() sha.update(template.encode()) res = sha.hexdigest() # md5 m = md5() m.update(res.encode()) res = m.hexdigest() return res def request(self, d: dict): """ 申请封包 """ plaintext = { "build_id": "a1000", "token": "", "oauth_type": "android", "app_status": "A72B8E7B0E661AAEEB5280AAC3993DC6F4A2D8C0:2", "version": "4.5.5", "apiV2": "v2", "app_type": "local" } d.update(plaintext) self.timestamp = self.get_timestamp(10) self.encrypt_data = self.encrypt(json.dumps(d, separators=(',', ':'))) sign = self.get_sign() data = {"timestamp": self.timestamp, "data": self.encrypt_data, "sign": sign} res = requests.post(url=self.url, data=data, headers=self.headers) resj = res.json() res = self.decrypt(resj.get('data')) print(res) return res def get_user(self): """ 生成新用户 """ # 取随机md5 m = md5() m.update(get_random_bytes(16)) oauth_id = m.hexdigest() data = {"mod": "system", "oauth_id": oauth_id, "code": "index"} self.request(data) self.oauth_id = oauth_id print(oauth_id) def invite(self): """ 刷邀请,邀请码:self.aff """ self.get_user() data = {"mod": "user", "oauth_id": self.oauth_id, "aff": self.aff, "code": "invitation"} self.request(data)if __name__ == "__main__": aff = Aff('gcKyA') aff.invite() # data = 'x' # print(aff.decrypt(data))
视频加密个别分为加密和解密播放两局部,加密的作用是对视频进行非凡解决,个别是在本地实现的,不须要网络。而播放的话,是须要联网验证还是离线激活后播放,其实是看具体的应用场景去设计加解密逻辑。比方一些学校、医院等特定场景下网络是局域网,这种个别须要离线形式解密播放,比方通过设施的机器码来受权特定的激活秘匙。
随着在线教育、企业培训、原创视频爱护、单位机构外部课程、私人影咖等的倒退,对于视频创作者来说也越来越重视视频的安全性和严密性,视频加密软件的开发就施展了重要的作用。 在加密过程中会遇到一些问题如:操作是否简略快捷?实用于哪些终端?必须要在联网的场景下应用吗?能够多个设施应用吗? 就以上问题来说视频加密软件场景应用问题是最常见也比拟受关注的一个问题,因为在应用过程中可能遇到如:网络环境差连不上网,所以就会导致用户体验成果差。点盾云加密零碎因而推出了离线激活、联网预创立激活和联网主动申请激活三种模式。 一.预创立模式1.实用于用户可联网场景,激活码在后盾可控,可随时召回,召回后用户无奈观看视频;2、商家可事后批量创立激活码,一个激活码对应一个用户,用户首次观看视频时需输出激活码激活能力观看,激活的同时激活码和机器码实现绑定过程;3、一个激活码可受权用户的在指定数量的播放设施上应用(扣除多个激活码点数),超过指定日期、指定次数或指定设施后,用户需从新获取激活码;4、激活过的加密视频容许离线播放10次,10次后须要从新联网验证无效信息; 二.预申请模式1、实用于用户可联网场景,激活码在后盾可控,可随时召回,召回后用户无奈观看视频;2、商家的视频可提供给未知的用户进行观看,用户首次观看时需输出商家要求的信息而后申请播放,商家在后盾进行审核,审核通过后用户可间接观看视频;3、激活码主动和设施绑定无需发放过程,超过指定日期或指定次数后,用户需从新申请;4、也可容许用户在无奈联网的环境下观看视频10次,离线观看超过规定次数后须从新联网后才可持续观看; 三.离线版1、实用于用户无奈联网的场景;2、用户首次观看加密视频,需将由播放器主动获取的机器码发给商家;3、商家依据机器码在后盾创立对应的激活码,发给用户,用于激活播放;4、该激活码只能在对应设施上应用,超过指定日期或指定次数后,用户需从新分割商家获取激活码 这三种模式可能无效的保障在不同环境下都能够操作,大大晋升了用户的应用感。但要留神的是一个手机号只能注册一种受权形式。所以也能够依据对方的状况来抉择。
上周,咱们介绍了即构新推出的自研互动白板,依靠成熟的亿级用户实时信令网络,即构互动白板具备“音视频实时同步、百人实时在线合作、跨国跨网无差别体验”等独特劣势。 咱们提供了互动白板的体验APP,扫描下方二维码,即可获取iOS、Android、Web三个端的下载地址,大家能够亲自感触即构互动白板的应用成果: 课件数据安全是教育平台在白板选型时的重点关注因素,那么,如何保障白板分享时课件数据的安全性呢?基于在音视频、信令服务近20年的技术积攒,上面咱们将分享即构互动白板在解决数据安全难点的计划及技术实际。 随着教育行业竞争的加剧,越来越多的教育平台投入大量的人力物力进行课程研发,因此这些外围课件数据的爱护非常重要。教育平台在抉择白板互动厂商时,往往更关注教学过程中的课件平安问题,包含课件的防被盗、防失落,防损坏等。 即构依据白板文件共享的整体流程,从文件存储、拜访、业务等多方面保障数据的安全性。 存储平安 咱们次要从以下两方面来保障存储的安全性: 加密存储无论是原课件还是转码后的文件,都先通过加密解决后再进行存储,确保文件自身的加密平安,内容不透露。 备份容灾基于云服务厂商提供的备份容灾能力,确保课件存储的可靠性。 拜访平安 咱们通过双重验证来保障文件拜访的安全性: 文档服务反对对拜访课件的申请进行auth key验证,只有验证通过能力获取到课件的相干信息,如存储信息等。基于云服务厂商提供的对课件的鉴权拜访。业务平安 通过采纳转码业务与存储相拆散设计,把存储变成独立模块,反对第三方存储接入。客户能够仅应用即构的转码服务,而应用本人的存储服务,打消客户对外围课件资源的安全性顾虑。 通过对课件上传、转码、存储、散发、下载的整个链路的进行加密、鉴权,保障客户的课件平安,为客户的外围课件数据保驾护航。
AES 简介密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES(Data Encryption Standard),已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院 (NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。该算法为比利时密码学家Joan Daemen和Vincent Rijmen所设计,结合两位作者的名字,以Rijdael之名命之,投稿高级加密标准的甄选流程。(Rijdael的发音近于 "Rhine doll"。) 示例(Python3)第三方包安装pip3 install pycryptodome -i https://pypi.doubanio.com/simple/pip3 install pkcs7 -i https://pypi.doubanio.com/simple/code# encoding=utf-8# author: walker# date: 2019-09-19# summary: AES 加密解密示例(CBC模式,pkcs7占位)import timeimport base64from urllib import parsefrom Crypto.Cipher import AESfrom pkcs7 import PKCS7Encoderdef encrypt_aes_pkcs7(plaintext, key, iv): r""" 加密 plaintext: 明文 key: 密钥 iv: 偏移量 """ encoder = PKCS7Encoder() aes = AES.new(key, AES.MODE_CBC, iv) padtext = encoder.encode(plaintext) cipherbytes = aes.encrypt(padtext.encode('utf8')) ciphertext = base64.b64encode(cipherbytes).decode('utf8') return ciphertextdef decrypt_aes_pkcs7(ciphertext, key, iv): r""" 解密 plaintext: 密文 key: 密钥 iv: 偏移量 """ encoder = PKCS7Encoder() aes = AES.new(key, AES.MODE_CBC, iv) cipherbytes = base64.b64decode(ciphertext.encode('utf8')) padtext = aes.decrypt(cipherbytes).decode('utf8') plaintext = encoder.decode(padtext) return plaintextif __name__ == '__main__': key = b'1CF28E8DBB1F36F9DE50C06ADFFD942B' iv = key[0:16] timestamp = time.time() print('timestamp: %f (%s)' % (timestamp, time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(timestamp)))) plaintext = "%s*%s" % (timestamp, r'Adobe Spark is an online and mobile design app') print('plaintext: %s' % plaintext) print('key: %s' % key) print('iv: %s' % iv) assert(plaintext == decrypt_aes_pkcs7(encrypt_aes_pkcs7(plaintext, key, iv), key, iv)) ciphertext = encrypt_aes_pkcs7(plaintext, key, iv) print('ciphertext: %s' % ciphertext)相关链接pypi: pycryptodome , pkcs7gist 示例代码: https://gist.github.com/denni...AES在线加密解密本文出自 walker snapshot
最近遇到的几个网站在提交密码时提交的已经是密文,也就是说在网络上传输的密码是密文,这样提升了密码在网络传输中的安全性。 后端语言加解密已经有很成熟的方案了,前端的话Google之前出过一个crypto-js,为浏览器的js提供了加解密方案。今天一起来了解一下基于AES的前后端加解密流程。 Javascript安装npm包 npm install crypto-js加密代码 const CryptoJS = require("crypto-js");const key = CryptoJS.enc.Latin1.parse('1234567812345678');const iv = CryptoJS.enc.Latin1.parse('1234567812345678');const encoded = CryptoJS.AES.encrypt('hahaha', key, { iv: iv, mode: CryptoJS.mode.CBC, adding: CryptoJS.pad.ZeroPadding}).toString()console.log('encoded', encoded)解密代码 const key = CryptoJS.enc.Latin1.parse('123456781234567812345678');const iv = CryptoJS.enc.Latin1.parse('1234567812345678');const decoded = CryptoJS.AES.decrypt(encoded, key, { iv: iv, mode: CryptoJS.mode.CBC, adding: CryptoJS.pad.ZeroPadding}).toString(CryptoJS.enc.Utf8)console.log('decoded', decoded);输出如下 encoded 6bcgYd4f4ZgNOQH/3tqMpg==decoded hahahaPHP直接使用openssl解密即可,代码如下: $encoded = '6bcgYd4f4ZgNOQH/3tqMpg==';$key = '123456781234567812345678';$iv = '1234567812345678';var_dump(openssl_decrypt($encoded, 'AES-192-CBC', $key, 0,$iv));输出结果: string(6) "hahaha"注意事项 AES加密位数跟密钥key有关, 以下是密钥位数和加密对应关系 16 => AES-12824 => AES-19232 => AES-256iv是初始化向量. 超过16字节或者不足16字节都会被补足16字节或者截断到16字节。由于AES是块加密,铭文被分割成固定长度的块(一般是16字节长度),所以iv也是16字节。CBC是加密模式
还记得上初二的那年夏天,班里来了一个新同学,他就住在我家对面的楼里,于是我们一起上学放学,很快便成了最要好的朋友。我们决定发明一套神秘的沟通方式,任何人看到都不可能猜到它的真实含义。我们第一个想到的就是汉语拼音,但很显然光把一个句子变成汉语拼音是不够的,于是我们把26个英文字母用简谱的方式从低音到高音排起来,就得到了一个简单的密码本: 把“我们都是好朋友”用这个密码本变换之后就得到了这样的结果: 小时候玩这个游戏乐此不疲,觉得非常有趣。上大学后,有幸听卢开澄教授讲《计算机密码学》,才知道原来我们小时候玩的这个游戏远远不能称之为加密。那么到底什么是加密呢? 什么是加密?把字符串123456经过base64变换之后,得到了MTIzNDU2,有人说这是base64加密。 把字符串123456经过md5变换之后,得到了E10ADC3949BA59ABBE56E057F20F883E,有人说这是md5加密。 从严格意义上来说,不管是base64还是md5甚至更复杂一些的sha256都不能称之为加密。 一句话,没有密钥的算法都不能叫加密。 编码(Encoding)是把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8位字节或者电脉冲),以便文本在计算机中存储和通过通信网络的传递的方法,常见的例子包括将拉丁字母表编码成摩尔斯电码和ASCII。base64只是一种编码方式。杂凑(Hashing)是电脑科学中一种对资料的处理方法,通过某种特定的函数/算法(称为杂凑函数/算法)将要检索的项与用来检索的索引(称为杂凑,或者杂凑值)关联起来,生成一种便于搜索的资料结构(称为杂凑表)。杂凑算法常被用来保护存在资料库中的密码字符串,由于杂凑算法所计算出来的杂凑值具有不可逆(无法逆向演算回原本的数值)的性质,因此可有效的保护密码。常用的杂凑算法包括md5, sha1, sha256等。 加密(Encryption)是将明文信息改变为难以读取的密文内容,使之不可读的过程。只有拥有解密方法的对象,经由解密过程,才能将密文还原为正常可读的内容。加密分为对称加密和非对称加密,对称加密的常用算法包括DES, AES等,非对称加密算法包括RSA,椭圆曲线算法等。 在古典加密算法当中,加密算法和密钥都是不能公开的,一旦泄露就有被破解的风险,我们可以用词频推算等方法获知明文。1972年美国IBM公司研制的DES算法(Data Encryption Standard)是人类历史上第一个公开加密算法但不公开密钥的加密方法,后来成为美国军方和政府机构的标准加密算法。2002年升级成为AES算法(Advanced Encryption Standard),我们今天就从AES开始入手学习加密和解密。 准备工具通常情况下,加解密都只需要在服务端完成就够了,这也是网上大多数教程和样例代码的情况,但在某种特殊情况下,你需要用一种语言加密而用另一种语言解密的时候,最好有一个中立的公正的第三方结果集来验证你的加密结果,否则一旦出错,你都不知道是加密算法出错了,还是解密算法出错了,对此我们是有惨痛教训的,特别是如果一个公司里,写加密的是前端,用的是js语言,而写解密的是后端,用的是java语言或者php语言或者go语言,则双方更需要有这样一个客观公正的平台,否则你们之间必然会陷入永无休止的互相指责的境地,前端说自己没有错,是后端解密解错了,后端说解密没有错,是前端加密写错了,而事实上是双方都是菜鸟,对密码学一知半解,在这种情况下浪费的时间就更多。 在线AES加密解密就是这样的一个工具网站,你可以在上面验证你的加密结果,如果你加密得到的结果和它的结果完全一致,就说明你的加密算法没有问题,否则你就去调整,直到和它的结果完全一致为止。反之亦然,如果它能从一个密文解密解出来,而你的代码解不出来,那么一定是你的算法有问题,而不可能是数据的问题。 我们先在这个网站上对一个简单的字符串123456进行加密。 下面我们对网站上的所有选项逐个解释一下: AES加密模式:这里我们选择的是ECB(ee cc block)模式。这是AES所有模式中最简单也是最不被人推荐的一种模式,因为它的固定的明文对应的是固定的密文,很容易被破解。但是既然是练习的话,就让我们先从最简单的开始。填充:在这里我们选择pkcs标准的pkcs7padding。数据块:我们选择128位,因为java端解密算法目前只支持AES128,所以我们先从128位开始。密钥:因为我们前面选择了128位的数据块,所以这里我们用128 / 8 = 16个字节来处理,我们先简单地填入16个0,其实你也可以填写任意字符,比如abcdefg1234567ab或者其它,只要是16个字节即可。理论上来说,不是16个字节也可以用来当密钥,优秀的算法会自动补齐,但是为了简单起见,我们先填入16个0。偏移量:置空。因为是ECB模式,不需要iv偏移量。输出:我们选择base64编码方式。字符集:这里因为我们只加密英文字母和阿拉伯数字,所以选择utf-8和gb2312都是一样的。好了,现在我们知道按照以上选项设置好之后的代码如果加密123456的话,应该输出DoxDHHOjfol/2WxpaXAXgQ==,如果不是这个结果,那就是加密端的问题。 AES-ECBAES-ECB的Javascript加密为了完成AES加密,我们并不需要自己手写一个AES算法,不需要去重复造轮子。但如何选择js的加密库是个很有意思的挑战。我们尝试了很多方法,一开始我们尝试了aes-js这个库,但它不支持RSA算法,后来我们看到Web Crypto API这种浏览器自带的加密库,原生支持AES和RSA,但它的RSA实现和Java不兼容,最终我们还是选择了Forge这个库,它天生支持AES的各种子集,并且它的RSA也能和Java完美配合。 使用forge编写的js代码实现AES-ECB加密的代码就是下面这些: const cipher = forge.cipher.createCipher('AES-ECB', '这里是16字节密钥');cipher.start();cipher.update(forge.util.createBuffer('这里是明文'));cipher.finish();const result = forge.util.encode64(cipher.output.getBytes())forge的AES缺省就是pkcs7padding,所以不用特别设置。运行它之后你就会得到正确的加密结果。 AES-ECB的Java解密接下来我们看看Java端的解密代码该如何写: try { Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec("这里是16字节密钥".getBytes(), "AES")); String plaintext = new String(cipher.doFinal(Base64.getDecoder().decode("这里是明文".getBytes())), "UTF-8"); System.out.println(plaintext);} catch (Exception e) { System.out.println("解密出错:" + e.toString());}注意这里我们用到的是PKCS5Padding,上面加密的时候不是用的是pkcs7padding吗?怎么这里变成5了呢? ...
本文旨在帮助大家分清各种加密方式以及用途原理说明,具体的加密算法分析不在本文的主要探讨之内!知识路线graph LR对称加密 --> 非对称加密非对称加密 --> 哈希算法哈希算法 --> 数字签名引入背景:不论是前端还是后端开发中,数字签名、信息加密是经常需要使用到的技术,应用场景包括了用户登入、交易、信息通讯、oauth 等等,不同的应用场景也会需要使用到不同的签名加密算法,或者需要搭配不一样的 签名加密算法 来达到业务目标。 漫画:https://cloud.tencent.com/dev... 早在古罗马时期,加密算法就被应用于战争当中。 在大规模的战争中,部队之间常常需要信使往来,传递重要的军事情报。 传送情报过程中,容易遭到中间人攻击,怎样防止这种情况的发生呢? 古罗马人想出了一种非常朴素的加密方法,被称为凯撒密码。加密的原理就像下图这样: 数据加密过程:在对称加密算法中,数据发送方 将 明文 (原始数据) 和 加密密钥 一起经过特殊 加密处理,生成复杂的 加密密文 进行发送。数据解密过程:数据接收方 收到密文后,若想读取原数据,则需要使用 加密使用的密钥 及相同算法的 逆算法 对加密的密文进行解密,才能使其恢复成 可读明文常见的加密算法介绍常见的加密算法可以大致分为:对称加密算法、非对称加密算法、摘要算法。接下来主要围绕这三种算法进行介绍。对称加密算法(Symmetric-key algorithm)常见的 对称加密 算法主要有 DES、3DES、AES 等原理 讲解常见的集中算法AES、DES、3DES、Blowfish、IDEA、RC4、RC5、RC6常见对称加密算法的原理DES (Data Encryption Standard) 数字加密算法是1977年美国联邦信息处理标准(FIPS)中所采用的一种对称密码。DES一直以来被美国以及其它国家的政府和银行等广泛使用。DES运算速度快、资源消耗较少,但是随着计算机计算能力的增强,DES已经能够在短时间内暴力破解,安全性较低。RSA公司在20世纪末举办过的破译DES密钥的比赛数据显示,到1999年破译密钥只需要22小时15分钟。鉴于DES已经能够在短时间内被破解,现在除了破解之前的密文,已不再推荐使用。3DES(Triple Data Encryption Algorithm) 由于DES已经能够在短时间内被破解,为了增加DES的强度,将DES重复3次的用来替代DES的分组密码3DES被开发出来,也称为TDEA(Triple Data Encryption Algorithm)。 但是,3DES处理速度不高,除了在一些重视向下兼容性的环境中,很少有新的用途,也逐渐被AES所取代。 AES (Advanced Encryption Standard) 高级加密标准是取代DES标准的一种对称加密算法的新标准,最终在2000年从众多候选对称密码算法中选出了Rijndael作为AES。被选为AES的密码算法必须满足一定的条件,比如,算法没有弱点、加密以及密钥准备的速度要够快、实现容易、能够在各平台上有效工,同时,还必须无条件地免费供全世界使用。可以说,被选为AES的算法近乎“完美”。AES加解密机制较复杂,综合运用了逐字节替换、平移行、混合列、与轮密钥进行XOR等,其优点在运算速度快、资源消耗少,且安全性高。前面我们简单介绍了DES、3DES和AES三种对称密码,DES已经能够被暴力破解,3DES也逐渐被AES取代。鉴于AES在其选定过程中经过了全世界密码专家的严谨验证,一般来说,我们在使用的时候应尽量使用AES。 优点与缺点优点:对称加密算法的优点是算法公开、计算量小、加密速度快、加密效率高。缺点:秘钥的管理和分发非常困难,不够安全。在数据传送前,发送方和接收方必须商定好秘钥,然后双方都必须要保存好秘钥,如果一方的秘钥被泄露,那么加密信息也就不安全了。另外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的唯一秘钥,这会使得收、发双方所拥有的钥匙数量巨大,密钥管理成为双方的负担。用途与场景通信过程中的加密数据库存储的敏感信息加密【一般用于保存用户手机号、身份证等敏感但能解密的信息 】思考 在对称加密中,我们应该如何将密钥安全地发送给接收者? 非对称加密算法非对称加密算法,又称为 公开密钥加密算法。它需要两个密钥,一个称为 公开密钥 (public key),即 公钥,另一个称为 私有密钥 (private key),即 私钥。 ...
概览工作中,我们时刻都会和接口打交道,有的是调取他人的接口,有的是为他人提供接口,在这过程中肯定都离不开签名验证。 在设计签名验证的时候,一定要满足以下几点: 可变性:每次的签名必须是不一样的。时效性:每次请求的时效性,过期作废。唯一性:每次的签名是唯一的。完整性:能够对传入数据进行验证,防止篡改。下面主要分享一些工作中常用的加解密的方法。 常用验证举例:/api/login?username=xxx&password=xxx&sign=xxx 发送方和接收方约定一个加密的盐值,进行生成签名。 示例代码: //创建签名private function _createSign(){ $strSalt = '1scv6zfzSR1wLaWN'; $strVal = ''; if ($this->params) { $params = $this->params; ksort($params); $strVal = http_build_query($params, '', '&', PHP_QUERY_RFC3986); } return md5(md5($strSalt).md5($strVal));}//验证签名if ($_GET['sign'] != $this->_createSign()) { echo 'Invalid Sign.';}上面使用到了 MD5 方法,MD5 属于单向散列加密。 单向散列加密定义把任意长的输入串变化成固定长的输出串,并且由输出串难以得到输入串,这种方法称为单项散列加密。 常用算法MD5SHAMACCRC优点以 MD5 为例。 方便存储:加密后都是固定大小(32位)的字符串,能够分配固定大小的空间存储。损耗低:加密/加密对于性能的损耗微乎其微。文件加密:只需要32位字符串就能对一个巨大的文件验证其完整性。不可逆:大多数的情况下不可逆,具有良好的安全性。缺点存在暴力破解的可能性,最好通过加盐值的方式提高安全性。应用场景用于敏感数据,比如用户密码,请求参数,文件加密等。推荐密码的存储方式password_hash() 使用足够强度的单向散列算法创建密码的哈希(hash)。 示例代码: //密码加密$password = '123456';$strPwdHash = password_hash($password, PASSWORD_DEFAULT);//密码验证if (password_verify($password, $strPwdHash)) { //Success} else { //Fail}PHP 手册地址: http://php.net/manual/zh/func... 对称加密定义同一个密钥可以同时用作数据的加密和解密,这种方法称为对称加密。 常用算法DESAESAES 是 DES 的升级版,密钥长度更长,选择更多,也更灵活,安全性更高,速度更快。 ...
项目需求中需要对用户登录时的密码进行加密,在网上查询些许文章后,最终与后端协商使用jsencrypt.js。jsencrypt.js的github地址:https://github.com/travist/js…使用yarn安装至Vue项目yarn add jsencrypt –dep或者使用npmnpm install jsencrypt –dep引入jsencryptimport { JSEncrypt } from ‘jsencrypt’可封装为全局混合,便于调用公钥为后端提供,如前端需要解密数据,则也需要后端提供私钥。methods: { // 加密 encryptedData(publicKey, data) { // 新建JSEncrypt对象 let encryptor = new JSEncrypt(); // 设置公钥 encryptor.setPublicKey(publicKey); // 加密数据 return encryptor.encrypt(data); }, // 解密 decryptData(privateKey,data){ // 新建JSEncrypt对象 let decrypt= new JSEncrypt(); // 设置私钥 decrypt.setPrivateKey(privateKey); // 解密数据 decrypt.decrypt(secretWord); } }调用函数加密,此处的公钥是我从后端那获取的,然后加密密码,这仅使用加密。encryptedPassword = this.encryptedData(publicKey, password);即完成加密。更多使用可查阅官方文档http://travistidwell.com/jsen…
一般情况下,很少会在前端进行加解密的操作,因为没有太大的必要性,前端的代码是很容易看到的,即使这样,我觉得还是有比较处理一下的,至少不让别人一眼就看到信息我使用localStorage存储了一些用户的用户名昵称等的信息,通过crypto-js进行加解密处理,这里我选用了AES加密算法对json对象数据进行处理按照官方的例子,如下var CryptoJS = require(“crypto-js”); var data = [{id: 1}, {id: 2}] // Encryptvar ciphertext = CryptoJS.AES.encrypt(JSON.stringify(data), ‘secret key 123’); // Decryptvar bytes = CryptoJS.AES.decrypt(ciphertext.toString(), ‘secret key 123’);var decryptedData = JSON.parse(bytes.toString(CryptoJS.enc.Utf8)); console.log(decryptedData);以上代码在chrome里运行没什么问题,可是在Safari的时候报了malformed utf-8 data可能是前端加解密的场景比较少,搜到若干报这个错的,但是鲜有解决方法,其中有一个说加密数据不是8的整数倍就会报上述错误解决方法:将数据加密后,再进行base64进行处理 let newUserInfo = {nickname:‘hello’,email:‘abc123@qq.com’}; //加密数据 let encJson = cryptoJS.AES.encrypt(JSON.stringify(newUserInfo), ‘aes’).toString(); //对加密数据进行base64处理, 原理:就是先将字符串转换为utf8字符数组,再转换为base64数据 let encData = cryptoJS.enc.Base64.stringify(cryptoJS.enc.Utf8.parse(encJson)); localStorage.setItem(‘userInfo’, encData); //将数据先base64还原,再转为utf8数据 let decData = cryptoJS.enc.Base64.parse(localStorage.getItem(‘userInfo’)).toString(cryptoJS.enc.Utf8); //解密数据 let decJson = cryptoJS.AES.decrypt(decData, ‘aes’).toString(cryptoJS.enc.Utf8); userInfo = JSON.parse(decJson); console.log(userInfo);以上,在safari,chrome,firefox运行没问题
缘起因为项目中使用mysql的AES_DECRYPT方法,欲使用golang实现该方法, 但是研究了半天没明白怎么回事, 最后才发现golang当前默认支持CBC的方式,但是mysql当前使用的是ECB模式, 所以需要使用者分组分块加密,特总结一下golang中的各个加密算法关于密码学当前我们项目中常用的加解密的方式无非三种.对称加密, 加解密都使用的是同一个密钥, 其中的代表就是AES非对加解密, 加解密使用不同的密钥, 其中的代表就是RSA签名算法, 如MD5、SHA1、HMAC等, 主要用于验证,防止信息被修改, 如:文件校验、数字签名、鉴权协议AESAES:高级加密标准(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。5.输出反馈模式(Output FeedBack (OFB))加密模式对应加解密方法CBCNewCBCDecrypter, NewCBCEncrypterCTRNewCTRCFBNewCFBDecrypter, NewCFBEncrypterOFBNewOFB相关示例见: https://golang.org/src/crypto...1.CBC模式, 最常见的使用的方式package mainimport( “bytes” “crypto/aes” “fmt” “crypto/cipher” “encoding/base64”)func main() { orig := “hello world” key := “0123456789012345” fmt.Println(“原文:”, orig) encryptCode := AesEncrypt(orig, key) fmt.Println(“密文:” , encryptCode) decryptCode := AesDecrypt(encryptCode, key) fmt.Println(“解密结果:”, decryptCode)}func AesEncrypt(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 AesDecrypt(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)]}2.ECB模式: mysql中AES_DECRYPT函数的实现方式主要关注三点: 1.调用aes.NewCipher([]byte)是加密关键字key的生成方式, 即下面的generateKey方法2.分组分块加密的加密方式3.mysql中一般需要HEX函数来转化数据格式加密: HEX(AES_ENCRYPT(‘关键信息’, ‘—key’))解密: AES_DECRYPT(UNHEX(‘关键信息’), ‘-key’)所以调用AESEncrypt或者AESDecrypt方法之后, 使用hex.EncodeToString()转化代码参考: https://github.com/fkfk/mysql...package mysqlcryptoimport ( “crypto/aes”)func AESEncrypt(src []byte, key []byte) (encrypted []byte) { cipher, _ := aes.NewCipher(generateKey(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}func AESDecrypt(encrypted []byte, key []byte) (decrypted []byte) { cipher, _ := aes.NewCipher(generateKey(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 decrypted[:trim]}func generateKey(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}CFB模式代码来源: https://golang.org/src/crypto...func ExampleNewCFBDecrypter() { // Load your secret key from a safe place and reuse it across multiple // NewCipher calls. (Obviously don’t use this example key for anything // real.) If you want to convert a passphrase to a key, use a suitable // package like bcrypt or scrypt. key, _ := hex.DecodeString(“6368616e676520746869732070617373”) ciphertext, _ := hex.DecodeString(“7dd015f06bec7f1b8f6559dad89f4131da62261786845100056b353194ad”) block, err := aes.NewCipher(key) if err != nil { panic(err) } // The IV needs to be unique, but not secure. Therefore it’s common to // include it at the beginning of the ciphertext. if len(ciphertext) < aes.BlockSize { panic(“ciphertext too short”) } iv := ciphertext[:aes.BlockSize] ciphertext = ciphertext[aes.BlockSize:] stream := cipher.NewCFBDecrypter(block, iv) // XORKeyStream can work in-place if the two arguments are the same. stream.XORKeyStream(ciphertext, ciphertext) fmt.Printf("%s", ciphertext) // Output: some plaintext}func ExampleNewCFBEncrypter() { // Load your secret key from a safe place and reuse it across multiple // NewCipher calls. (Obviously don’t use this example key for anything // real.) If you want to convert a passphrase to a key, use a suitable // package like bcrypt or scrypt. key, _ := hex.DecodeString(“6368616e676520746869732070617373”) plaintext := []byte(“some plaintext”) block, err := aes.NewCipher(key) if err != nil { panic(err) } // The IV needs to be unique, but not secure. Therefore it’s common to // include it at the beginning of the ciphertext. ciphertext := make([]byte, aes.BlockSize+len(plaintext)) iv := ciphertext[:aes.BlockSize] if _, err := io.ReadFull(rand.Reader, iv); err != nil { panic(err) } stream := cipher.NewCFBEncrypter(block, iv) stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) // It’s important to remember that ciphertexts must be authenticated // (i.e. by using crypto/hmac) as well as being encrypted in order to // be secure. fmt.Printf("%x\n", ciphertext)}RSA首先使用openssl生成公私钥import ( “crypto/rand” “crypto/rsa” “crypto/x509” “encoding/base64” “encoding/pem” “errors” “fmt”)// 私钥生成//openssl genrsa -out rsa_private_key.pem 1024var privateKey = []byte(-----BEGIN RSA PRIVATE KEY-----MIICWwIBAAKBgQDcGsUIIAINHfRTdMmgGwLrjzfMNSrtgIf4EGsNaYwmC1GjF/bMh0Mcm10oLhNrKNYCTTQVGGIxuc5heKd1gOzb7bdTnCDPPZ7oV7p1B9Pud+6zPacoqDz2M24vHFWYY2FbIIJh8fHhKcfXNXOLovdVBE7Zy682X1+R1lRK8D+vmQIDAQABAoGAeWAZvz1HZExca5k/hpbeqV+0+VtobMgwMs96+U53BpO/VRzl8Cu3CpNyb7HY64L9YQ+J5QgpPhqkgIO0dMu/0RIXsmhvr2gcxmKObcqT3JQ6S4rjHTln49I2sYTz7JEH4TcplKjSjHyq5MhHfA+CV2/AB2BO6G8limu7SheXuvECQQDwOpZrZDeTOOBkz1vercawd+J9ll/FZYttnrWYTI1sSF1sNfZ7dUXPyYPQFZ0LQ1bhZGmWBZ6a6wd9R+PKlmJvAkEA6o32c/WEXxW2zeh18sOO4wqUiBYq3L3hFObhcsUAY8jfykQefW8qyPuuL02jLIajFWd0itjvIrzWnVmoUuXydwJAXGLrvllIVkIlah+lATprkypH3GycYFnxCTNkOzIVoXMjGp6WMFylgIfLPZdSUiaPnxby1FNM7987fh7Lp/m12QJAK9iL2JNtwkSR3p305oOuAz0oFORn8MnB+KFMRaMT9pNHWk0vke0lB1sc7ZTKyvkEJW0oeQgic9DvIYzwDUcU8wJAIkKROzuzLi9AvLnLUrSdI6998lmeYO9x7pwZPukz3erazncjRK3pbVkv0KrKfczuJiRlZ7dUzVO0b6QJr8TRAA==-----END RSA PRIVATE KEY-----)// 公钥: 根据私钥生成//openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pemvar publicKey = []byte(-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcGsUIIAINHfRTdMmgGwLrjzfMNSrtgIf4EGsNaYwmC1GjF/bMh0Mcm10oLhNrKNYCTTQVGGIxuc5heKd1gOzb7bdTnCDPPZ7oV7p1B9Pud+6zPacoqDz2M24vHFWYY2FbIIJh8fHhKcfXNXOLovdVBE7Zy682X1+R1lRK8D+vmQIDAQAB-----END PUBLIC KEY-----)// 加密func RsaEncrypt(origData []byte) ([]byte, error) { //解密pem格式的公钥 block, _ := pem.Decode(publicKey) if block == nil { return nil, errors.New(“public key error”) } // 解析公钥 pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return nil, err } // 类型断言 pub := pubInterface.(*rsa.PublicKey) //加密 return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)}// 解密func RsaDecrypt(ciphertext []byte) ([]byte, error) { //解密 block, _ := pem.Decode(privateKey) if block == nil { return nil, errors.New(“private key error!”) } //解析PKCS1格式的私钥 priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil, err } // 解密 return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)}func main() { data, _ := RsaEncrypt([]byte(“hello world”)) fmt.Println(base64.StdEncoding.EncodeToString(data)) origData, _ := RsaDecrypt(data) fmt.Println(string(origData))} 散列算法// sha256加密字符串str := “hello world"sum := sha256.Sum256([]byte(str))fmt.Printf(“SHA256:%x\n”, sum)// sha256加密文件内容func fileSha156() { file, err := os.OpenFile(“e:/test.txt”, os.O_RDONLY, 0777) if err != nil { panic(err) } defer file.Close() h := sha256.New() // 将文件内容拷贝到sha256中 io.Copy(h, file) fmt.Printf("%x\n”, h.Sum(nil))}// md5加密 result := md5.Sum([]byte(str))fmt.Printf(“MD5:%x\n”, result)参考文档golang中几种加密方式的处理对称加密算法和分组密码的模式 ...