base64编码解码原理
base64简介
- 是网络上使用最广泛的编码系统,能够将任何二进制数据,转换成只有 65 个字符组成的文本文件.
- 编码后的数据由
a-z A-Z 0-9 + / =
表示. - base64 编码后的结果能够反算,不够安全.
- base64 是所有现代加密算法的基础算法.
Base64编码演示 = 终端命令
- 编码文件
# 将 10.jpg 进行 base64 编码,生成 10.txt 文件
$ base64 10.jpg -o 10.txt
# 将 10.txt 解码生成 10.jpg 文件
$ base64 10.txt -o 10.jpg -D
- 编码字符串
# 将字符串 Man 进行 base64 编码
$ echo -n "Man" | base64
# 将字符串 TWFu 解码
$ echo -n "TWFu" | base64 -D
base64编码的原理
- 把一个字符转换成二进制取出前6位查表.
- 不够6位的时候补0,如果是8位,则补4个0,编码后连接两个==.
- 如果最后是4位,补2个0,编码后连接一个=.
- 编码之后文件会变大,因为有补0.
图解base64编码原理
base64编码解码模拟加密解密
- 提示 : 此处使用
base64编码解码
来模拟
数据的加密和解密
.
加密和解密
-
发送
隐私信息时需要加密
-
提示 : 服务器上保存的私密信息是机密之后的数据
-
保存
隐私信息时也需要加密
-
读取
保存的隐私信息时需要解密
-
网络应用程序的数据安全
- 网络上不允许传输用户隐私数据的"明文".
- 在本地不允许保存用户隐私数据的"明文".
base64编码解码模拟加密解密代码实现
-
提示 : base64编码的本质是编码不是加密.此处只是一个
模拟加密
-
base64编码 ===>
模拟加密
/// base64编码---加密 : 传入需要"加密"的字符串,返回"加密"之后的字符串
- (NSString *)base64Encode:(NSString *)str
{
// 1.将需要加密的数据转成二进制,因为Base64的编码和解码都是针对二进制的
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
// 2.把二进制数据编码之后,直接转成字符串
NSString *encodeStr = [data base64EncodedStringWithOptions:0];
// 3.返回结果
return encodeStr;
}
- base64解码 ===>
模拟解密
/// base64解码---解密
- (NSString *)base64Decode:(NSString *)encodeStr
{
if (encodeStr.length == 0) {
return nil;
}
// 1.把编码之后的字符串解码成二进制
NSData *data = [[NSData alloc] initWithBase64EncodedString:encodeStr options:0];
// 2.把解码之后的二进制转换成字符串
NSString *decodeStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// 3. 返回结果
return decodeStr;
}
- 发送用户信息时先"加密".
NSString *psd = self.psdTextField.text;
// 密码加密之后再发送出去
psd = [self base64Encode:psd];
- 保存用户信息之前"加密"处理.
/// 保存"加密"后的用户信息到偏好设置
- (void)saveUserInfo
{
[[NSUserDefaults standardUserDefaults] setObject:self.userNameTextField.text forKey:userNameKey];
// 保存之前先加密
NSString *userName = [self base64Encode:self.psdTextField.text];
[[NSUserDefaults standardUserDefaults] setObject:userName forKey:psdKey];
}
- 读取本地"加密"的用户信息时需要"解密".
/// 读取保存到本地的"加密"的用户信息
- (void)readUserInfo
{
self.userNameTextField.text = [[NSUserDefaults standardUserDefaults] objectForKey:userNameKey];
// 读取时先解密
NSString *psd = [self base64Decode:[[NSUserDefaults standardUserDefaults] objectForKey:psdKey]];
self.psdTextField.text = psd;
}
base64编码的好处
- 使用
Base64编码
之后,不能直接看到用户密码的明文.
存在的问题
- 但是
Base64编码解码
的算法是公开的,并且算法可逆,安全性并不好.
MD5
MD5简介
- 对任意的数据进行计算,生成固定长度的字符串.32个字符.
- 一般用来加密密码.
- 有时候也用来验证文件下载时,是否被篡改过.
- 文件下载完成之后计算文件的md5值,与服务器计算的MD5值比较,如果不一样那么这个文件在下载的过程中被篡改了.
MD5终端命令
# 得到文件的MD5值
$ md5 文件名
# 得到字符串的MD5值
md5 -s "string"
MD5加密方案
- 先导入分类
#import "NSString+Hash.h"
方案一 : 直接MD5计算
psd = [psd md5String];
- Base64与MD5对比
- Base64编码 : "加密"简单,算法可逆.毫无安全性可言.不能用来加密密码.
- MD5 : 加密过程复杂,算法不可逆,安全性高,常用来加密密码等用户的敏感信息.但是简单的密码MD5加密之后可以暴力破解.
- 暴力破解网站 : http://www.cmd5.com/
方案二 : 密码加盐
- 如果原始密码过于简单,直接进行MD5加密是很容易被暴力破解的.
- 为了增强密码的安全性,防止加密的密码被暴力破解,可以向原始密码中加盐.
- 盐 : 服务器端和客户端约定的一个字符串.
- MD5+盐 : 原始密码+盐拼接出新的密码字符串,再进行MD加密.
- 以上为加一勺盐,比单纯的直接MD5加密安全性要高.
- 盐要足够的咸,越咸越安全.
// 盐
NSString *salt = @"123zxcASD!@#";
psd = [[psd stringByAppendingString:salt] md5String];
方案三 : HMAC
- HMAC : 加两勺盐.加两勺盐的密码加密强度比加一勺盐要高.
- 原理 : 原始密码+盐进行MD5计算,结算的结果+原始密码再进行MD5计算.
// 盐
NSString *salt = @"123zxcASD!@#";
psd = [psd hmacMD5StringWithKey:salt];
注意
- 不能用不可逆的加密算法加密密码并保存到本地.因为不可逆的加密算法加密的数据几乎不能还原回来.
- 苹果提供了
钥匙串
专门保存用户的私密信息到本地.
钥匙串
- safari 偏好设置里面可以读取到保存到钥匙串中的密码.
- 使用 AES 256 加密算法,能够保证用户密码的安全.
- 钥匙串访问SDK,是苹果在 iOS 7.0.3 版本以后公布的.钥匙串访问的SDK是纯 C 语言的.
- 钥匙串访问的密码保存在哪里?
- 只有苹果知道!是为了进一步保障用户的密码安全!
- 钥匙串访问的第三方框架,是对 C 框架的封装,可以不用看源代码.
- 框架地址 : https://github.com/soffes/sskeychain
sskeychain提供的常用的方法
/// 所有账户
+ (NSArray *)allAccounts;
/// 获取所有账户信息
+ (NSArray *)accountsForService:(NSString *)serviceName;
/// 获取账号密码
+ (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account;
/// 删除账号密码
+ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account;
/// 将账号密码保存在钥匙串
+ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account;
密码保存到钥匙串
- 先导入头文件 :
#import "SSKeychain.h"
/*
参数1 : 要保存到钥匙串的密码
参数2 : 保存哪个应用的密码
参数3 : 保存哪个账号的密码
*/
[SSKeychain setPassword:self.psdTextField.text forService:[NSBundle mainBundle].bundleIdentifier account:self.userNameTextField.text];
从钥匙串读取密码
self.psdTextField.text = [SSKeychain passwordForService:[NSBundle mainBundle].bundleIdentifier account:self.userNameTextField.text];