go crypto aes


原文链接: go crypto aes

OAuth请求头里的nonce(随机数)、timestamp(时间戳)、signatrue(签名)

名词解释:

  1. Nonce(能使用一次的随机数字)

    Nonce是一个在加密通信只能使用一次的数字。在认证协议中,它往往是一个随机或伪随机数,以避免重放攻击
    原理:

    1. Server 首先发送 nonce 到 Client,
    2. Client 将密码和 nonce 通过 hash(password+nonce) 运算再提交到 Server 进行身份验证,
    3. 这样我们可以认为(而非绝对)每次用于身份验证的 hash 值都不相同,即使攻击者窃取了前一次用于身份验证的 hash 值也无法冒充用户进行登录

  2. AEAD (Authenticated Encryption with Associated Data) 同时实现 加密和认证

    是一种同时具备保密性,完整性和可认证性的加密形式。
    从 2008 年起,业内开始提出,需要在一个算法在内部同时实现加密认证
    基于这个思想,一些新的算法被提出,这些算法被称为真正的 AEAD 算法。
    常见的 AEAD 算法如下:
    AES-128-GCM
    AES-192-GCM
    AES-256-GCM
    ChaCha20-IETF-Poly1305
    XChaCha20-IETF-Poly1305

在具备 AES 加速的 CPU(桌面,服务器)上,建议使用 AES-XXX-GCM 系列,
移动设备建议使用 ChaCha20-IETF-Poly1305 系列。
注意: 在设计加密系统的时候,请务必选用 AEAD 算法

加密方式选择

Xchacha20-ietf-poly1305 是相对最安全的
AES-256-GCM

目前这种结构支持硬件加速,需要Intel SSSE3扩展,以及 aesni 和 pclmul。
官方暂无计划将AES-256-GCM通过非硬件技术(即软件层)来实现

ChaCha20-Poly1305
虽然AES-256-GCM在专用硬件上速度非常快,但在非专用硬件上性能要低得多。并且, AES容易受到缓存冲突时间的攻击。   

ChaCha20在纯软件方面加密就比AES快得多,在缺乏专用AES硬件的平台上速度比其快三倍。 并且, ChaCha20对定时攻击也不敏感。

Poly1305 是一种高速信息验证码。
ChaCha20 流密码 + Poly1305认证的组合的使得其成为了Salsa20-Poly1305加密方式的替代品。其于2015年5月成为IETF官方标准,所以目前很多主流操作系统均以支持ChaCha20-Poly1305,

##### XChaCha20-IETF-Poly1305

XChaCha20-Poly1305继承了ChaCha20-Poly1305所有优势并将随机文件nonce大小扩展到192位。这种扩展的随机数大小允许安全使用随机数。

libsodium中的XChaCha20-Poly1305实现可在所有支持的体系结构中移植。这种加密需要 >=libsodium 1.0.12的版本方能支持

加密方式 | Key 大小 | Nonce大小 | Block大小 | MAC 大小 | 对应libsodium版本
----------------------- | ------- | ------- | ------- | ------- |
AES-256-GCM | 256 比特 | 96比特 | 128 比特 | 128 比特 | libsodium >= 1.0.4 but requires hardware support.
ChaCha20-Poly1305 | 256 比特 | 64比特 | 512 比特 | 128 比特 | libsodium >= 0.6.0. Also implemented in {Libre,Open,Boring}SSL.
ChaCha20-IETF-Poly1305 | 256 比特 | 96比特 | 512 比特 | 128 比特 | libsodium >= 1.0.4. IETF standard; also implemented in Ring, {Libre,Open,Boring}SSL and other libraries.
XChaCha20-IETF-Poly1305 | 256 比特 | 192 比特 | 512 比特 | 128 比特 | libsodium >= 1.0.12.

加密 摘要 签名
EncryptionhashesSignatures
* DES* MD4* RSA
* 3DES* MD5> * PKCS1v15
* RC4* RIPEMD160> * PSS
* TEA* SHA1* ECDSA
* XTEA* ✔️ SHA2> * ✔️ P256
* Blowfish* ✔️ SHA3> * P385
* ✔️ Twofish> * P521
* CAST5* Ed25519
* ✔️ Salsa20
* ✔️ AES
> * CBC
> * CFB
> * CTR
> * OFB
> * ✔️ GCM

AES
case 16, 24, 32: // AES 128/196/256
区别 AES-XXX-CFB AES-XXX-CTR AES-XXX-GCM
定义 GMAC伽罗瓦消息验证码+CTR
区别 仅加密 仅加密 加密+消息完整性校验
优点 加密可并行 加密解密均可并行计算 加密解密均可并行计算
缺点 解密串行
CHACHA20
​ chacha20是salsa20的改良
​ 20 : 20轮加密
​ ietf : chacha20算法的一个变种(某些参数调整)
​ xchacha20 : 记忆中xchacha20比chacha20好
​ poly1305 : 消息完整性校验方式
总结
RC4-MD5,安全性几乎没保障,淘汰。
AES兼顾效率和安全。在拥有AES指令集的机器上, 效率比XCHACHA20更高。推荐:AES-256-GCM。
XCHACHA20兼顾效率和安全。在没有AES指令集的机器上,效率比AES高。推荐:XCHACHA20-IETF-POLY1305。

AES加解密方式有以下这些

算法/模式/填充 字节加密后数据长度 不满16字节加密后长度
AES/CBC/NoPadding 16 不支持
AES/CBC/PKCS5Padding 32 16
AES/CBC/ISO10126Padding 32 16
AES/CFB/NoPadding 16 原始数据长度
AES/CFB/PKCS5Padding 32 16
AES/CFB/ISO10126Padding 32 16
AES/ECB/NoPadding 16 不支持
AES/ECB/PKCS5Padding 32 16
AES/ECB/ISO10126Padding 32 16
AES/OFB/NoPadding 16 原始数据长度
AES/OFB/PKCS5Padding 32 16
AES/OFB/ISO10126Padding 32 16
AES/PCBC/NoPadding 16 不支持
AES/PCBC/PKCS5Padding 32 16
AES/PCBC/ISO10126Padding 32 16

很多人对于AES加密并不是很了解,导致互相之间进行加密解密困难。
本文用简单的方式来介绍AES在使用上需要的知识,而不涉及内部算法。最后给出例子来帮助理解AES加密解密的使用方法。

AES的麻烦

相比于其他加密,AES加密似乎模式很多,包括ECB、CBC等等等等,每个模式又包括IV参数和Padding参数,并且,不同语言对AES加密的库设计有区别。这些导致AES加密在不同人之间联调会很麻烦。

AES属于块加密

不难理解,对越长的字符串进行加密,代价越大,所以通常对明文进行分段,然后对每段明文进行加密,最后再拼成一个字符串。块加密的一个要面临的问题就是如何填满最后一块?所以这就是PADDING的作用,使用各种方式填满最后一块字符串,所以对于解密端,也需要用同样的PADDING来找到最后一块中的真实数据的长度。

加密模式

AES分为几种模式,比如ECB,CBC,CFB等等,这些模式除了ECB由于没有使用IV而不太安全,其他模式差别并没有太明显,大部分的区别在IV和KEY来计算密文的方法略有区别。具体可参考WIKI的说明。
另外,AES分为AES128,AES256等,表示期待秘钥的长度,比如AES256秘钥的长度应该是256/8的32字节,一些语言的库会进行自动截取,让人以为任何长度的秘钥都可以。而这其实是有区别的。

IV的作用 (initialization vector) 初始向量

IV称为初始向量,一般的使用上会要求它是随机数或拟随机数(pseudorandom).不同的IV加密后的字符串是不同的,加密和解密需要相同的IV,既然IV看起来和key一样,却还要多一个IV的目的,对于每个块来说,key是不变的,但是只有第一个块的IV是用户提供的,其他块IV都是自动生成。
IV的长度为16字节。超过或者不足,可能实现的库都会进行补齐或截断。但是由于块的长度是16字节,所以一般可以认为需要的IV是16字节。

PADDING
AES块加密说过,PADDING是用来填充最后一块使得变成一整块,所以对于加密解密两端需要使用同一的PADDING模式,大部分PADDING模式为PKCS5, PKCS7, NOPADDING。

加密解密端
所以,在设计AES加密的时候

  • 对于加密端,应该包括:加密秘钥长度,秘钥,IV值,加密模式,PADDING方式。
  • 对于解密端,应该包括:解密秘钥长度,秘钥,IV值,解密模式,PADDING方式。

Nodejs实现
这里使用Nodejs的cryptojs库模拟AES加密解密

var crypto = require("crypto");

var algorithm='aes-256-cbc';
var key = new Buffer("aaaabbbbccccddddeeeeffffgggghhhh");
var iv = new Buffer("1234567812345678");
function encrypt(text){
​ var cipher=crypto.createCipheriv(algorithm,key,iv);
​ cipher.update(text,"utf8");
​ return cipher.final("base64");
}
function decrypt(text){
​ var cipher=crypto.createDecipheriv(algorithm,key,iv);
​ cipher.update(text,"base64");
​ return cipher.final("utf8");
}

var text="ni你好hao";
var encoded=encrypt(text)
console.log(encoded);
console.log(decrypt(encoded))

结果如下

WfH4hzIc3dc0pjxa9V/RgQ==
ni你好hao
1
2
nodejs自带的并不能自动配置padding等参数,演示起来并不方便。
于是使用另一个框架crypto-js的nodejs库实现和之前完全相同的版本

var CryptoJS = require("crypto-js");
var key ="aaaabbbbccccddddeeeeffffgggghhhh";
var iv = "1234567812345678";

function encrypt(text){
​ return CryptoJS.AES.encrypt(text,CryptoJS.enc.Utf8.parse(key),{
​ iv:CryptoJS.enc.Utf8.parse(iv),
​ mode:CryptoJS.mode.CBC,
​ padding:CryptoJS.pad.Pkcs7
​ })
}

function decrypt(text){
​ var result = CryptoJS.AES.decrypt(text,CryptoJS.enc.Utf8.parse(key),{
​ iv:CryptoJS.enc.Utf8.parse(iv),
​ mode:CryptoJS.mode.CBC,
​ padding:CryptoJS.pad.Pkcs7
​ })
​ return result.toString(CryptoJS.enc.Utf8)
}

var text="ni你好hao";
var encoded=encrypt(text)
console.log(encoded.toString());
console.log(decrypt(encoded))

现在aes的参数都变成可配置的,接下来验证一下之前对AES的理解。

改变IV的长度,发现当IV大于16字节的时候,不管16字节之后的是什么,都不影响加密结果,应该是种自动截取机制(nodejs原生库IV不是16字节,就会报错)
改变IV的长度,当IV小于16字节,还可以成功加密,可能是自动补齐机制
加密IV和解密IV不同的时候,并不影响解密是否成功,但是解密的结果有差别,比如将解密的IV变成1234567813345678,则解密结果变为ni你好h`o
修改padding,加密解密的padding换成NoPadding,发现解密之后生成utf8字符串出错
经过多次尝试,加密为Pkcs7和ZeroPadding时,加密后的字符串变化显著,这时解密用任何padding模式,都可以成功解密。
ni你好hao,经过Pkcs7后,输出为

WfH4hzIc3dc0pjxa9V/RgQ==
1
nopadding后,输出为

OtSNypfx1SF6C2E=
1
zeropadding后,输出为

OtSNypfx1SF6C2GfyXMidA==
1
Pkcs7的结果和其他结果相差很大,很难相信其padding是补充最后一块
有趣的是Pkcs7的结果和zeropadding的结果通过同样的解密设置,能解出同样的字符串ni你好hao

总结
AES加密解密的秘钥有一对,一个是IV一个是KEY,并且他们的长度都有严格要求。
Padding的作用似乎不只是补齐最后,如果自己什么都对,但是加密失败,可以尝试不同Padding

`