Base64
参考网站:http://zh.wikipedia.org/wiki/Base64
简介
是网络上使用最广泛的编码系统,能够将任何二进制数据,转换成只有 65 个字符组成的文本文件
a~z,A~Z,0~9,+,/,=
Base 64 编码后的结果能够反算,不够安全
Base 64 是所有现代加密算法的基础算法
终端命令
# 将 10.jpg 进行 base64 编码,生成 10.txt 文件
$ base64 10.jpg -o 10.txt
# 将 10.txt 解码生成 1.jpg 文件
$ base64 -D 10.txt -o 1.jpg
# 将字符串 Man 进行 base64 编码
$ echo -n "Man" | base64
# 将字符串 TWFu 解码
$ echo -n "TWFu" | base64 -D
代码实现
/// BASE 64 编码
- (NSString *)base64Encode:(NSString *)str {
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
return [data base64EncodedStringWithOptions:0];
}
/// BASE 64 解码
- (NSString *)base64Decode:(NSString *)str {
NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:0];
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
保存 和 加载用户信息
/// 保存用户信息
- (void)saveUserInfo {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:self.usernameText.text forKey:HMUserNameKey];
NSString *pwd = [self base64Encode:self.pwdText.text];
[defaults setObject:pwd forKey:HMUserPwdKey];
[defaults synchronize];
}
/// 加载用户信息
- (void)loadUserInfo {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
self.usernameText.text = [defaults objectForKey:HMUserNameKey];
self.pwdText.text = [self base64Decode:[defaults objectForKey:HMUserPwdKey]];
}
存在的问题
使用 Base 64 不能直接看到用户密码的明文
但是 Base 64 的算法是公开的,并且算法可逆,所以安全性并不好
密码学
现代密码学 - 所有加密算法都是公开的!
散列(哈希)函数
MD5/SHA1/SHA256(美国国家安全局/苹果)/SHA512
对任意一个二进制数据进行加密,可以得到定长的字符串结果
MD5 加密结果是 32 个字符
核心思想是从给定的数据中,抽取特征码,不容易产生重复!加密后的字符串通常被称为“指纹”“信息摘要”
MD5 因为数据长度不够,现在国外基本上已经不怎么用了!国内用的很普遍
王小云
破解网站:http://www.cmd5.com
相同的字符串,使用相同的算法,每次加密的结果是固定的
MD5
约定
同样的密码,同样的加密算法,每次加密的结果是不一样
方案一 直接 MD5
pwd = pwd.md5String;
方案二 MD5 + 盐
pwd = [pwd stringByAppendingString:salt].md5String;
MD5 安全方案三 - HMAC
pwd = [pwd hmacMD5StringWithKey:@"haliluya"];
MD5 安全方案四 - 时间戳密码
pwd = [self timePassword];
/// 生成时间戳密码
- (NSString *)timePassword {
// 1. 以 suday.md5 作为 hmac key
NSString *key = @"sunday".md5String;
NSLog(@"HMAC KEY - %@", key);
// 2. 对用户密码 HMAC 加密
NSString *pwd = [self.pwd hmacMD5StringWithKey:key];
// 3. 取出当前系统时间
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat = @"yyyy-MM-dd HH:mm";
NSString *dateStr = [fmt stringFromDate:[NSDate date]];
// 4. 拼接时间字符串
pwd = [pwd stringByAppendingString:dateStr];
// 5. 再次 hmac 散列密码
return [pwd hmacMD5StringWithKey:key];
}
MD5 安全方案五 - 服务器时间戳密码
/// 生成时间戳密码
- (NSString *)timePassword:(NSString *)pwd {
// 1. 以 itheima.md5 作为 hmac key
NSString *key = @"itheima".md5String;
NSLog(@"HMAC KEY - %@", key);
// 2. 对密码进行 hamc
NSString *pwd = [self.pwd hmacMD5StringWithKey:key];
// 3. 取服务器时间
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://localhost/hmackey.php"]];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
NSString *dateStr = dict[@"key"];
// 4. 拼接时间字符串
pwd = [pwd stringByAppendingString:dateStr];
// 5. 再次 hmac 散列密码
return [pwd hmacMD5StringWithKey:key];
}
对称加密算法
加密和解密使用同一个秘钥,加密解密的速度快
适合给大数据进行加密
注意:秘钥的安全性非常重要
使用 RSA 给对称加密算法的秘钥进行加密
非对称加密算法 RSA
使用 公钥 加密,使用 私钥 解密
使用 私钥 加密,使用 公钥 解密
更安全
但是加密解密的速度极慢!
适合给小数据进行加密
对称加密算法 - 传统加密算法
加密和解密使用同一个密钥
优缺点
优点
算法公开、计算量小、加密速度快、加密效率高
缺点
双方使用相同钥匙,安全性得不到保证
注意事项
密钥的保密工作非常重要
密钥要求定期更换
经典算法
- DES 数据加密标准(用的少,因为强度不够)
- 3DES 使用3个密钥,对相同的数据执行三次加密,强度增强
- AES 高级加密标准,目前美国国家安全局使用的
- 苹果的钥匙串访问采用的是 AES 加密
ECB & CBC
ECB :电子代码本,就是说每个块都是独立加密的
CBC :密码块链,使用一个密钥和一个初始化向量 (IV)对数据执行加密转换
OpenSSL 终端测试命令
ECB
# 加密
$ openssl enc -des-ecb -K 616263 -nosalt -in msg1.txt -out msg1.bin
# 解密
$ openssl enc -des-ecb -K 616263 -nosalt -in msg1.bin -out msg1.txt -d
# 查看加密之后的二进制文件
$ xxd msg1.bin
CBC
# 加密
$ openssl enc -des-cbc -K 616263 -iv 0000000000000000 -nosalt -in a.txt -out msg1.bin
# 解密
$ openssl enc -des-cbc -K 616263 -iv 0000000000000000 -nosalt -in msg1.bin -out msg4.txt -d
# 查看加密之后的二进制文件
$ xxd msg1.bin
CBC加密可以有效地保证密文的完整性,也就是说如果有一个块在传送时丢失了(或被敌人改变了),就会导致后面所有的块无法正常解密这个特性可以用来防范一些窃听技巧
代码示例:
// EBC 加密
NSLog(@"%@", [CryptorTools AESEncryptString:@"hello" keyString:@"abc" iv:nil]);
NSLog(@"%@", [CryptorTools AESDecryptString:@"d1QG4T2tivoi0Kiu3NEmZQ==" keyString:@"abc" iv:nil]);
// CBC 加密
uint8_t iv[8] = {1, 2, 3, 4, 5, 6, 7, 8};
NSData *ivData = [NSData dataWithBytes:iv length:8];
NSLog(@"%@", [CryptorTools AESEncryptString:@"hello" keyString:@"abc" iv:ivData]);
NSLog(@"%@", [CryptorTools AESDecryptString:@"u3W/N816uzFpcg6pZ+kbdg==" keyString:@"abc" iv:ivData]);
OpenSSL 终端测试命令
ECB 加密/解密
# AES(ECB)加密
$ echo -n "hello" | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
# AES(ECB)解密
$ echo -n "d1QG4T2tivoi0Kiu3NEmZQ==" | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d
CBC 加密/解密
# AES(CBC)加密
$ echo -n "hello" | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
AES(CBC)解密
$ echo -n "u3W/N816uzFpcg6pZ+kbdg==" | base64 -D | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -d
终端命令说明
加密过程是先加密,再base64编码
解密过程是先base64解码,再解密
| 是终端管道命令,会将前一个命令结果传递给后一个命令
-K 使用的密钥需要是密钥的 ASCII 码
非对称加密算法
介绍
非对称加密算法需要两个密钥:公开密钥(publickey) 和 私有密钥(privatekey)
公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密
特点
算法强度复杂、安全性依赖于算法与密钥
加密解密速度慢
与对称加密算法的对比
- 对称加密只有一种密钥,并且是非公开的,如果要解密就得让对方知道密钥
- 非对称密钥体制有两种密钥,其中一个是公开的
RSA 算法原理
找出两个“很大”的质数:P & Q
N = P * Q
M = (P – 1) * (Q – 1)找出整数E,E与M互质,即除了1之外,没有其他公约数
找出整数D,使得 ED 除以 M 余 1,即 (E D) % M = 1
经过上述准备工作之后,可以得到:
- E是公钥,负责加密
- D是私钥,负责解密
- N负责公钥和私钥之间的联系
加密算法,假定对X进行加密
- (X ^ E) % N = Y
解密算法,根据费尔马小定义,可以使用以下公式完成解密
- (Y ^ D) % N = X
代码示例:
CryptorTools *tools = [[CryptorTools alloc] init];
// 1. 加载公钥
NSString *pubKeyPath = [[NSBundle mainBundle] pathForResource:@"rsacert.der" ofType:nil];
[tools loadPublicKeyWithFilePath:pubKeyPath];
// 2. 使用公钥加密数据
NSString *cipher = [tools RSAEncryptString:@"abcdefghijklmnopqrstuvwxyz1234567890"];
NSLog(@"%@", cipher);
// 3. 加载私钥
NSString *privateKeyPath = [[NSBundle mainBundle] pathForResource:@"p.p12" ofType:nil];
[tools loadPrivateKey:privateKeyPath password:@"123"];
// 4. 解密数据
NSLog(@"%@", [tools RSADecryptString:cipher]);
iOS 相关函数
- SecKeyEncrypt 使用公钥对数据加密
- SecKeyDecrypt 使用私钥对数据解密
- SecKeyRawVerify 使用公钥对数字签名进行验证
- SecKeyRawSign 使用私钥生成数字签名
应用场景
由于RSA算法的加密解密速度要比对称算法的速度慢很多,在实际应用中,通常采取:
- 数据本身的加密解密使用对称加密算法(AES)
- 用RSA算法加密并传输对称算法所需的密钥
终端测试命令
##程序开发证书生成
# 生成私钥
$ openssl genrsa -out private.pem 1024
# 创建证书请求
$ openssl req -new -key private.pem -out rsacert.csr
# 生成证书并签名,有效期10年
$ openssl x509 -req -days 3650 -in rsacert.csr -signkey private.pem -out rsacert.crt
# 转换格式-将 PEM 格式文件转换成 DER 格式
$ openssl x509 -outform der -in rsacert.crt -out rsacert.der
# 导出P12文件
$ openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
在苹果开发中,不能直接使用 PEM 格式的证书
- DER 文件是 CRT 文件的 BASE 64 解码前的二进制数据文件*
- OpenSSL 默认生成的都是 PEM 格式的证书(BASE64 编码后的文本文件)
数字签名
发送方
- ”报文” HASH 得到 “报文摘要”
- “报文摘要” 用公钥加密(数字签名) + 报文
发送给接收方
- 接收方
- “报文” HASH 得到 “报文摘要”
- “数字签名” 用私钥解密 判断是否与 “报文摘要” 相同
生成密钥示例
私钥 & 公钥
# 生成强度是 512 的 RSA 私钥
$ openssl genrsa -out private.pem 512
# 以明文输出私钥内容
$ openssl rsa -in private.pem -text -out private.txt
# 校验私钥文件
$ openssl rsa -in private.pem -check
# 从私钥中提取公钥
$ openssl rsa -in private.pem -out public.pem -outform PEM -pubout
# 以明文输出公钥内容
$ openssl rsa -in public.pem -out public.txt -pubin -pubout -text
加密 & 解密
# 使用公钥加密小文件
$ openssl rsautl -encrypt -pubin -inkey public.pem -in msg.txt -out msg.bin
# 使用私钥解密小文件
$ openssl rsautl -decrypt -inkey private.pem -in msg.bin -out a.txt
格式转换
# 将私钥转换成 DER 格式
$ openssl rsa -in private.pem -out private.der -outform der
# 将公钥转换成 DER 格式
$ openssl rsa -in public.pem -out public.der -pubin -outform der
PKCS
Public-Key Cryptography Standards (PKCS)是由美国 RSA 数据安全公司及其合作伙伴制定的一组公钥密码学标准,其中包括证书申请、证书更新、证书作废表发布、扩展证书内容以及数字签名、数字信封的格式等方面的一系列相关协议
PKCS协议
协议 <->说明
- PKCS#1 定义 RSA 公开密钥算法加密和签名机制,主要用于组织 PKCS#7 中所描述的数字签名和数字信封(专门用来加密/解密)
- PKCS#8 描述私有密钥信息格式,该信息包括公开密钥算法的私有密钥以及可选的属性集等(JAVA使用)
- PKCS#12 描述个人信息交换语法标准。描述了将用户公钥、私钥、证书和其他相关信息打包的语法(苹果使用)