浅析php加密的有关几个函数及iOS的实现
2017-12-10 本文已影响12人
_onePiece
最近对加密比较感兴趣,其中有一段加密算法的php的函数,着实让我花费的了一些时间才弄明白这个坑。由此记录下来,并阐述发现及解决问题本质的一点皮毛,当做抛砖引玉。
function hmacsha1($key, $data) {
$blocksize = 64;
$hashfunc = 'sha1';
if (strlen($key) > $blocksize)
$key = pack('H*', $hashfunc($key));
$key = str_pad($key, $blocksize, chr(0x00));
$ipad = str_repeat(chr(0x66), $blocksize);
$opad = str_repeat(chr(0x55), $blocksize);
$hmac = pack ('H*',(此处为$key,$ipad,$opad的一些逻辑运算))
//本文假设为$hmac = pack('H*', $hashfunc($key ^ $ipad.$key^$opad));
return bin2hex($hmac);
}
科普几个php的函数
pack(format,args) 函数把数据装入一个二进制字符串
参数 | 描述 |
---|---|
format | 必需。规定在包装数据时所使用的格式。 |
args+ | 可选。规定被包装的一个或多个参数。 |
代码中pack('H*', )是16进制打包。(其它参数类型)
example1:
<?php
echo pack("C*",80,72,80);
?>
输出:PHP
C*表示不带有符号的字符,此处为10进制,80,72,80对应的ASCII码为PHP
example2:
<?php
echo pack("H*",50,48,50);
?>
输出:PHP
H*表示十六进制字符串,此处为16进制,0x50 = 80; 0x48 = 72;结果同上。
bin2hex() 函数把 ASCII 字符的字符串转换为十六进制值。字符串可通过使用 pack() 函数再转换回去。unpack() 函数从二进制字符串对数据进行解包。
pack()和unpack()是成对的,pack加密数据,unpack()解密数据。这两个功能很强大,但是需要输入一些格式化的东西。感觉bin2hex()是在unpack()上封装了一下,使用起来更方便。
example1:
<?php
echo bin2hex("504850");
?>
输出:PHP
example2:
<?php
echo unpack('H*',"504850");
?>
输出:PHP
sha1为hash算法中的sha1加密
strlen($key)求字符串$key的长度
str_pad() 函数把字符串填充为新的长度。
参数 | 描述 |
---|---|
string | 必需。规定要填充的字符串。 |
length | 必需。规定新的字符串长度。如果该值小于字符串的原始长度,则不进行任何操作 |
pad_string | 可选。规定供填充使用的字符串。默认是空白。 |
pad_type | 可选。规定填充字符串的哪边。可能的值:STR_PAD_BOTH - 填充字符串的两侧。如果不是偶数,则右侧获得额外的填充。STR_PAD_LEFT - 填充字符串的左侧。*STR_PAD_RIGHT - 填充字符串的右侧。默认。 |
str_repeat() 函数把字符串重复指定的次数。
chr()进制数字字符转化ASCII字符
example:
<?php
echo str_repeat(chr(0x66), 3);
?>
输出:fff
ASCII中0x66--->f
至此上面的php一部分加密的算法应该是可以看懂了,开始oc的实现
刚刚开始没有想做太多的优化,用面向对象的思想来直接写,
具体的实现部分就不贴代码了,我直接写出方法的定义就可以。
实现思路很简单,对应的实现各个php中的函数就可以了.
可以新建一个Security的类
- (NSString *)pack:(NSString *)str;
- (NSString *)unpack:(NSString *)str;
- (NSString *)hashFunc:(NSString *)str;
- (NSString *)str_pad:(NSString *)str;
- (NSString *)hashfunc:(NSString *)str;
- (NSString *)str_repeat:(NSString *)str1 size:(NSIntger)size;
- (NSString *)hmacsha1:(NSString *)key data:(NSString *)data;
这个是相应的逻辑运算,比如同或 异或等等,具体的逻辑运算相应的计算。
主要是因为oc无法直接进行逻辑运算
example:0x36->6; 0x6b->[;=> 6 ^ [= m;
php 底层优化,6和[为二进制数据00110110(6)和01011011([)的存储方式,
然后进行^运算
01101101
00110110(6)
^
01011011([)
----------------
01101101(m)
这个方法里面为了逻辑运算会将字符遍历获取char类型,然后计算
- (NSString *)str1:(NSString *)str1 str2:(NSString *)str2;
基本上实现上面的方法就可以大功告成了,但是总会有意向不到的事情。
用以下一个例子来说明遇到的pack()和unpack()实现的问题。
php example:
<?php
for($a = 0; $a < 256; $a++) {
$b = pack('S*', $a);
$c = unpack('C*', $b);
echo "pack".$a."=".$b."******unpack".$b."=".$c[1]."\n";
}
oc example:
//这样会crash,characterAtIndex越界了,
//是因为会有不可见字符,str可能为nil,而nil转为ASCII码会出现问题
for (int i = 0; i < 256; i++) {
NSString *str = [NSString stringWithFormat:@"%c", (char)i];
NSLog(@"pack(%d) = %c,unpack(%c)=%d", i,(char)i, (char)i,[str characterAtIndex:0]);
}
?>
发生上面的情况着实没有想到,原先以为各个平台的ASCII应该会是完全一样的,以为ASCII转字符和字符转ASCII是完全一样的,可以相互转化而没有任何差异的。但是事实不是,各个平台有一些差异,比如php这个当为不可见字符是有问号表示,然后用bin2hex()解码还能够转回来,底层的优化我认为类似指针一样,存储的数据是没有变化的。基于数据存储的二进制数据是没有变化的,减少不必要的数据格式化,设计了以下的方法。
- (NSMutableData *)hashFunc:(NSData *)data;
- (NSString *)str_repeat:(NSInteger)size str:(NSString *)str;
//异或函数
- (NSData *)str1:(NSData *)str1Data str2:(NSData *)str2Data;
- (NSMutableData *)appendData:(NSData *)targetData data:(NSData *)data;
- (NSString *)convertPack:(NSData *)data;
- (NSData *) stringToHexData:(NSString *)hexStr;