一、HASH概述
Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数
Hash的特点:
-
算法是公开的
-
对相同数据运算,得到的结果是一样的
-
对不同数据运算,如MD5得到的结果默认是
128位,32个字符(16进制标识)。 -
这玩意
没法逆运算 -
信息摘要,信息“指纹”,是用来做数据识别的
非对称加密:RSA
对称加密:DES,3DES,AES
HASH:MD5,SHA1/256
二、HMAC
针对用户信息安全:
方案1:一个用户绑定一个hash值,使用这个hash值进行加盐处理。每个用户的盐不一样,增加用户信息的安全性。
方案2:一个用户绑定一个hash值,(hash值+当前时间).md5 得到新的hash值,服务器也用同样的(hash+当前时间).md5 匹配当前时间,和上一分钟匹配,这个hash值的有效时间是1分59秒。使用服务器的时间戳。
三、对称加密
1、对称加密算法
对称加密方式:明文通过密钥加密得到密文。密文通过密钥解密得到明文。
-
DES数据加密标准(用得少,因为强度不够) -
3DES使用3个密钥,对相同的数据执行3次加密,强度增强 -
AES高级密码标准。 -
ECB(Electronic Code Book):电子密码本模式。每一块数据,独立加密。最基本的加密模式,也就是通常理解的加密,相同的明文将永远加密成相同的密文,无初始向量,容易受到密码本重放攻击,一般情况下很少用。
-
CBC(Cipher Block Chaining):密码分组链接模式。使用一个密钥和一个初始化向量[IV]对数据执行加密。明文被加密前要与前面的密文进行异或运算后再加密,因此只要选择不同的初始向量,相同的密文加密后会形成不同的密文,这是目前应用最广泛的模式。CBC加密后的密文是上下文相关的,但明文的错误不会传递到后续分组,但如果一个分组丢失,后面的分组将全部作废(同步错误)。
CBC可以有效的保证密文的完整性,如果一个数据块在传递是丢失或改变,后面的数据将无法正常解密。
OpenSSL命令:
//加密:
//AES(ECB)加密“hello”字符串
$ echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
//AES(CBC)加密“hello”字符串
$ echo -n hello | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
//解密:
//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
2、对称加密演练
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//用户登录 -- 直接md5
NSString * pwd = @"123456";
//HMAC加密方案
/**
* 使用一个密钥加密,并且做了两次散列
* 在实际开发中,密钥来自于服务器
*/
pwd = [pwd hmacMD5StringWithKey:@"NYY"];
NSLog(@"现在的密码是:%@",pwd);
}
#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];
}
四、CCCrypt函数
/**
*kCCOptionPKCS7Padding CBC加密
*kCCOptionPKCS7Padding | kCCOptionECBMode ECB加密
*/
- (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
/**
1、kCCEncrypt 加密/kCCDecrypt 解密
2、加密算法。
3、加密选项:ECB/CBC
4、加密的密钥
5、密钥的长度
6、iv 初始化向量
7、加密的数据
8、加密的数据长度
9、密文的内存地址
10、密文缓冲区的大小
11、加密结果大小
*/
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];
}
加密使用代码:
/** AES - ECB 加密 */
NSString * key = @"abc";
NSString * encStr = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:nil];
NSLog(@"加密的结果是:%@",encStr);
NSLog(@"解密的结果是:%@",[[EncryptionTools sharedEncryptionTools] decryptString:encStr keyString:key iv:nil]);
/** AES - CBC 加密 */
NSString * key = @"abc";
uint8_t iv[8] = {1,2,3,4,5,6,7,8};
NSData * ivData = [NSData dataWithBytes:iv length:sizeof(iv)];
NSLog(@"加密的结果:%@",[[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:ivData]);
NSLog(@"解密的结果:%@",[[EncryptionTools sharedEncryptionTools] decryptString:@"u3W/N816uzFpcg6pZ+kbdg==" keyString:key iv:ivData]);