04-文件上传,加密进阶

一、文件上传

经常有人咨询上传文件的原理,并且反馈第三方框架 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

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

推荐阅读更多精彩内容