全栈汇总

浅析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;
上一篇下一篇

猜你喜欢

热点阅读