iOS逆向攻防之HASH,数字签名,对称加密算法

在密码学中,加密部分主要分为对称加密非对称加密非对称加密主要有RSA非对称加密(使用公钥/私钥来加密解密),对称加密主要有DES/3DES/AES对称加密算法,顺带提一下我们今天介绍的Hash算法,Hash属于一种消息摘要算法,不属于加密算法,但是由于其单向运算,不可逆性,所以Hash是加密算法中的构成部分,Hash算法主要有MD5/Sha1/Sha2,这几个只是Hash算法加密精度有所不同。

那么紧接之前的非对称加密RSA,直接上这次的干货部分

1、Hash概述
2、数字签名
3、对称加密算法简介
4、对称加密算法终端命令
    5、对称加密算法终端演练
6、对称加密算法代码演练
7、CCCrypt函数

一、Hash概述


1、Hash的概念

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

2、Hash特点

1、算法是公开的
2、对相同的数据运算,得到的结果是一样的
3、对于不同的数据运算,如MD5(Hash算法的一种)的到的结果默认是128位的,32个字符(16进制标识)
4、没法逆运算(因为哈希值是映射关系,会存在散列碰撞【即:无限个数据加密得到有限个数据,就存在一个或许多个数据存在同样的哈希值】)
5、信息摘要,信息’指纹‘,一般是用来做数据识别的(由于没法做逆运算,所以一般不会用来做加密数据,只是把数据的哈希值取到,然后用来对比,做数据识别的)

3、Hash函数(单向散列函数)

1、MD5(Message Digest Algorithm 5)
2、SHA(Secure Hash Algorithm)
   SHA又分为:
   SHA-1
   SHA-2系列(224,256,384,512,512/224,512/256统称为SHA-2系列)
3、MAC(Message Authentication Code)
4、CRC(Cyclic Redundancy Check)
5、SM3(国产哈希算法)

4、Hash用途

1、用户密码的加密
2、搜索引擎
3、版权
4、数字签名(应用签名)

5、HMAC

什么是HMAC?HMAC(Hash-based message authentication code)是一种使用Hash函数(单向散列函数)来构造消息认证码的方法,利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。主要是为了能让人对对方身份正确性和消息有效性进行验证,与消息摘要的最大不同,就是有签名密钥!

HMAC通过两次hash两个不同的key来生成。 目前还没有发现有任何的方法来产生碰撞。

HMAC中所使用的单向散列函数并不仅限于一种,任何高强度的Hash函数(单向散列函数)都可以被用于HMAC。
比如使用SHA-1、SHA-224、SHA-256、SHA-384、SHA-512所构造的HMAC,分别称为HMAC-SHA1、HMAC-SHA-224、HMAC-SHA-384、HMAC-SHA-512。

二、数字签名


1、什么是数字签名

数字签名就是用于鉴别数字信息的方法;

2、数字签名

下面我们以电商支付金额这个场景来描述数字签名的具体意义:

数字签名理解示例.png

图示中,经过RSA加密的原商品信息Hash值这个整体就叫做数字签名。

数字签名的概念.png

三、对称加密概述


1、对称加密算法定义:

对称加密方式:就是明文通过密钥加密得到密文。密文通过密钥解密得到明文。

2、对称加密常见算法

1、DES(Data Encryption Standard):数据加密标准,速度较快,适用于加密大量数据的场合;(题外话:实际上用的不多,因为加密强度不够)
2、3DES(Triple DES):是基于DES的对称算法,对相同的数据用3个不同的密钥执行3次加密,强度更高;(题外话:不过因为3个密钥管理起来麻烦,所以一般不是很常用~一出生就挂掉了,很惨。。。)
3、RC2和RC4:用变长密钥对大量数据进行加密,比DES快哦~
4、AES(Advanced Encryption Standard):高级加密标准,是下一代的加密算法标准,速度快,安全级别高,在21世纪AES标准的一个实现是Rijndael算法;(题外话:很安全,苹果的钥匙串访问就是用的AES,美国国家安全局也是用的AES,想要暴力破解基本不可能)

3、对称加密应用模式
对称加密主要有两种应用模式,下面来详细介绍一下

ECB(Electronic Code Book):电子密码本模式。每一块数据, 独立加密。

ECB是最基本的加密方式,也就是通常理解的加密,相同的明文将永远加密成相同的密文,无初始向量,容易受到密码本重放攻击,一般情况下很少用。

CBC(Cipher Block Chaining):密码分组链接模式。使用一个密钥和一个初始化向量(IV)对数据进行加密。

CBC加密方式,明文被加密前要与前面的密文进行异或运算后再加密,因此只要选择不同的初始向量,相同的密文加密后会形成不同的密文,这是目前应用最广泛的模式。CBC加密后的密文是上下文相关的,但明文的错误不会传递到后续分组,但如果一个分组丢失,后面的分组将全部作废(同步错误).

CBC可以有效的保证密文的完整性,如果一个数据块在传递时丢失或者改变,后面的数据无法进行正常的解密。

四、对称加密算法终端命令


AES对称加密算法两种应用模式下的终端命令分别如下:
1、AES(ECB)的加密与解密

AES(ECB)加密'battleMage'字符串

$ echo -n battleMage | openssl enc -aes-128-ecb -K 616263 -nosalt | base64

AES(ECB)解密'battleMage'字符串

$ echo -n kXcE5nnetsinAMBEcK6D5g== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d

2、AES(CBC)的加密与解密

AES(CBC)加密'battleMage'字符串

$ echo -n battleMage | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64

AES(CBC)解密'battleMage'字符串

$ echo -n H3tn3dXCEtKNvijJYLsStw== | base64 -D | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -d

五、对称加密算法终端演练对比


1、新建一个message.txt文本文件

$ vi message.txt

回车进入编辑界面,点击'i',进入编辑界面,输入5排'1234567890',点击'esc',再点击'shift+:',输入'wq'回车保存。

message.txt文件.png

2、对该'message.txt'文件直接使用AES(ECB)进行加密,然后输出一个'meg1.bin'文件

$ openssl enc -des-ecb -K 616263 -nosalt -in message.txt -out meg1.bin

直接敲回车,得到一个 meg1.bin 的文件

然后直接修改message.txt文件,把最后一排的第一个1改成2,

AES(ECB)修改之后再次加密.png

再次使用上述命令进行加密,然后输出一个'meg2.bin'文件

$ openssl enc -des-ecb -K 616263 -nosalt -in message.txt -out meg2.bin

直接敲回车,得到一个 meg2.bin 的文件

接下来使用xxd命令查看meg1.bin 和 meg2.bin文件

同样通过AES(CBC)加密'message.txt'并输出一个‘meg3.bin’文件

$ openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -in message.txt -out meg3.bin

再次手动编辑message.txt文件,把message.txt还原,然后通过AES(CBC)加密并输出一个‘meg4.bin’文件

$ openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -in message.txt -out meg4.bin

对比如下图,

AES两种方式ECB和CBC的区别.png

六、对称加密算法代码演练


接下来开始代码演练部分,需要导入一个工具类,工具类代码并不多,这里直接贴工具类的内容吧,工具类头文件AES,DES各种终端命令也都包含在内了:

.h文件

#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCrypto.h>

/**
 *  终端测试指令
 *
 *  DES(ECB)加密
 *  $ echo -n hello | openssl enc -des-ecb -K 616263 -nosalt | base64
 *
 * DES(CBC)加密
 *  $ echo -n hello | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
 *
 *  AES(ECB)加密
 *  $ echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
 *
 *  AES(CBC)加密
 *  $ echo -n hello | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
 *
 *  DES(ECB)解密
 *  $ echo -n HQr0Oij2kbo= | base64 -D | openssl enc -des-ecb -K 616263 -nosalt -d
 *
 *  DES(CBC)解密
 *  $ echo -n alvrvb3Gz88= | base64 -D | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -d
 *
 *  AES(ECB)解密
 *  $ echo -n d1QG4T2tivoi0Kiu3NEmZQ== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d
 *
 *  AES(CBC)解密
 *  $ echo -n u3W/N816uzFpcg6pZ+kbdg== | base64 -D | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -d
 *
 *  提示:
 *      1> 加密过程是先加密,再base64编码
 *      2> 解密过程是先base64解码,再解密
 */
@interface EncryptionTools : NSObject
    
+ (instancetype)sharedEncryptionTools;
    
    /**
     @constant   kCCAlgorithmAES     高级加密标准,128位(默认)
     @constant   kCCAlgorithmDES     数据加密标准
     */
    @property (nonatomic, assign) uint32_t algorithm;
    
    /**
     *  加密字符串并返回base64编码字符串
     *
     *  @param string    要加密的字符串
     *  @param keyString 加密密钥
     *  @param iv        初始化向量(8个字节)
     *
     *  @return 返回加密后的base64编码字符串
     */
- (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv;
    
    /**
     *  解密字符串
     *
     *  @param string    加密并base64编码后的字符串
     *  @param keyString 解密密钥
     *  @param iv        初始化向量(8个字节)
     *
     *  @return 返回解密后的字符串
     */
- (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv;
    
    @end


.m文件

#import "EncryptionTools.h"

@interface EncryptionTools()
    @property (nonatomic, assign) int keySize;
    @property (nonatomic, assign) int blockSize;
    @end

@implementation EncryptionTools
    
+ (instancetype)sharedEncryptionTools {
    static EncryptionTools *instance;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
        instance.algorithm = kCCAlgorithmAES;
    });
    
    return instance;
}
    
- (void)setAlgorithm:(uint32_t)algorithm {
    _algorithm = algorithm;
    switch (algorithm) {
        case kCCAlgorithmAES:
        self.keySize = kCCKeySizeAES128;
        self.blockSize = kCCBlockSizeAES128;
        break;
        case kCCAlgorithmDES:
        self.keySize = kCCKeySizeDES;
        self.blockSize = kCCBlockSizeDES;
        break;
        default:
        break;
    }
}
    
- (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
    
    // 设置秘钥
    NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t cKey[self.keySize];
    bzero(cKey, sizeof(cKey));
    [keyData getBytes:cKey length:self.keySize];
    
    // 设置iv
    uint8_t cIv[self.blockSize];
    bzero(cIv, self.blockSize);
    int option = 0;
    if (iv) {
        [iv getBytes:cIv length:self.blockSize];
        option = kCCOptionPKCS7Padding;
    } else {
        option = kCCOptionPKCS7Padding | kCCOptionECBMode;
    }
    
    // 设置输出缓冲区
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    size_t bufferSize = [data length] + self.blockSize;
    void *buffer = malloc(bufferSize);
    
    // 开始加密
    size_t encryptedSize = 0;
    //加密解密都是它 -- CCCrypt
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          self.algorithm,
                                          option,
                                          cKey,
                                          self.keySize,
                                          cIv,
                                          [data bytes],
                                          [data length],
                                          buffer,
                                          bufferSize,
                                          &encryptedSize);
    
    NSData *result = nil;
    if (cryptStatus == kCCSuccess) {
        result = [NSData dataWithBytesNoCopy:buffer length:encryptedSize];
    } else {
        free(buffer);
        NSLog(@"[错误] 加密失败|状态编码: %d", cryptStatus);
    }
    
    return [result base64EncodedStringWithOptions:0];
}
    
- (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
    
    // 设置秘钥
    NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t cKey[self.keySize];
    bzero(cKey, sizeof(cKey));
    [keyData getBytes:cKey length:self.keySize];
    
    // 设置iv
    uint8_t cIv[self.blockSize];
    bzero(cIv, self.blockSize);
    int option = 0;
    if (iv) {
        [iv getBytes:cIv length:self.blockSize];
        option = kCCOptionPKCS7Padding;
    } else {
        option = kCCOptionPKCS7Padding | kCCOptionECBMode;
    }
    
    // 设置输出缓冲区
    NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
    size_t bufferSize = [data length] + self.blockSize;
    void *buffer = malloc(bufferSize);
    
    // 开始解密
    size_t decryptedSize = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                          self.algorithm,
                                          option,
                                          cKey,
                                          self.keySize,
                                          cIv,
                                          [data bytes],
                                          [data length],
                                          buffer,
                                          bufferSize,
                                          &decryptedSize);
    
    NSData *result = nil;
    if (cryptStatus == kCCSuccess) {
        result = [NSData dataWithBytesNoCopy:buffer length:decryptedSize];
    } else {
        free(buffer);
        NSLog(@"[错误] 解密失败|状态编码: %d", cryptStatus);
    }
    
    return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}
    
    @end

接下来新建工程,把工具类.h,.m拖入工程,在ViewController.m实现touchBegin方法

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSString * key = @"abc";
    uint8_t iv[8] = {1,2,3,4,5,6,7,8};
    
    //备注:选择的是AES(ECB), 初始向量iv直接传nil,如果选择 AES(CBC),初始向量iv需要传值,具体可见工具类.m文件中实现,是判断iv是否为nil来选取加密方式的
    //1、选择AES(ECB)
    NSString * encStr =  [[EncryptionTools sharedEncryptionTools]encryptString:@"hello" keyString:key iv:nil];
    
    NSLog(@"AES(ECB)加密的结果是:%@", encStr);
    NSLog(@"AES(ECB)解密的结果是:%@", [[EncryptionTools sharedEncryptionTools]decryptString:encStr keyString:key iv:nil]);
    
    //2、选择AES(CBC)
    NSData * ivData = [NSData dataWithBytes:iv length:sizeof(iv)];
    NSString * encStr1 =  [[EncryptionTools sharedEncryptionTools]encryptString:@"hello" keyString:key iv:ivData];
    
    NSLog(@"AES(CBC)加密的结果是:%@", encStr1);
    NSLog(@"AES(CBC)解密的结果是:%@", [[EncryptionTools sharedEncryptionTools]decryptString:encStr1 keyString:key iv:ivData]);
    
}


@end


点击运行,运行结果OK

2019-10-12 21:57:26.858675+0800 CryptDemo[1790:115503] AES(ECB)加密的结果是:d1QG4T2tivoi0Kiu3NEmZQ==
2019-10-12 21:57:26.858896+0800 CryptDemo[1790:115503] AES(ECB)解密的结果是:hello
2019-10-12 21:57:26.859040+0800 CryptDemo[1790:115503] AES(CBC)加密的结果是:u3W/N816uzFpcg6pZ+kbdg==
2019-10-12 21:57:26.859194+0800 CryptDemo[1790:115503] AES(CBC)解密的结果是:hello

七、CCCrypt函数


第六步已经使用过封装好的加密工具类EncryptionTools.h,这个工具类只是封装了CCCrypt函数,下面我们来研究一下加密工具的核心函数CCCrypt函数:

使用CCCrypt函数,需要引入系统库

#import <CommonCrypto/CommonCrypto.h>

不管是加密还是解密都是使用这个函数,下面我们来介绍一下这个函数中的参数,参数解释我直接备注在API的后面,注意里面有坑!!!

CCCrypt函数

参数介绍
1、 CCOperation op :操作类型:加密or解密,枚举值;
    kCCEncrypt 代表加密
    kCCDecrypt 代表解密

2、 CCAlgorithm alg:加密算法,枚举值;
    kCCAlgorithmAES     高级加密标准,128位(默认)
    kCCAlgorithmDES     数据加密标准
    
3、 CCOptions options:加密应用模式,枚举值;
    注意注意!!!!!!!!!!这里有个坑;kCCOptionPKCS7Padding代表填充模式,这个options必须加上填充模式;
    CCCrypt的option默认是CBC,所以只需要补充一个填充模式就能代表CBC; 但是ECB就需要额外再加上一个kCCOptionECBMode,所以选择ECB就需要kCCOptionPKCS7Padding | kCCOptionECBMode;
    
    所以想要选择CBC和ECB,需要按下面进行填写!
    kCCOptionPKCS7Padding;  代表CBC
    kCCOptionPKCS7Padding | kCCOptionECBMode; 代表ECB

4、 const void *key :加密的密钥的指针
5、 size_t keyLength:密钥的长度
6、 const void *iv: 初始化向量
7、 const void *dataIn:加密的原始数据
8、 size_t dataInLength:加密的原始数据的长度
9、 void *dataOut:加密后密文的内存地址
10、size_t dataOutAvailable:加密后密文的缓冲区大小
11、size_t *dataOutMoved :加密结果的大小


CCCryptorStatus CCCrypt(
    CCOperation op,         /* kCCEncrypt, etc. */
    CCAlgorithm alg,        /* kCCAlgorithmAES128, etc. */
    CCOptions options,      /* kCCOptionPKCS7Padding, etc. */
    const void *key,
    size_t keyLength,
    const void *iv,         /* optional initialization vector */
    const void *dataIn,     /* optional per op and alg */
    size_t dataInLength,
    void *dataOut,          /* data RETURNED here */
    size_t dataOutAvailable,
    size_t *dataOutMoved)


需要注意的是,直接使用这个函数安全隐患非常的大!因为这个函数是系统提供的,不管你是加密还是解密,都是调用了CCCrypt函数,而黑客可以通过越狱手机附加调试或者是非越狱手机重签调试,能够用函数断点断到你的CCCrypt函数,然后通过寄存器直接获取函数的对应参数,根据上面函数的介绍,我们的数据其实是其中的第七个参数'const void *dataIn', 第七个参数的下标为6, 然后调用汇编指令'x6',就可以拿到你的数据的地址,然后转一下类型,就能直接打印出你的加密数据!具体操作如下:

1、还是打开之前的工程,设置函数断点CCCrypt,然后使用真机运行!!!必须用真机,因为真机和模拟器的CPU不一样

1、符号断点设置为CCCrypt.png

2、运行工程,模拟黑客调试,然后点击屏幕出发touchBegin方法,然后断点停在了CCCrypt函数的地方

3、因为函数在调用的时候,都是存在CPU的寄存器上,输入寄存器查看指令

register read x6

read x6是读取该函数对应的第7个参数,第一个参数是x0

4、拿到地址,然后强转类型,蒙圈了吧,你的数据就泄漏了

2、寄存器读取加密的数据.png

所以这个函数不能直接使用,现在只说基础,后面会详细说安全防护今天就说到这里了

溪浣双鲤的技术摸爬滚打之路

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 这篇文章主要讲述在Mobile BI(移动商务智能)开发过程中,在网络通信、数据存储、登录验证这几个方面涉及的加密...
    雨_树阅读 2,235评论 0 6
  • 这里先简单介绍单向散列函数、消息摘要和哈希碰撞的的概念 单向散列函数: 将任意长度的信息转换为较短的固定长度的值,...
    坤_7a1e阅读 3,362评论 0 0
  • HASH 现在在处理App的用户敏感信息方面,大部分都是采用HASH加密的方式来进行处理。 关于哈希算法 详细看这...
    Phant阅读 11,017评论 0 0
  • 工作或者面试过程中我们总会接触到密码相关的技术和问题,本篇文章是我对近期阅读《图解密码技术》的总结,这本书很值得推...
    乐Coding阅读 1,400评论 0 5
  • 笔记的艺术,让你的效率upupup! 当代人的生活是快节奏的,但是与其说快节奏,更好的步调是时缓时急。不但要能跟上...
    水木十一阅读 1,108评论 0 4