坑货libmcrypt

今天接触的了一个php版本的 aes-128-cbc

en/de原文如下


class SecretUtil {
    public static $hex_iv = '00000000000000000000000000000000'; # converted JAVA byte code in to HEX and placed it here
    //public static $hex_iv = 'EDD80600A09CFBCB4B152C2B2FAAA237'; # converted JAVA byte code in to HEX and placed it here
    public static $key='my key';

    public static function setKey(){
        self::$key = hash('sha256', self::$key, true);
    }

    public static function encrypt($str){
        self::setKey();

        $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
        mcrypt_generic_init($td, self::$key, self::hexToStr(self::$hex_iv));

        $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        $pad = $block - (strlen($str) % $block);
        $str .= str_repeat(chr($pad), $pad);
        $encrypted = mcrypt_generic($td, $str);
        mcrypt_generic_deinit($td);
        mcrypt_module_close($td);

        return base64_encode($encrypted);
    }
}


看起来好简单的样子。可是我发现怎么也还原不了,无头绪了半天。。。。。。真的半天,直到发现libmcrypt的确是个坑货 


If you're writing code to encrypt/encrypt data in 2015, you should use openssl_encrypt() and openssl_decrypt(). The underlying library (libmcrypt) has been abandoned since 2007, and performs far worse than OpenSSL (which leverages AES-NI on modern processors and is cache-timing safe).


Also, MCRYPT_RIJNDAEL_256 is not AES-256, it's a different variant of the Rijndael block cipher. If you want AES-256 in mcrypt, you have to use MCRYPT_RIJNDAEL_128 with a 32-byte key. OpenSSL makes it more obvious which mode you are using (i.e. 'aes-128-cbc' vs 'aes-256-ctr').


那么好吧。事情就简单了
 self::$key = hash('sha256', self::$key, true);
 这个坑就填了。原来的加解密其实是使用的aes-256-cbc
 第二个坑容易找  $pad = $block - (strlen($str) % $block);
 正好加密内容的长度为 block_size,也就是16时,这家伙会直接追加16个0x10,这个比较有个性。所以使用openssl时也不能使用padding了,得自己来
 我们来试试对应的ruby实现

#encoding:utf-8
require 'openssl'
require 'base64'
key=OpenSSL::Digest::SHA256.digest('my key') 

%w(AES-128-CBC AES-256-CBC).each do |flavour|
	string ='12345678901234561234567890123456asfg'
 	c = OpenSSL::Cipher::Cipher .new flavour
   	pad= c.block_size - string.length % c.block_size 
   	str=string 
   	str<<  Array.new(pad){|x| x=pad}.pack('c*') #unless  pad == 16
   	puts "string pad #{pad} to #{str.length}: #{str.unpack('H*')[0]}"
   
 	c.encrypt
	c.padding=0
	c.key = key
	iv=Array.new(16,0).pack('c*')
	c.iv=iv
 
	enc = c.update(str) + c.final
    en_str=Base64.strict_encode64(enc)
	puts "#{flavour} encrypt #{string} \r\n#{en_str}"

	#解密过程
	d=  OpenSSL::Cipher::Cipher .new flavour
	d.decrypt
	d.padding=0
	d.key=key
	d.iv=iv
	dec=Base64.strict_decode64(en_str)
	de_str=d.update(dec)+ d.final
	puts "#{flavour} decrypt #{en_str} \r\n#{de_str.unpack('H*')[0]}"

	#前面填的坑要自己来埋,去掉最后的padding个padding字符
	last_char=de_str[-1,1].ord
 	padding=Array.new(last_char,last_char).pack('c*') 
 	puts "padding #{padding.unpack('H*')[0] }"
	de_str=de_str[0,de_str.length-padding.length] if de_str.end_with?(padding) 
	puts "drop padding #{de_str} \r\nhex:#{de_str.unpack('H*')[0]}"
end
 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值