golang实现aes-cbc-256加密解密
我为什么吃撑了要实现go的aes-cbc-256加密解密功能?
之前的项⽬是⽤php实现的,现在准备⽤go重构,需要⽤到这个功能,这么常⽤的功能上⽹⼀搜⼀⼤把现成例⼦,于是基于go现有api分分钟实现⼀对加密解密函数,你想得没错,⼀跑就失败,好了不废话了,go的aes-cbc实现由两个限制
1:⾯临两个问题
1:go秘钥长度必须是16/24/32
go源码如下,我们的秘钥长度是72,不符合啊
// 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.
func NewCipher(key []byte) (cipher.Block, error) {
k := len(key)
switch k {
default:
return nil, KeySizeError(k)
case16, 24, 32:
break
}
return newCipher(key)
}
2:go根本不⽀持256位的aes-cbc加密解密
好脾⽓的我再次贴⼀下go的相关源码,赫然写着const BlockSize = 16,还他妈是个常量,也就是说go⼀次只能加密16*8=128位,我的php256位怎么迁移
const BlockSize = 16//你⼀眼就看到这么帅的我
type aesCipherAsm struct{
aesCipher
}
var useAsm = cipherhw.AESGCMSupport()
func newCipher(key []byte) (cipher.Block, error) {
if!useAsm {
return newCipherGeneric(key)
}
n := len(key) + 28
c := aesCipherAsm{aesCipher{make([]uint32, n), make([]uint32, n)}}
rounds := 10
switch len(key) {
case128/ 8:
rounds = 10
case192/ 8:
rounds = 12
case256/ 8:
rounds = 14
}
expandKeyAsm(rounds, &key[0], &[0], &c.dec[0])
if hasGCMAsm() {
return&aesCipherGCM{c}, nil
}
return&c, nil
}
func(c *aesCipherAsm) BlockSize() int { return BlockSize }
func(c *aesCipherAsm) Encrypt(dst, src []byte) {
if len(src) < BlockSize {
panic("crypto/aes: input not full block")
}
if len(dst) < BlockSize {
panic("crypto/aes: output not full block")
}
}
encryptBlockAsm()/4-1, &[0], &dst[0], &src[0])
}
func(c *aesCipherAsm) Decrypt(dst, src []byte) {
if len(src) < BlockSize {
panic("crypto/aes: input not full block")
}
if len(dst) < BlockSize {
panic("crypto/aes: output not full block")
}
decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0])
}
2:哥开始思考了
问题⼀个个击破,想办法看能不能绕过去,由于是在NewCipher的时候对必要长度做了限制,我⾃⼰new不就⾏了,⼀看傻眼了,只有接⼝是public,实现对象都是private的,要想实例化对象只能通过NewCipher,绕不过去啊,⼤不了我把你的源码拷出来,⾃⼰在改改,再次冲进go源码,并复制了出来,给个位看看先
//加密实现
TEXT ·encryptBlockAsm(SB),NOSPLIT,$0
MOVQ nr+0(FP), CX
<
Lenc256:
MOVUPS 0(AX), X1
<
Lenc196:
MOVUPS 0(AX), X1
<
Lenc128:
MOVUPS 0(AX), X1
666..
RET
//解密实现
/
/ func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
TEXT ·decryptBlockAsm(SB),NOSPLIT,$0
MOVQ nr+0(FP), CX
<
Ldec256:
MOVUPS 0(AX), X1
<
Ldec196:
MOVUPS 0(AX), X1
<
Ldec128:
MOVUPS 0(AX), X1
<
RET
//通过key和iv初始化加密解密所需的数据结构
// func expandKeyAsm(nr int, key *byte, enc, dec *uint32) {
// Note that round keys are stored in uint128 format, not uint32
TEXT ·expandKeyAsm(SB),NOSPLIT,$0
MOVQ nr+0(FP), CX
JE Lexp_enc196  //完全不知道是两个什么⿁命令
JB Lexp_enc128  //同上,所以说是两个⿁命令
Lexp_enc256:
MOVUPS 16(AX), X2
<
⾸长:同志们,跟我⼀起喊:源码在⼿,天下我有,
⼩弟:⼤哥,这源码好像有点不对劲啊
把部分代码拷出来,试着改了⼀下汇编代码,运⾏了⼀下,没成功
其实go也有⾮汇编实现的go代码,但每次也是加密16字节,不符合要求,我要每次处理32字节的源码,之后还尝试过把NewCipher出的对象包⼀层,让BlockSize()返回32,⾃然也是不⾏
第⼀阶段以失败告终
3:想⽤go调PHP
4:golang实现aes-cbc-256加密解密正式开始
第⼀步看PHP源码。按照⼊⼝⼀步步看下去,主要是以下⼏个函数
mcrypt_module_open
mcrypt_generic_init
mcrypt_generic
mdecrypt_generic
//获取加密key长度
func getKeySize(size int) int {
for_, val := range keySizes {
if size <= val {
return val
}
}
return BLOCK_SIZE
}
5:含着泪也要解决问题
实现完加密的时候,我就向⼤神吹⽜说,我已经实现,现在解密没解决,怎么办?
⼜是⼀阵看代码,没发现任何问题,只好使出终极杀⼿锏:单步对⽐调试,其实之前已经发现static word32 rtable[256];初始化不对了,为什么加密能成解密就不⾏,这个变量还真是只在解密⽤到,同步对⽐调试终于发现了问题,⼀个go语⾔不同于c语⾔的问题,且看下⾯这个函数:
//c语⾔实现
static byte bmul(byte x, byte y)
{
if(x && y)
return ptab[(ltab[x] + ltab[y]) % 255];
else
return0;
}
bmul(200,200) == 145
//go语⾔实现
func bmul(x, y byte) byte {
if x > 0 && y > 0 {
return ptab[(ltab[x]+ltab[y])%255]
}
return0
}
php实例代码解密bmul(200,200) == 144
朋友们啊,看到区别没有,前⾯说了,我是把c语⾔直接翻译成go语⾔的,但是c语⾔和go语⾔不⼀样啊,两个完全⼀样的函数,竟然不⼀样,c语⾔400%255=145好理解,go怎么就变成144了呢,200+200=144,我们来看看400的⼆进制表⽰110010000,去掉最前⾯的1,就是010010000,刚好144,也就是说c语⾔byte超过了255根本没关系,⽽go超过了255就给截断了,说好的互联⽹时代的c语⾔呢!
6:最后厚颜⽆耻的挂到了github

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。