• 非对称加密


      上一篇文章中讲到对称加密,客户端和服务端使用的都是同一个密钥key。这样存在一定安全风险,如果客户端如app被人逆向破解或反编译,那么密钥key就可能会被暴露。在这种情况我们就会想到非对称加密的方式,非对称加密更安全,但性能更低,大约为对称加密的1%,即如果对称加密需要花1s时间完成,那么同样方式使用非对称加密就需要100s的时间来完成。 

      非对称加密要用到两个密钥,一个公钥(客户端拥有),一个私钥(服务端拥有)。公钥是公开的,私钥是保密的。加密时客户端通过公钥进行加密,服务端接收到加密数据使用私钥进行解密。其流程如下:

      

    【RSA算法】

      非对称加密中使用最广泛的算法是RSA算法,具体原理可参考阮一峰教程 RSA算法原理

    【命令行生成公钥和私钥】

      1. 生成私钥,输入如下命令,对应目录下将生成 private.pem 私钥文件。1024表示加密强度。

    openssl genrsa -out private.pem 1024

      2. 生成公钥,如下命令,从中可以看出,公钥是从私钥中提取。

    openssl rsa -in private.pem -out public.pem -outform PEM -pubout

      3. 使用公钥加密(创建一个文件123.txt, 里面输入1234567内容),加密生成文件为123.bin

    openssl rsautl -encrypt -pubin -inkey public.pem -in 123.txt -out 123.bin

      4. 使用私钥进行解密,解密内容输出到dec.txt。

    openssl rsautl -decrypt -inkey private.pem -in 123.bin -out dec.txt

    【私钥转PCK#8】

      在有些平台使用私钥解密时可能需要转换成PCK#8的私钥格式

      1. openssl 敲回车

      2. pkcs8 -topk8 -inform PEM -in private.pem -outform PEM -nocrypt -out private_key_pkcs8.pem

    【数字证书】

      上面讲到公钥放在客户端中相当于是公开的,也有些网站直接会提供一个公钥下载链接等。公钥公开有时候会被伪装,即中间人攻击。所以一般非对称加密会搭配证书进行使用。

      数字证书就是对公钥进行数字签名,让别人无法伪造公钥。证书里面有很多信息,如姓名,组织,地址等,以及属于此人的公钥,并有认证机构施加的数字签名,只要看到公钥证书,我们就可以知道认证机构认证公钥的确属于此人。

      1. 创建证书请求(要通过上面的私钥来先生成一个证书请求),证书请求格式为 csr。

     openssl req -new -key private.pem -out rsacert.csr

      输入上面命令后会要求输入一系列信息,姓名,地址,公司等,都可以跳过

      2. 生成证书并签名,有效日期为100年,输出的 rsacert.crt 就是证书。

    openssl x509 -req -days 36500 -in rsacert.csr -signkey private.pem -out rsacert.crt

      3. 格式转换,在 ios 开发中要转换成der格式证书才可以使用

    openssl x509 -outform der -in rsacert.crt -out rsacert.der

    【前后端通信思路】

      非对称加密放在前后端通信中可以有这样一种实现思路:有两对公钥和私钥,如公钥A,私钥A;公钥B,私钥B。服务端可以放私钥A,公钥B;前端可以放私钥B,公钥A。

      前端发送请求给服务端时用公钥A加密,服务端接收到请求后用私钥A进行解密。服务端返回数据用公钥B加密,前端接收到返回值用私钥B进行解密。这样即使客户端被破解反编译,那么服务端的私钥也是无法被破解的。

    【代码演示】

      上一篇博客中用对称加密演示了请求通信的加解密,这里的代码加解密就不演示 http请求了。这里就只用 node.js 简单演示一下用公钥加密,用私钥解密

      1. 根据前面所讲的方法生成公钥和私钥,将公钥和私钥放入 node.js 工程中,如下:(这一步也可以不使用命令行生成,可以直接使用crypto库生成)

      

      2. 使用 crypto 加密解密如下

    let crypto = require('crypto');
    let fs = require('fs');
    
    let privateKey = fs.readFileSync('./other/private.pem').toString();
    let publicKey = fs.readFileSync('./other/public.pem').toString();
    
    var data = "lijinshi嘿嘿哈哈";
    var dataBuffer = new Buffer(data);
    
    // 公钥加密
    let encBuffer = crypto.publicEncrypt(publicKey, dataBuffer);
    let encString = encBuffer.toString("base64");
    console.log(encString);
    
    // 私钥解密
    let privateObj = {
      key: privateKey,
      passphrase: "",
      padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
    };
    let decBuffer = crypto.privateDecrypt(privateObj, new Buffer(encString, 'base64'));
    console.log(decBuffer.toString());

      3. 运行打印如下:

      

      4. 小补充,我在实验时发现填入其他填充模式会导致解密失败,这方面还有待研究。这里填的是 RSA_PKCS1_OAEP_PADDING , 测试过程中发现每次加密的字符串都是不一样的,想起做 ios rsa 加密也出现过一样的现象,这都是填充模式不同引起的。每次加密生成的密文都不一样,但解密出的明文始终都一样。

    【参考文献】

    crypto翻译:http://wiki.jikexueyuan.com/project/iojs-api-doc/crypto.html

    crypto官方教程:https://nodejs.org/api/crypto.html

  • 相关阅读:
    How to using X++ code achieve copying records
    How to using x++ code achieve Lookup files list with entire folder
    Using X++ code create and Read XML file.
    Using X++ Code Create master table form
    When you are finished renamed the Item number Jobs
    Visual Studio.NET 简介
    Visual C++中的异常处理浅析
    最常见的20种VC++编译错误信息
    开发WDM型的USB设备驱动程序
    C++中内存管理
  • 原文地址:https://www.cnblogs.com/buerjj/p/8030361.html
Copyright © 2020-2023  润新知