一、文件上传
经常有人咨询上传文件的原理,并且反馈第三方框架 AFNetworking 在处理有些文件上传时无法胜任。文件上传的原理只需要理解即可,工作中可以直接cmd+c&cmd+v。
- 准备工作
- 将文件夹 资料/网站素材/POST文件夹 放到服务器根目录。
- 修改 POST/abc 文件夹的权限为任何人可读写,否则不能上传文件到该目录。
1、文件上传原理
- 浏览器演示上传txt文件和图片文件
- 通过firebug查看浏览器上传文件时传递的参数
/**********下面内容是浏览器上传txt文件 需要传递给服务器的内容及格式**************/
Content-Type multipart/form-data; boundary=---------------------------134602830911050518651168115799
-----------------------------134602830911050518651168115799 \r\n
Content-Disposition: form-data; name="userfile"; filename="abc.txt" \r\n
Content-Type: text/plain \r\n\r\n// 上传文件的内容类型
txt文件内容 \r\n
-----------------------------134602830911050518651168115799-- // 结尾标记
/**********下面内容是浏览器上传png图片 需要传递给服务器的内容及格式*************/
Content-Type multipart/form-data; boundary=---------------------------1995980454601440591206486508
-----------------------------1995980454601440591206486508 \r\n
Content-Disposition: form-data; name="userfile"; filename="001.png" \r\n
Content-Type: image/png \r\n\r\n// 上传文件的类型是png图片
图片二进制数据 \r\n
-----------------------------1995980454601440591206486508-- // 结尾标记
/********下面是上传多个文件,需要传递给服务器的内容和格式**********/
Content-Type multipart/form-data; boundary=---------------------------594966490917936998244605338
-----------------------------594966490917936998244605338 \r\n
Content-Disposition: form-data; name="userfile[]"; filename="文件名" \r\n
Content-Type: application/octet-stream \r\n\r\n
文件1二进制数据 \r\n
-----------------------------594966490917936998244605338 \r\n
Content-Disposition: form-data; name="userfile[]"; filename="文件名" \r\n
Content-Type: image/jpeg \r\n\r\n
文件2二进制数据 \r\n
-----------------------------594966490917936998244605338 \r\n
Content-Disposition: form-data; name="username" \r\n\r\n
普通文本内容 \r\n
-----------------------------594966490917936998244605338-- // 结尾标记
#以上内容,是在 iOS 中,如果要上传文件,需要拼接的数据格式!
- 文件上传参数解析
-
Content-Type:客户端用来告诉服务器,提交的二进制数据类型。常用的取值有以下几种:
application/x-www-form-urlencoded:在发送到服务器之前,所有字符都会进行编码(特殊符号转换为 ASCII值)。当请求方法为GET时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1&name2=value2...),然后把这个字串append到url后面,用?分割,加载这个新的url。 当请求方法是为POST时候,浏览器把form数据封装到HttpBody中,然后发送到服务器。
multipart/form-data:在使用包含文件上传控件的表单时,必须使用该值。它既可以发送文本数据,也支持二进制数据上传。
text/plain:数据以纯文本形式进行编码
application/json:向服务器提交json格式数据。
text/xml:向服务器提交xml格式数据。
boundary:分割线,用于分割请求体中的多个post的内容,如文件内容和文本内容之间需要分割开来,不然接收方就无法正常解析和还原这个文件了。可以是任意数字或者字符的组合,但必须上下一致。比如---------------------------134602830911050518651168115799可以用 'alangeit' 代替。
注意点:分隔符绝对不能有中文name:服务器上传文件的字段名称,可以找公司后台要
filename:保存到服务器上的文件名,通常不允许重复,但是后端脚本会处理。
-
Content-Type:告诉服务器当前文件的类型(MIMEType),一般划分格式为:
- 大类型/小类型
text/plain 纯文本
text/html html文件
text/xml xml文件
image/png
image/gif
image/jpg
application/json
application/octet-stream 任意的二进制数据
........
如果不知道填什么,百度下就行了,没必要死记。
- 大类型/小类型
-
2、上传单个文件
// ViewController.m
// 上传单个文件
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// http://localhost/post/upload.php
}
//记得修改本地服务器文件夹的权限,否则无法上传文件
//文件夹->右键->显示简介->共享与权限->权限->所有用户都选“读和写”
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 要上传文件的二进制数据
// NSString *filePath = [[NSBundle mainBundle] pathForResource:@"abc.txt" ofType:nil];
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"cccc.png" ofType:nil];
NSData *fileData = [NSData dataWithContentsOfFile:filePath];
// 上传文件
// [self upload:fileData fieldName:@"userfile" fileName:@"abcd.txt"];
[self upload:fileData fieldName:@"userfile" fileName:@"cccc.png"];
}
// 分隔符
#define Boundary @"itcast"
- (void)upload:(NSData *)fileData fieldName:(NSString *)fieldName fileName:(NSString *)fileName {
// URL
NSURL *url = [NSURL URLWithString:@"http://localhost/post/upload.php"];
// Request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 设置请求方法
request.HTTPMethod = @"POST";
// 设置请求头
//Content-Type multipart/form-data; boundary=itcast
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",Boundary] forHTTPHeaderField:@"Content-Type"];
// 设置请求体
request.HTTPBody = [self fileData:fileData fieldName:fieldName fileName:fileName];
// NSURLConnection
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
NSLog(@"%@---%@",response,[NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]);
}];
}
// 请求体的内容
/*
--itcast \r\n
Content-Disposition: form-data; name="userfile"; filename="abc.txt"\r\n
Content-Type: application/octet-stream \r\n\r\n
上传文件的内容二进制数据
\r\n--itcast--
*/
/**
* 拼接文件数据
*
* @param fileData 要上传文件的二进制数据
* @param fieldName 对应服务器接收文件数据的字段名
* @param fileName 保存到服务器使用的文件名
*/
- (NSData *)fileData:(NSData *)fileData fieldName:(NSString *)fieldName fileName:(NSString *)fileName {
// 可变的NSData
NSMutableData *dataM = [NSMutableData data];
// 创建一个可变的字符串
NSMutableString *strM = [NSMutableString stringWithFormat:@"--%@\r\n",Boundary];
[strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",fieldName,fileName];
[strM appendString:@"Content-Type: application/octet-stream\r\n\r\n"];
//将strM转成二进制数据
[dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]];
// 插入文件的二进制数据
[dataM appendData:fileData];
// 插入结束标记字符串
NSString *tail = [NSString stringWithFormat:@"\r\n--%@--",Boundary];
[dataM appendData:[tail dataUsingEncoding:NSUTF8StringEncoding]];
return dataM;
}
@end
3、上传多个文件
// ViewController.m
// 上传多个文件-(理解)
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// http://localhost/post/upload.php
}
//记得修改本地服务器文件夹的权限,否则无法上传文件
//文件夹->右键->显示简介->共享与权限->权限->所有用户都选“读和写”
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 要上传文件的二进制数据
// 文件1
NSString *filePath1 = [[NSBundle mainBundle] pathForResource:@"cccc.png" ofType:nil];
NSData *fileData1 = [NSData dataWithContentsOfFile:filePath1];
// 文件2
NSString *filePath2 = [[NSBundle mainBundle] pathForResource:@"abc.txt" ofType:nil];
NSData *fileData2 = [NSData dataWithContentsOfFile:filePath2];
// 普通参数
NSString *username = @"jack";
// 参数如何传递?
// 文件字典数据
// 文件字典
NSDictionary *fileDict = @{@"bbb.png":fileData1,@"dddd.txt":fileData2};
// 普通参数
NSDictionary *params = @{@"username":username};
// 上传文件
[self upload:fileDict params:params fieldName:@"userfile[]"];
}
// 分隔符
#define Boundary @"alangeIT"
- (void)upload:(NSDictionary *)fileDict params:(NSDictionary *)params fieldName:(NSString *)fieldName {
// URL
NSURL *url = [NSURL URLWithString:@"http://localhost/post/upload-m.php"];
// Request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 设置请求方法
request.HTTPMethod = @"POST";
// 设置请求头
//Content-Type multipart/form-data; boundary=itcast
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",Boundary] forHTTPHeaderField:@"Content-Type"];
// 设置请求体
request.HTTPBody = [self fileData:fileDict params:params fieldName:fieldName];
// NSURLConnection
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
NSLog(@"网络请求:%@---%@",response,[NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]);
}];
}
/**
* 拼接文件数据
*
* @param fileData 要上传文件的二进制数据
* @param fieldName 对应服务器接收文件数据的字段名
* @param fileName 保存到服务器使用的文件名
*/
// 请求体的内容
/*
--itcast\r\n
Content-Disposition: form-data; name="userfile[]"; filename="abc.txt"\r\n
Content-Type: application/octet-stream\r\n\r\n
文件1的数据\r\n
--itcast\r\n
Content-Disposition: form-data; name="userfile[]"; filename="文件上传.m"\r\n
Content-Type: application/octet-stream\r\n\r\n
文件2的数据\r\n
--itcast\r\n
Content-Disposition: form-data; name="username"\r\n\r\n
rose
\r\n--itcast--
*/
- (NSData *)fileData:(NSDictionary *)fileDict params:(NSDictionary *)params fieldName:(NSString *)fieldName {
// 可变的NSData
NSMutableData *dataM = [NSMutableData data];
// 遍历文件字典
[fileDict enumerateKeysAndObjectsUsingBlock:^(id fileName, id fileData, BOOL * _Nonnull stop) {
// 创建一个可变的字符串
NSMutableString *strM = [NSMutableString stringWithFormat:@"--%@\r\n",Boundary];
[strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",fieldName,fileName];
[strM appendString:@"Content-Type: application/octet-stream\r\n\r\n"];
[dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]];
// 插入文件的二进制数据
[dataM appendData:fileData];
// 插入\r\n
[dataM appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
}];
// 遍历普通的参数字典
[params enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull value, BOOL * _Nonnull stop) {
// 创建一个可变的字符串
NSMutableString *strM = [NSMutableString stringWithFormat:@"--%@\r\n",Boundary];
[strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",key];
[strM appendFormat:@"%@\r\n",value];
[dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]];
}];
// 插入结束标记字符串
NSString *tail = [NSString stringWithFormat:@"--%@--",Boundary];
[dataM appendData:[tail dataUsingEncoding:NSUTF8StringEncoding]];
return dataM;
}
@end
二、RESTful风格--仅作了解
REST是'REpresentational State Transfer'的缩写,可以翻译成"表现层状态转化"。如果一个软件架构符合REST原则,就称它为RESTful架构。
-
如何理解RESTful架构?
最好的方法就是去理解Representational State Transfer这个词组到底是什么意思,它的每一个词代表了什么涵义。只要搞懂每一个词的含义,也就不难体会REST是一种什么样的风格。资源(Resources)。REST的名称"表现层状态转化"中,省略了主语。"表现层"其实指的是"资源"(Resources)的"表现层"。所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。你可以用一个URI(统一资源标志符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。所谓"上网",就是与互联网上一系列的"资源"互动,调用它的URI。
表现层(Representation)
"资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表现层"(Representation)。比 如:文本可以用txt格式表现,也可以用HTML格式,XML格式,JSON格式表现,甚至可以采用二进制格式。图片可以用JPG格式表现,也可以用PNG格式表现。状态转化(State Transfer)
访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。HTTP协议是一个无状态协议。客户端不会保存资源的状态。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer)。而这种转化是建立在表现层之上的,所以就是"表现层状态转化"。
-
四种手段来操作资源
- GET:用来获取资源
- POST:用来新建资源(也可以用于更新资源)
- PUT:用来更新资源
- DELETE:用来删除资源。
这四种手段正好对应HTTP协议提供的 GET/POST/PUT/DELETE 方法。
-
RESTful架构特点
- 每一个URI代表一种资源。
- 客户端和服务器之间,传递这种资源的某种表现层。
- 客户端通过四个HTTP方法,对服务器端资源进行操作,实现"表现层状态转化"。
-
小结
- RESTful的设计风格,让后端的设计更加直观,解读起来非常容易。
- RESTful的设计风格目前在国际上非常流行,国内也开始逐渐普及。
- 前端程序员只要知道即可,正常使用的时候,和上课的演练没有区别。
1、URI与URL区别?
-
名字区别
URI (uniform resource identifier)统一资源标志符。
-
URL(uniform resource location)统一资源定位符(或统一资源定位器)。可以提供找到该资源的路径, 比如http://www.baidu.com/abc.png,但URL又是URI,因为它可以标识一个资源,所以URL又是URI的子 集。
- 举个是个URI但不是URL的例子:urn:isbn:0-486-27557-4,这个是一本书的isbn,可以唯一标识这本 书
URI就是一种资源定位机制,它是比较笼统地定位了资源,并不局限于客户端和服务器。 而URL就定位了网上的一切资源,只要是网上的资源,都有唯一的URL。
2、示例
URI:http://www.xxx.com/product/123
# GET http://www.xxx.com/product/123
语义:从服务器获取产品代号是123的产品信息
# POST http://www.xxx.com/product/123
语义:在服务器“新增”产品代号为123的产品记录
# PUT http://www.xxx.com/product/123
语义:在服务器修改产品代号为123的产品信息(如果数据不存在,则新增)
# DELETE http://www.xxx.com/product/123
语义:在服务器删除产品代号为123的产品记录
三、发送JSON数据
-
开发中实际需求
- 提交一个JSON格式的二进制数据给后端。
- 后端程序员可以直接反序列化,得到 JSON 中的字典信息。
代码实现
// 上传 json 到服务器
- (void)postJSON:(NSData *)data{
// 请求 url
NSURL *url = [NSURL URLWithString:@"http://localhost/post/postjson.php"];
// 请求对象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 设置请求方法
request.HTTPMethod = @"POST";
// 设置 content-Type。有些服务器在接收数据的时候,会对数据进行校验,
// 建议上传 json 数据的时候要写上下面代码
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
// 设置 请求体
request.HTTPBody = data;
// 发送请求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}];
}
字典-->JSON数据
NSDictionary *dict1 = @{@"productId":@(11),@"productName":@"Mac 开发教程"};
// 判断数据格式是否是有效的 json对象
if (![NSJSONSerialization isValidJSONObject:dict1])return;
// 序列化 将数据发送给服务器之前,将字典或数组转换成二进制数据
// 反序列化 将服务器返回的二进制数据转换成OC对象。
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict1 options:0 error:NULL];
[self postJSON:jsonData];
数组-->JSON数据
NSDictionary *dict1 = @{@"productId":@(11),@"productName":@"Mac 开发教程"};
NSDictionary *dict2 = @{@"productId":@(10),@"productName":@"iOS 开发教程"};
NSArray *array = @[dict1,dict2];
// 判断数据格式是否是有效的 json对象
if (![NSJSONSerialization isValidJSONObject:array]) return;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:array options:0 error:NULL];
[self postJSON:jsonData];
错误演示
//Invalid top-level type in JSON write
// 无效的顶级节点类型
NSString *values = @"iOS";
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:values options:0 error:NULL];
[self postJSON:jsonData];
四、POST自定义对象
// 参数:对象属性名称的数组
NSDictionary *dict = [self.person dictionaryWithValuesForKeys:@[@"name",@"age"]];
// 判断数据格式是否是有效的 json 对象
if (![NSJSONSerialization isValidJSONObject:dict]){
NSLog(@"无效的 json 数据");
return;
}
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:NULL];
[self postJSON:jsonData];
- dictionaryWithValuesForKeys和setValuesForKeysWithDictionary都是KVC方法。
- 字典转模型 setValuesForKeysWithDictionary。
- 模型转字典 dictionaryWithValuesForKeys。
五、对称加密算法
提示:加密内容属于高级程序员的话题,有些内容会很枯燥,注意掌握加密码的思路和操作步骤即可! 代码不要求会写,只要会用 就行。
1、简介
-
1、简介
- 对称加密算法又称传统加密算法。
- 加密和解密使用同一个 密钥。
-
2、对称加密算法示例
- 密钥:X
- 加密算法:每个字符+X
- 明文:Hello
- 密钥为 1 时加密结果:Ifmmp
- 密钥为 2 时加密结果:Jgnnq
-
3、优缺点
- 算法公开,计算量小,加密速度快,加密效率高
- 双方使用相同的钥匙,安全性得不到保证
-
4、注意事项
- 密钥的保密工作非常重要
- 密钥要求定期更换
2、经典加密算法
-
1、经典加密算法
- DES(Data Encryption Standard):数据加密标准(现在用的比较少,因为它的加密强度不够,能够暴力破解)
- 3DES:原理和DES几乎是一样的,只是使用3个密钥,对相同的数据执行三次加密,增强加密强度。(缺点:要维护3个密钥,大大增加了维护成本)
- AES(Advanced Encryption Standard):高级加密标准,目前美国国家安全局使用的,苹果的钥匙串访问采用的就AES加密。是现在公认的最安全的加密方式,是对称密钥加密中最流行的算法。
-
2、加密模式
- ECB:电子密码本,就是每个块都是独立加密的。(ECB加密模式.png)
- CBC:密码块链,使用一个密钥和一个初始化向量(IV)对数据执行加密转换。(CBC加密模式.png)
只要是对称加密都有 ECB和 CBC 模式,加密模式是加密过程对独立数据块的处理。对于较长的明文进行加密需要进行分块加密,在实际开发中,推荐使用CBC的,ECB的要少用。
3、终端演示ECB和CBC加密的特点
#终端命令如下
> 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
// xxd 命令用于以十六进制显示文件的内容
> CBC
# 加密
$ openssl enc -des-cbc -K 616263 -iv 000000000000 -nosalt -in msg1.txt -out msg1.bin
# 解密
$ openssl enc -des-cbc -K 616263 -iv 000000000000 -nosalt -in msg1.bin -out msg1.txt -d
# 查看加密之后的二进制文件
$ xxd msg1.bin
- 3、代码实现
- (void)AESDemo {
/************ EBC ****************/
// 加密使用的 key
NSString *key = @"abc";
// 要加密的字符串
NSString *str = @"i love you";
// 加密
NSString *result = [CryptorTools AESEncryptString:str keyString:key iv:nil];
NSLog(@"ECB 加密 = %@",result);
// 使用 base64 解码 (echo -n "0qg3nXM31/76bCMMJ6NRRg==" ! | base64 -D)
NSLog(@"ECB 解密 = %@",[CryptorTools AESDecryptString:result keyString:key iv:nil]);
/************ CBC ****************/
uint8_t iv[8] = {1,2,3,4,5,6,7,8};
NSData *ivData = [NSData dataWithBytes:iv length:sizeof(iv)];
NSString *result1 = [CryptorTools AESEncryptString:str keyString:key iv:ivData];
NSLog(@"CBC 加密 = %@",result1);
NSLog(@"CBC 解密 = %@",[CryptorTools AESDecryptString:result1 keyString:key iv:ivData]);
}
- 通过终端命令验证上面代码加密的结果
ECB 加密/解密
# AES(ECB)加密
$ echo -n "i love you" | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
# AES(ECB)解密
$ echo -n "0qg3nXM31/76bCMMJ6NRRg==" | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d
CBC 加密/解密
# AES(CBC) 加密
$ echo -n "i love you" | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
# AES(CBC) 解密
$ echo -n "DLUEfBbhjjk2yaKhAlkJwA==" | base64 -D | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -d
终端命令解释
加密过程先加密,再 base64编码。
解密过程是先 base64,再解密。
其中 | 在命令里面叫做管道。作用是将前一个命令的结果当作参数传递给后一个命令
-K 就是密钥的ASCII码的十六进制
六、非对称加密算法
1、简介
-
1、简介
- 非对称加密是计算机通信安全的基石,保证了加密数据不会被破解。
- 非对称加密算法需要两个密钥:公开密钥(publickey) 和 私有密钥(privatekey)
- 公开密钥和私有密钥是一对
- 如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密。
- 如果用私有密钥对数据进行加密,只有用对应的公开密钥才能解密。
-
2、特点
- 算法强度复杂,安全性依赖于算法与密钥。
- 加密解密速度慢。
-
3、与对称加密算法的对比
- 对称加密只有一种密钥,并且是非公开的,如果要解密就得让对方知道密钥。
- 非对称加密有两种密钥,其中一个是公开的。
-
4、经典非对称加密算法:RSA算法
- 1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。
2、原理
1、找出两个‘很大’的质数:P & Q,一般长度是上百位。然后通过下面计算得到 N和 M;
# N =P * Q
# M = (P - 1) * (Q - 1)
2、找出整数E,E与M互质,即除了1之外,没有其他公约数
3、找出整数D,使用ED除以M余1,即(ED) % M = 1
4、经过上述准备工作之后,可以得到:
# E是公钥,负责加密
# D是私钥,,负责解密
# N负责公钥和私钥之间的联系
5、加密算法,假定对X进行加密
# (X^E)%N = Y
6、解密算法,根据‘费马小定理',可以使用以下公式完成解密
# (Y^D)%N = X
3、RSA算法演练
1、RSA原理代码演示
2、RSA算法演练
- (void)RSADemo{
CryptorTools *tools = [[CryptorTools alloc] init];
// 加载公钥
NSString *pubPath = [[NSBundle mainBundle] pathForResource:@"rsacert.der" ofType:nil];
[tools loadPublicKeyWithFilePath:pubPath];
// 使用公钥加密
NSString *result = [tools RSAEncryptString:@"i love you"];
NSLog(@"%@",result);
// 加载私钥
NSString *privatePath = [[NSBundle mainBundle] pathForResource:@"p.p12" ofType:nil];
[tools loadPrivateKey:privatePath password:@"123"];
// 使用私钥解密
NSLog(@"%@",[tools RSADecryptString:result]);
}
*4、RSA应用场景
由于 RSA算法的加密解密速度要比对称算法速度慢很多,在实际应用中,通常采取
- 数据本身的加密和解密使用对称加密算法(AES)。
- 用 RSA算法加密并传输对称算法所需的密钥
七、RSA密钥生成过程
1、程序开发证书生成
# 生成私钥文件
$ openssl genrsa -out private.pem 1024
openssl:是一个自由的软件组织,专注做加密和解密的框架。
genrsa:指定了生成私钥算法使用RSA
-out:后面的参数表示生成的key的输入文件
1024:表示的是生成key的长度,单位字节(bits)
# 创建证书请求
$ openssl req -new -key private.pem -out rsacert.csr
可以拿着这个文件去数字证书颁发机构(即CA)申请一个数字证书。CA会给你一个新的文件cacert.pem,那才是你的数字证书。(要收费的)
# 生成证书并签名,有效期10年
$ openssl x509 -req -days 3650 -in rsacert.csr -signkey private.pem -out rsacert.crt
X509是一种非常通用的证书格式。
将用上面生成的密钥privkey.pem和 rsacert.csr证书请求文件 生成一个数字证书rsacert.crt。这个就是公钥。
# 转换格式 将 PEM 格式文件 转换成 DER 格式
$ openssl x509 -outform der -in rsacert.crt -out rsacert.der
在 iOS开发中,公钥是不能使用base64编码的,上面的命令是将公钥的base64编码字符串转换成二进制数据
# 导出 P12 文件
$ openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
在iOS使用私钥不能直接使用,需要导出一个p12文件。下面命令就是将私钥文件导出为p12文件。
八、Charles--青花瓷
网络抓包工具
可以拦截 iPhone/Android 手机中App 的 非加密 网络请求数据。
-
使用
- 手机&电脑在同一个局域网。
- 确保电脑能够通过路由器访问互联网
-
电脑安装 Charles,禁止 MAC OS X Proxy & Mozilla FireFox Proxy
-
设置手机的网络代理
- ip : 电脑的 ip
-
端口:8888
注意点:如果让电脑通过手机的3G 访问网络,无法拦截数据
九、知识扩展
1、使用运行时机制动态获得对象的所有属性。
http://c.m.163.com/nc/article/headline/T1348647853363/0-20.html