5.ios-HASH

282 阅读6分钟

Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数

Hash的特点

  • 算法是公开的
  • 对相同数据运算,得到的结果是一样的
  • 对不同数据运算,如MD5得到的结果默认是128位,32个字符(16进制标识)。
  • 这玩意没法逆运算
  • 信息摘要,信息“指纹”,是用来做数据识别的。
  • 由于结果的长度的一定的很可能结果是一样的 简称hash碰撞

用途

  • 用户密码的加密
  • 搜索引擎
  • 版权
  • 数字签名

密码加密

  • 通过运用HASH算法,给用户的密码进行加密。

  • 为什么不能用RSA来加密密码呢,因为如果是RSA加密明文就会存放在服务端。这样不能保证服务端的密码如果写恶意窃取就是导致用户密码的泄露所以不管是服务端还是前段都不能保存明文

  • 字符串->MD5加密

  • (字符串+盐)->MD5加密

  • HMAC 加密 盐由服务端提供不写死 一个账号一个Key

  • (key+字符串)MD5加密后加时间戳再MD5加密

数字签名

  • 目的:验证二进制数据是否为原始颁发机构颁发的。
  • 技术:如何判断数据是否被修改过
  • 流程:
    • 1.数据的传输过程中可能被修改
    • 2.数据+数据的hash值
    • 3.用同样的算法计算数据的hash值 验证数据是否被修改。hash值不同则数据被修改。
    • 4.hash值通过RSA加密后
    • 5.客户端解密RSA后得到HASH值与数据的同样算法后的HASH值作比较。
    • 这样就保证了数据传输过程中的可靠性

NSString+Hash 拓展类

//
//  NSString+Hash.h
//  EncryptDemo
//
//  Created by H on 2018/10/16.
//  Copyright © 2018年 hank. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface NSString (Hash)
    
#pragma mark - 散列函数
    /**
     *  计算MD5散列结果
     *
     *  终端测试命令:
     *  @code
     *  md5 -s "string"
     *  @endcode
     *
     *  <p>提示:随着 MD5 碰撞生成器的出现,MD5 算法不应被用于任何软件完整性检查或代码签名的用途。<p>
     *
     *  @return 32个字符的MD5散列字符串
     */
- (NSString *)md5String;
    
    /**
     *  计算SHA1散列结果
     *
     *  终端测试命令:
     *  @code
     *  echo -n "string" | openssl sha1
     *  @endcode
     *
     *  @return 40个字符的SHA1散列字符串
     */
- (NSString *)sha1String;
    
    /**
     *  计算SHA256散列结果
     *
     *  终端测试命令:
     *  @code
     *  echo -n "string" | openssl sha256
     *  @endcode
     *
     *  @return 64个字符的SHA256散列字符串
     */
- (NSString *)sha256String;
    
    /**
     *  计算SHA 512散列结果
     *
     *  终端测试命令:
     *  @code
     *  echo -n "string" | openssl sha512
     *  @endcode
     *
     *  @return 128个字符的SHA 512散列字符串
     */
- (NSString *)sha512String;
    
#pragma mark - HMAC 散列函数
    /**
     *  计算HMAC MD5散列结果
     *
     *  终端测试命令:
     *  @code
     *  echo -n "string" | openssl dgst -md5 -hmac "key"
     *  @endcode
     *
     *  @return 32个字符的HMAC MD5散列字符串
     */
- (NSString *)hmacMD5StringWithKey:(NSString *)key;
    
    /**
     *  计算HMAC SHA1散列结果
     *
     *  终端测试命令:
     *  @code
     *  echo -n "string" | openssl sha1 -hmac "key"
     *  @endcode
     *
     *  @return 40个字符的HMAC SHA1散列字符串
     */
- (NSString *)hmacSHA1StringWithKey:(NSString *)key;
    
    /**
     *  计算HMAC SHA256散列结果
     *
     *  终端测试命令:
     *  @code
     *  echo -n "string" | openssl sha256 -hmac "key"
     *  @endcode
     *
     *  @return 64个字符的HMAC SHA256散列字符串
     */
- (NSString *)hmacSHA256StringWithKey:(NSString *)key;
    
    /**
     *  计算HMAC SHA512散列结果
     *
     *  终端测试命令:
     *  @code
     *  echo -n "string" | openssl sha512 -hmac "key"
     *  @endcode
     *
     *  @return 128个字符的HMAC SHA512散列字符串
     */
- (NSString *)hmacSHA512StringWithKey:(NSString *)key;
    
#pragma mark - 文件散列函数
    
    /**
     *  计算文件的MD5散列结果
     *
     *  终端测试命令:
     *  @code
     *  md5 file.dat
     *  @endcode
     *
     *  @return 32个字符的MD5散列字符串
     */
- (NSString *)fileMD5Hash;
    
    /**
     *  计算文件的SHA1散列结果
     *
     *  终端测试命令:
     *  @code
     *  openssl sha1 file.dat
     *  @endcode
     *
     *  @return 40个字符的SHA1散列字符串
     */
- (NSString *)fileSHA1Hash;
    
    /**
     *  计算文件的SHA256散列结果
     *
     *  终端测试命令:
     *  @code
     *  openssl sha256 file.dat
     *  @endcode
     *
     *  @return 64个字符的SHA256散列字符串
     */
- (NSString *)fileSHA256Hash;
    
    /**
     *  计算文件的SHA512散列结果
     *
     *  终端测试命令:
     *  @code
     *  openssl sha512 file.dat
     *  @endcode
     *
     *  @return 128个字符的SHA512散列字符串
     */
- (NSString *)fileSHA512Hash;
    
    @end

//
//  NSString+Hash.m
//  EncryptDemo
//
//  Created by H on 2018/10/16.
//  Copyright © 2018年 hank. All rights reserved.
//

#import "NSString+Hash.h"
#import <CommonCrypto/CommonCrypto.h>

@implementation NSString (Hash)
    
#pragma mark - 散列函数
- (NSString *)md5String {
    const char *str = self.UTF8String;
    uint8_t buffer[CC_MD5_DIGEST_LENGTH];
    
    CC_MD5(str, (CC_LONG)strlen(str), buffer);
    
    return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
    
- (NSString *)sha1String {
    const char *str = self.UTF8String;
    uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
    
    CC_SHA1(str, (CC_LONG)strlen(str), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
    
- (NSString *)sha256String {
    const char *str = self.UTF8String;
    uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
    
    CC_SHA256(str, (CC_LONG)strlen(str), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
    
- (NSString *)sha512String {
    const char *str = self.UTF8String;
    uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
    
    CC_SHA512(str, (CC_LONG)strlen(str), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
    
#pragma mark - HMAC 散列函数
- (NSString *)hmacMD5StringWithKey:(NSString *)key {
    const char *keyData = key.UTF8String;
    const char *strData = self.UTF8String;
    uint8_t buffer[CC_MD5_DIGEST_LENGTH];
    
    CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer);
    
    return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
    
- (NSString *)hmacSHA1StringWithKey:(NSString *)key {
    const char *keyData = key.UTF8String;
    const char *strData = self.UTF8String;
    uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
    
    CCHmac(kCCHmacAlgSHA1, keyData, strlen(keyData), strData, strlen(strData), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
    
- (NSString *)hmacSHA256StringWithKey:(NSString *)key {
    const char *keyData = key.UTF8String;
    const char *strData = self.UTF8String;
    uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
    
    CCHmac(kCCHmacAlgSHA256, keyData, strlen(keyData), strData, strlen(strData), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
    
- (NSString *)hmacSHA512StringWithKey:(NSString *)key {
    const char *keyData = key.UTF8String;
    const char *strData = self.UTF8String;
    uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
    
    CCHmac(kCCHmacAlgSHA512, keyData, strlen(keyData), strData, strlen(strData), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
    
#pragma mark - 文件散列函数
    
#define FileHashDefaultChunkSizeForReadingData 4096
    
- (NSString *)fileMD5Hash {
    NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
    if (fp == nil) {
        return nil;
    }
    
    CC_MD5_CTX hashCtx;
    CC_MD5_Init(&hashCtx);
    
    while (YES) {
        @autoreleasepool {
            NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
            
            CC_MD5_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
            
            if (data.length == 0) {
                break;
            }
        }
    }
    [fp closeFile];
    
    uint8_t buffer[CC_MD5_DIGEST_LENGTH];
    CC_MD5_Final(buffer, &hashCtx);
    
    return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
    
- (NSString *)fileSHA1Hash {
    NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
    if (fp == nil) {
        return nil;
    }
    
    CC_SHA1_CTX hashCtx;
    CC_SHA1_Init(&hashCtx);
    
    while (YES) {
        @autoreleasepool {
            NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
            
            CC_SHA1_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
            
            if (data.length == 0) {
                break;
            }
        }
    }
    [fp closeFile];
    
    uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1_Final(buffer, &hashCtx);
    
    return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
    
- (NSString *)fileSHA256Hash {
    NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
    if (fp == nil) {
        return nil;
    }
    
    CC_SHA256_CTX hashCtx;
    CC_SHA256_Init(&hashCtx);
    
    while (YES) {
        @autoreleasepool {
            NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
            
            CC_SHA256_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
            
            if (data.length == 0) {
                break;
            }
        }
    }
    [fp closeFile];
    
    uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
    CC_SHA256_Final(buffer, &hashCtx);
    
    return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
    
- (NSString *)fileSHA512Hash {
    NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
    if (fp == nil) {
        return nil;
    }
    
    CC_SHA512_CTX hashCtx;
    CC_SHA512_Init(&hashCtx);
    
    while (YES) {
        @autoreleasepool {
            NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
            
            CC_SHA512_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
            
            if (data.length == 0) {
                break;
            }
        }
    }
    [fp closeFile];
    
    uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
    CC_SHA512_Final(buffer, &hashCtx);
    
    return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
    
#pragma mark - 助手方法
    /**
     *  返回二进制 Bytes 流的字符串表示形式
     *
     *  @param bytes  二进制 Bytes 数组
     *  @param length 数组长度
     *
     *  @return 字符串表示形式
     */
- (NSString *)stringFromBytes:(uint8_t *)bytes length:(int)length {
    NSMutableString *strM = [NSMutableString string];
    
    for (int i = 0; i < length; i++) {
        [strM appendFormat:@"%02x", bytes[i]];
    }
    
    return [strM copy];
}
    
    @end