RSA非对称加密

一、背景

要对接实时翻译的平台,而对方提供的加密方式就是RSA(非对称加密),以往都是php对接,所以也没有深度研究过该加密方式,趁此次机会,学习一下

二、概述

非对称加密就是加密和解密使用的不是相同的密钥:只有同一个公钥-私钥对才能正常加解密。

比如,如果A要加密一个文件发送给B,他应该先向B索要公钥,然后用B给他的公钥加密,把加密文件发送给B,此文件只能由B的私钥解开。因为B的私钥在他自己手机,所以,除了B,没有任何人能解开此加密文件。

非对称加密的典型算法就是RSA算法,它是由Ron Rivest,Adi Shamir,Leonard Adleman这三个哥们一起发明的,所以用他们仨的姓的首字母缩写表示。

优点: 非对称加密相比对称加密的显著优点在于,对称加密需要协商密钥,而非对称加密可以安全地公开各自的公钥,在N个人之间通信的时候,使用废对称加密只需要N各密钥对,每个人只管理自己的密钥对。而使用对称加密需要N*(N-1)/2个密钥,因此每个人需要管理N-1个密钥,密钥管理难度大,且非常容易泄露。

缺点: 非对称加密的缺点就是运算速度非常慢,比对称加密要慢得多。

所以在实际应用中,两者总是一起使用。假设A要给B传输加密文件,他俩首先交换了各自的公钥,然后:

  • A生成一个随机的AES口令,然后用B的公钥通过RSA加密这个口令, 并发给B;
  • B用自己的RSA私钥解密得到AES口令;
  • 双方使用这个共享的AES口令用AES加密通信。

可见非对称加密实际上应用在第一步,即加密‘AES口令’,这也是浏览器中常用的https协议的做法,即浏览器和服务器先通过RSA交换AES口令,接下来双方通信实际上采用的是速度较快的AES对称加密,而非缓慢的RSA非对称加密。

知识点: RSA算法,它的密钥有256/512/1024/2048/4096等不同的长度。长度越长,密码强度越大,当然计算速度也越慢。使用512bit的RSA加密时,明文长度不能超过53字节,使用1024bit的RSA加密时,明文长度不能超过117字节,这也是为什么使用RSA的时候,总是配合AES一起使用,即用AES加密任意长度的明文,用RSA加密AES口令。只使用非对称加密算法不能防止中间人攻击。

三、RSA PKCS公钥加密标准

RSA PCKS(Public-Key Cryptography Standards Series 公钥加密标准系列),为了定义 RSA 加密的标准系列,IETF 组织总共定义了 15 个子系列标准,分别用在定义标准格式、如何封装、公钥加密封装标准、私钥加密封装标准、网络传输序列化标准等等… 具体可以参考 wikipedia PCKS 的解释: https://en.wikipedia.org/wiki/PKCS
PKCS #1 RSA Cryptography Standard: 定义了公钥加密技术(RSA)相关的数学属性以及相关的公钥和密钥的格式标准(通过 ASN.1 的格式标准来定义并明文展示),以及为 RSA 进行加密、解密,生成和验证签名等操作定义了基本的算法和编码/补零(padding)的方案;PCKS #1 定义的都是明文的格式;

除此以外,还有

四、密钥格式

  • PKCS #1: 该标准是专门为RSA密钥进行定义的,其对应的PEM文件格式如下:

公钥PEM格式:

-----BEGIN RSA PUBLIC KEY-----
BASE64 ENCODED DATA
-----END RSA PUBLIC KEY-----

私钥PEM文件格式:

-----BEGIN RSA PRIVATE KEY-----
BASE64 ENCODED DATA
-----END RSA PRIVATE KEY-----

  • PKCS #8: 该标准定义了一个密钥格式的通用方案,它不仅仅为 RSA 所使用,同样也可以被其它密钥所使用;其对应的PEM文件格式如下:

公钥PEM格式:

-----BEGIN PUBLIC KEY-----
BASE64 ENCODED DATA
-----END PUBLIC KEY-----

私钥PEM文件格式:

-----BEGIN PRIVATE KEY-----
BASE64 ENCODED DATA
-----END PRIVATE KEY-----

知识点: PEM和DER都是指文件的格式;其中DER是密钥的二进制表述格式,PEM是对DER编码转码为Base64字符的格式,通过解码还是能还原为DER格式的。

五、填充模式

跟DES、AES一样,RSA也是一个块加密算法,即总是在一个固定长度的块上进行操作,但是跟AES不同的是,block length跟key length以及所使用的填充模式有关。

  • RSA_PKCS1_PADDING
    最常用的填充模式,要求:
    输入必须比RSA钥 模长(modulus)短至少11ge字节,也就说输入长度要小于等于 RSA _size - 11 ;如果输入的明文过长,必须切割,然后填充;
    输出 和modulus以一样长
    根据这个要求,也就解释了在概述中密钥长度不同,明文长度就受限。
    block length = 512/8 - 11 = 53字节
    block length = 1024/8 -11 = 117字节
    加密的时候会在你的明文中随机填充一些数据,所以会导致对同样的明文每次加密后的结果都不一样。
    对加密后的密文,服务器使用相同的填充方式都能解密。解密后的明文也就是之前加密的明文。

  • RSA_PKCS1_OAEP_PADDING
    输入 比 RSA modulus 短至少41个字节
    输出 和modulus一样长

  • OPENSSL_NO_PADDING
    输入可以和RSA modulus一样长,如果输入的明文过长,必须切割, 然后填充
    输出和modulus一样长
    如果你的明文不够128字节,加密的时候会在你的明文前面填充零。
    解密后的明文也会包括前面填充的零,这是服务器需要注意把解密后的字段前向填充的零去掉,才是真正之前加密的明文。

六、实战代码示例

<?php

namespace App\Services;
/**
 * 填充方式为RSA_PKCS1_PADDING,
 * 密钥格式为PKCS1-V1_5
 * */
class AtmanService
{

    const API_TRANSFER_PATH = '/api/rsa/sso';
    /**
     * 构造函数
     */
    public function __construct() {
    }

    /**
    获取公共key字符串  重新格式化 为保证任何key都可以识别
     */

    public static function get_public_key(){
        $public_key = file_get_contents('public.txt');
        $search = [
            "-----BEGIN PUBLIC KEY-----",
            "-----END PUBLIC KEY-----",
            "\n",
            "\r",
            "\r\n"
        ];
        $public_key=str_replace($search,"",$public_key);
        return openssl_pkey_get_public($search[0] . PHP_EOL . wordwrap($public_key, 64, "\n", true) . PHP_EOL . $search[1]);
    }

    /**
    获取私有key字符串 重新格式化  为保证任何key都可以识别
     */
    public static function get_private_key()
    {
        $private_key= file_get_contents('private.txt');
        $search = [
            "-----BEGIN RSA PRIVATE KEY-----",
            "-----END RSA PRIVATE KEY-----",
            "\n",
            "\r",
            "\r\n"
        ];

        $private_key = str_replace($search, "", $private_key);
        return openssl_pkey_get_private($search[0] . PHP_EOL . wordwrap($private_key, 64, "\n", true) . PHP_EOL . $search[1]);

    }

    /**
     * 用公钥加密
     */
    public static function public_encrypt($input) {
        if (!is_string($input)) {
            return null;
        }

        openssl_public_encrypt($input,$output,self::get_public_key(),OPENSSL_PKCS1_PADDING);
        return base64_encode($output);
    }


    /**
     * 解密 公钥加密后的密文
     */
    public static function private_decrypt($input)
    {
        if (!is_string($input)) {
            return null;
        }

        openssl_private_decrypt(base64_decode($input), $output, self::get_private_key(), OPENSSL_PKCS1_PADDING);
        return $output;

    }

}

前人栽树,后人乘凉
栽树人1

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值