在企鹅和某团的面试过程中,都问到了非对称加密的相关问题,这里做个整理。
提起非对称加密,不管承认不承认,大多数人的第一反应肯定是RSA,它独特的质数分解思想让其破解的难度大大增加——我们都知道,两个数相乘非常容易实现,但要将一个特别特别特别大的数分解为两个很大的质数相乘,这个难度,你想试试,还是洗洗睡吧。。。
当然,这里无意去讨论它算法的核心实现,毕竟各类语言早就把这个伟大的算法实现为自己的API,轮子已经造好,更多的时候,我们扮演的其实就是一个调用者角色,对于这种算法,在调用的过程中容易出现哪些问题或者有哪些概念误区,才是本文讨论的重点。至于,算法的实现,有兴趣的可以看看。
RSA三个重要参数:公钥指数e,私钥指数d,模值n;
RSA的密钥组成其实是由(公钥+模值)、(私钥+模值)组队分发的,所以我们平时拿到的“公钥”,它还包含了模值在里面。可以肯定的是,他俩要想发挥作用,必须要成对存在,单独一个没有实际意义。
模值n。想必大家已经知道,rsa的算法相对复杂,决定了它的效率不会太高,也只适合用来加密比较短的数据,较长的数据必须要分块加密。那rsa到底能加密多长的数据呢?查找资料发现,rsa能加密的明文长度与密钥长度有关。注意,这里出现了一个密钥长度,不得不说,当我们讨论密钥长度的时候,我们所说的其实并不是公钥和私钥的长度,而是指与其进行模运算的模值的长度。而目前主流模值选取有1024bits、2048bits等等,当然,这么多位的一个素数也不是说生成就能生成的,很多时候的模值长度也只是接近1024位。
说了模值,来看看公钥指数e。PKCS(RSA的加密标准)建议选取素数65537(0x10001),RSA加密算法的核心就是分解素数,选择65537,可能是出于安全和计算效率的平衡考虑;
还有一个私钥指数d,它是根据ed%k=1,k=(p-1)(q-1)确定出来的,至于这个公式的具体含义,对我们只想使用RSA的同学来说,可不必深究。一般也是某个小于1024bits的大整数。
关于加密长度。RSA算法本身要求它能加密的明文长度l必须满足:0 < l < n (模值长度);当l=0时,加密结果全为0,当l>n时,会报异常。所以RSA 1024实际能加密的明文长度最大也就1024bits,折合128字节。但为什么会有“RSA 1024只能加密117字节长度明文”的说法呢?
查阅资料发现,原来是有一部分是作为padding使用,我们通过api来生成密钥时,会让你传一些padding参数,就是这个作用。PKCS建议padding的字节长度为11字节,所以实际的明文长度就是128-11=117字节。至于padding的作用,网上的说法是用来确定解密后内容的真实长度,比如一堆二进制数,如果没有固定字节的padding,很难确0是内容还是内容结束符。
既然加密长度受限,那么比较长的明文怎么处理?你可能已经想到了——分段加密。如果明文较长,我们可以将其先padding之后,再分段加密。不过一般这种情况比较少遇到,我们使用RSA加密的多数场景是用来加密用于对成加密的密钥或者来实现签名功能,对称加密的密钥通常情况下不会达到117字节(效率),而签名往往又是先需要对明文进行摘要(MD),它的长度一般也不会超范围;
说到签名,不妨来看看笔者曾经经常混淆的几个点,仅作为借鉴。
既然是一种加密技术,必然是双向的,能加密和解密,这个无需质疑;注意:如果密钥不配对也能解出结果,只不过是错误的。
加密和数字签名不是一个概念;RSA不仅能够加密,也能够用于数字签名;
数字摘要MD(message digest):非对称加密的算法决定了它处理长数据比较吃力,所以需要对文本生成一个数字摘要;同一种算法对同一个文本生成的摘要是一样的;
数字摘要的核心是对报文采用hash算法(SHA/SHA-1/MD5);
数字签名,核心是对数字摘要MD进行RSA;发送方将明文和数字签名发出,接收方对明文采用同样hash算法得到数字摘要MD,然后用公钥对数字签名解密(得到发送方发过来的摘要),比对两个摘要,如果相同,则说明报文完整、未被篡改,完成整个流程;
完全可以模拟数字签名的流程,采用自己的加密算法,实现自己的签名逻辑;