美文网首页
04-文件上传,加密进阶

04-文件上传,加密进阶

作者: AlanGe | 来源:发表于2017-08-27 23:23 被阅读285次

    一、文件上传

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

    相关文章

      网友评论

          本文标题:04-文件上传,加密进阶

          本文链接:https://www.haomeiwen.com/subject/asnidxtx.html