iOS开发单向散列函数:MD5及SHA1-SHA224-SHA2

2019-11-26  本文已影响0人  YYFast

1.1 单向散列函数

单向散列函数(One-way hash function),也称之为消息摘要函数(Message Digest Function),哈希函数,它可以根据消息的内容计算出一个散列值;
输出的散列值,也被称为消息摘要(message digest)、指纹(fingerprint);

1.2 单向散列函数的特点

1.散列值的长度与消息的长度<mark>无关</mark>,无论消息是1bit、10M、100G,单向散列函数都会计算出<mark>固定长度</mark>的散列值,如下图:

单向散列函数

2.计算速度快,能快速的计算出散列值;

3.消息不同,散列值也不同;

4.具备单向性:无法通过散列值反推出原始消息内容

单向性

2.1 单向散列函数常见类型

·MD4:具有3轮16步,输出位长度为128位。
·MD5:具有4轮16步,输出位长128位。
·SHA-1:具有4个20阶的步长和160位的输出位长度。
·SHA-256:具有64轮单步,输出位长度为256位。
·SHA-384:实际上与SHA-512相同,除了输出被截断为383位。
·SHA-512:具有80个单步的轮数和512位的输出位长度。


2.1.1 MD4:

MD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年设计的,MD 是 Message Digest 的缩写。它适用在32位字长的处理器上用高速软件实现--它是基于 32 位操作数的位操作来实现的。它的安全性不像RSA那样基于数学假设,尽管 Den Boer、Bosselaers 和 Dobbertin 很快就用分析和差分成功的攻击了它3轮变换中的 2 轮,证明了它并不像期望的那样安全,但它的整个算法并没有真正被破解过,Rivest 也很快进行了改进。


2.1.2 MD5:

MD5(RFC 1321)是 Rivest 于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联,与 MD4 相同。它较MD4所做的改进是:

  1. 加入了第四轮
  2. 每一步都有唯一的加法常数;
  3. 第二轮中的G函数从((X ∧ Y) ∨ (X ∧ Z) ∨ (Y ∧ Z)) 变为 ((X ∧ Z) ∨ (Y ∧ ~Z))以减小其对称性;
  4. 每一步都加入了前一步的结果,以加快"雪崩效应";
  5. 改变了第2轮和第3轮中访问输入子分组的顺序,减小了形式的相似程度;
  6. 近似优化了每轮的循环左移位移量,以期加快"雪崩效应",各轮的循环左移都不同。
    尽管MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好。

使用终端查看字符串或者文件的MD5值:
md5 -s 字符串
md5 文件路径

//字符串
md5 -s 24324
MD5 ("24324") = fb2e636577105f243646d6f1e199f0ba

//文件
MD5 /Users/i/Desktop/2.pdf
MD5 (/Users/i/Desktop/2.pdf) = bd32d590689394cae6a3f234a33ca93c

iOS实现字符串转MD5:

#import "NSString+MD5.h"
@implementation NSString (MD5)

- (NSString *)MD5String{
    //传入参数,转化成char
    const char * str = [self UTF8String];
    //开辟一个16字节(128位:md5加密出来就是128位/bit)的空间(一个字节=8字位=8个二进制数)
    unsigned char md[CC_MD5_DIGEST_LENGTH];
    /*
     extern unsigned char * CC_MD5(const void *data, CC_LONG len, unsigned char *md)官方封装好的加密方法
     把str字符串转换成了32位的16进制数列(这个过程不可逆转) 存储到了md这个空间中
     */
    CC_MD5(str, (int)strlen(str), md);
    //创建一个可变字符串收集结果
    NSMutableString * ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        /**
         X 表示以十六进制形式输入/输出
         02 表示不足两位,前面补0输出;出过两位不影响
         printf("%02X", 0x123); //打印出:123
         printf("%02X", 0x1); //打印出:01
         */
        [ret appendFormat:@"%02X",md[i]];
    }
    //返回一个长度为32的字符串
    return ret;
}
@end

ios实现NSData转H5

#import "NSData+MD5.h"
#import <CommonCrypto/CommonDigest.h>
@implementation NSData (MD5)
-(NSData *)MD5Data{
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(self.bytes, (CC_LONG)self.length, result);
    return [NSData dataWithBytes:result length:CC_MD5_DIGEST_LENGTH];
}
@end

2.1.3 SHA1-SHA224-SHA256-SHA384-SHA512:

- (NSString *) sha1String{  
    NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
    
    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
    
    CC_SHA1(data.bytes, (unsigned int)data.length, digest);
    
    NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
    
    for(int i=0; i<CC_SHA1_DIGEST_LENGTH; i++) {
        [output appendFormat:@"%02x", digest[i]];
    }
    
    return output;
}

-(NSString *)sha224String{
    const char *cstr=[self cStringUsingEncoding:NSUTF8StringEncoding];
    
    NSData*data=[NSData dataWithBytes:cstr length:self.length];
    
    uint8_t digest[CC_SHA224_DIGEST_LENGTH];
    
    CC_SHA224(data.bytes, (unsigned int)data.length, digest);
    
    NSMutableString*output=[NSMutableString stringWithCapacity:CC_SHA224_DIGEST_LENGTH*2];
    
    for(int i=0; i < CC_SHA224_DIGEST_LENGTH; i++){
        [output appendFormat:@"%02x", digest[i]];
    }
    
    return output;
}

- (NSString *)sha256String{
    const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
    
    NSData *data = [NSData dataWithBytes:cstr length:self.length];
 
    uint8_t digest[CC_SHA256_DIGEST_LENGTH];
 
    CC_SHA256(data.bytes,(CC_LONG)data.length, digest);
 
    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
 
    for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++){
        [output appendFormat:@"%02x", digest[i]];
    }
    
    return output;
}

- (NSString *)sha384String
{
    const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];  
    
    NSData *data = [NSData dataWithBytes:cstr length:self.length];
 
    uint8_t digest[CC_SHA384_DIGEST_LENGTH];
 
    CC_SHA384(data.bytes,(CC_LONG) data.length, digest);
 
    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA384_DIGEST_LENGTH * 2];
 
    for(int i = 0; i < CC_SHA384_DIGEST_LENGTH; i++){
        [output appendFormat:@"%02x", digest[i]];
    }
 
    return output;
}

- (NSString *)sha512String
{
    const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
    
    NSData *data = [NSData dataWithBytes:cstr length:self.length];
 
    uint8_t digest[CC_SHA512_DIGEST_LENGTH];
 
    CC_SHA512(data.bytes, (CC_LONG)data.length, digest);
 
    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA512_DIGEST_LENGTH * 2];
 
    for(int i = 0; i < CC_SHA512_DIGEST_LENGTH; i++){
        [output appendFormat:@"%02x", digest[i]];
    }
    
    return output;
}

3 单向散列函数的应用

3.1 某些大型软件的官网会公布软件的散列值,防止软件被篡改

软件生成散列值防伪

例如: vnc官网下载链接,会有软件的SHA256生成的散列值:

vnc官网软件散列值示例

3.2 服务器存放的用户的密码不是明文的,而是对应密码的散列值,比如SHA2(密码)

用户密码服务端存放示例
服务器中存放的不是用户密码的明文,如果存放的是密码明文,风险太高,一般存放的是对应用户名的密码的散列值,在用户登录的时候,通过散列值与数据库中的散列值对比,如果相同则登录成功.
上一篇下一篇

猜你喜欢

热点阅读