打开公钥文件看一下,里面包含模//modulus和公钥指数//public exponent。我们运行一个RSA2048计算,因此模的长度也是2048位,就是256个字节。公钥指数,通常我们可以选择一个较小的数,通常是65537,也经常使用2^16+1来表示。
再打开私钥文件看一下,同样的模,公钥指数,这些和公钥文件中一样。关键信息是私钥指数,同样也是2048位。
之前说了,如果想使用中国余数定理加速私钥的模幂运算,那么私钥可以用p,q系列的五元组来表示,在另外一个例子ModularExponentiationCRT中用这些参数的使用演示。
我们还是先来看标准RSA计算的例子,main.c中是对PKA HAL驱动的调用,也是用户执行PKA运算的逻辑。
由前后两部分组成,先是对明文加密,使用较小的公钥指数和2048位的模;然后对密文解密,使用2048位的私钥指数和相同的模。
加密过程在胶片的左面,解密过程在胶片的右面。这样并排一方,可以清晰地看到,RSA的加密、解密运算,是完全对称的。仅仅是把密钥参数从私钥换成公钥,把输入数据从明文换成密文。使用的HAL驱动和调用的顺序都完全一模一样。紫色方框部分是这种PKA硬件引擎的工作模式,都是mode=0x00,即:标准模幂运算。
我们来实际在板子上运行一下
>> 关掉优化,再编译
>> 检查板子选项字节配置,再下载
运行过程中,明显第二次用私钥计算的单步执行,可以感觉慢一点。我们加上计时代码,定量的看一下
添加计时相关代码:定义计时数组,初始化定时器,在想要考察的任务头、尾处添加时间戳记录。
我们准备对两端操作时间考察,一个是把操作数,即密钥、公钥,密文、明文,装载到PKA专用memory所需的时间。这个装载只能由CPU完成,不支持DMA。
另外一个是PKA硬件引擎执行模幂计算的时间,因此在PKA_Process() 函数里,置位START开始,到查询到操作完成标志置位结束。
运行起来,第一次PKA运行,停在memcmp这一句结束,来看timestamp数组,在运行过程中打了四个点,分别在关系的两个过程的一前一后,根据delta,可以大约得到这两个过程分别所耗的时钟周期。
我们再添加ICACHE使能,比较缺省状态下未使能ICACHE的情况下的运行测试结果。第一次运行结果是公钥参与的模幂计算,大概是135万个时钟周期,和STM32L5参考手册给出的表格,基本可以对的上。2048位RSA,公钥指数65536,通用用2^16+1表示,然后采用普通计算模式,而不是CRT快速计算方式。
表格里是大概122万个时钟周期。按照表格给出的理论值,计算出在以STM32L5最高主频110MHz的算力下,2048位公钥模幂运算,就是做加密或者验签,大约需要11ms左右。
继续运行,断点打在第二次memcmp结束的地方,这是使用2048位的私钥做模幂运算,按照表格8000多万个时钟周期,折算下来就是762ms。即RSA2048做解密或者签名,需要700多个ms。
《main.c》
#ifdef DWT_CYCCNT
uint32_t TimeStamp[4] = {0};
#endif
/* USER CODE BEGIN 1 */
#ifdef DWT_CYCCNT
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
/* Reset cycle counter */
DWT->CYCCNT = 0;
DWT->CTRL = 0x1;
#endif
/* USER CODE END 1 *
《stm32l5xx_hal_pka.c》
#ifdef DWT_CYCCNT
extern uint32_t TimeStamp[];
#endif
#ifdef DWT_CYCCNT
TimeStamp[0] = DWT->CYCCNT;
#endif
/* Set input parameter in PKA RAM */
PKA_ModExp_Set(hpka, in);
#ifdef DWT_CYCCNT
TimeStamp[1] = DWT->CYCCNT;
#endif
#ifdef DWT_CYCCNT
TimeStamp[2] = DWT->CYCCNT;
#endif
/* Start the computation */
hpka->Instance->CR |= PKA_CR_START;#ifdef DWT_CYCCNT
TimeStamp[3] = DWT->CYCCNT;
#endif
/* Check error */
hpka->ErrorCode |= PKA_CheckError(hpka, mode);
STM32L5参考手册里的表格,列出的是不同模长度情况下,使用不同长度密钥做RSA模幂计算的时钟周期,它不是以时间为单位,不是太直观。因此这个胶片把主要参数使用情境下的耗时列了出来,更加直观。
我们CubeL5固件包里和RSA模幂运算相关的例子,一个是刚才的标准模式,在使用值为65537的常用公钥情况下,最快可以11ms完成加密或者说验签操作;而对应的私钥很长,对应的解密和签名操作就需要大概762ms。
如果大家运行另外一个CRT例程,把计时代码也加进去测试一下,可以体会到,使用相同2048位私钥做RSA模幂运算,CRT快速模式的耗时,可以节省至少2/3,大概213毫秒。
CubeL5固件包里RSA模幂运算都是使用的2048位模长度,如果应用需要3072位RSA计算,我们首先要产生对应的公钥、私钥对,然后调整PKA调用的HAL驱动参数。
很多PC端工具可以生成RSA公私钥对。我们以gitbash为例来演示。
启动gitbash,输入命令:openssl genrsa –out rsa_priv_3072.pem 3072,然后你可以在当前目录下看到生成的公钥和私钥文件,它们是经过编码后,使用文本编辑器打开,可以看到标准的BEGIN和END标志文本。我们需要提前公钥私钥的二进制数据,放到代码中参与运算。于是在命令行输入命令:openssl rsa -in rsa_priv_3072.pem -text。就能看到模,公钥,私钥的二进制数据。
模和私钥指数,都是3072位的很大的大数,公钥指数还是常见的65537。把这两个大数据拷贝出来,去掉每个字节之间的【:】字符,每个数字字节前加上【0x】字符
关于RSA公私钥对的产生,小结一下。我们使用openssl中的genrsa命令,先生成3072位的私钥pem文件。可以继续使用rsa命令,由新生成的私钥文件计算出对应的公钥pem文件。
对两个公钥和私钥pem文件,继续使用rsa命令,得到对应的模、公钥指数、私钥指数二级制数据内容。经过矩阵化,作为数组,就可以被用到我们的工程中,作为参数喂给PKA硬件引擎,参与指定的模幂运算。
我们把新的密钥文件放到项目中,调整PKA模幂计算的输入参数,明文可以保持不变,甚至长度还是256字节、2048位没有问题。我们直接对明文加密,再对明文解密,得到的结果和明文数组比较。
在运行成功后,当然是比较结果一致,再添加计时代码,做一个耗时的参考。最后我们还是使用STM32L5参考手册里的数据值,转换成时间单位,得到一个感性的认识:使用RSA3072,加密和验签,大概需要24ms,而签名和解密,需要2.5s。
非对称加解密技术中,除了RSA之外,基于ECC椭圆曲线的数字签名和验签技术,也是运用非常广泛的算法。
在做ECC操作之前,通信双方协商出一条大家都能支持的曲线。PKA硬件引擎支持的曲线可以在STM32L5参考手册中查阅。
曲线确定了,它的相关参数就都确定了,包括模p,阶数n、曲线方程y2=x3+ax+b里面的协系数a和b,以及曲线的基点G。p和n的位数通常都一样,国际标准委员会发布的安全的ECC曲线中,有256位、320位、384位、512位、521位。协系数b、节点G的投影坐标值xG、yG,也都是很大的数,协系数a在由NIST发布的曲线上,通常是-3。
如何使用自己的私钥dA,对消息m做签名呢?这里私钥dA是一个整数。
先计算出消息的哈希值e,采用主流SHA2做哈希计算,根据模式不同,生成的哈希值有224、256、384和512位几种。
对生成的哈希值,取低几位,作为z。取低几位呢?位数就是曲线的阶数n,刚才说了有256,320,384,512位几种选择。
选择一个0到阶数n之间的随机数k,对基点G做k次点乘,后续是做各种大数的算术乘法、除法和取模。最后得到一对大数:r,s,作为使用私钥dA和消息m,在选定曲线上的签名。整个过程中,私钥dA和随机数k,都是需要保密的。
以上过程汇总,步骤4,5,6可以使用PKA做硬件加速。加速的方式有两种,一个是调用宏观API,即直接使用PKA支持的ECDSA这个工作模式,或者调用微观API的点乘,取模,模幂操作来组合完成。
我们打开STM32L5Cube固件包里DK板子下的PKA例子集合中的PKA_ECDSA_Sign。工程项目中有两个大家看起来比较陌生的文件:prime256v1.c,是NIST发布一的条安全椭圆曲线。里面列出了曲线的阶数、模、系数a、系数b、基点G,对应的x、y坐标值。SigGen.c,是从NIST-CAVP测试向量中选择的一个测试消息、选择的私钥d,随机数k,以及在NIST P-256曲线上做签名操作后的签名值。
PKA的HAL驱动封装出了对用户非常友好简便的接口,使用宏观API时,只要在输入参数中指定好两大部分内容,所用的曲线,和所用的私钥d、随机数k以及消息哈希值即可。
接下来,下载运行,直观体验一下。
和签名对应的操作是验签,ECDSA的验签原理:首先要确保对方的公钥点,在对应曲线上。这会用到PKA硬件引擎的另外一个工作模式,例程可以参考PKA例程集合目录下的“PKA_PointCheck”。对公钥点还要做另外两个核实,都可以使用PKA硬件引擎的“点乘”工作模式来完成。
验签方拿到了待验证的消息,消息的数字签名,可以使用PKA硬件引擎的“ECDSA 验签”来完成后续的大数计算。
我们打开STM32L5Cube固件包里DK板子下的PKA例子集合中的PKA_ECDSA_Verify。工程项目中的prime256v1.c文件和上一个例程一样,是NIST发布的一条安全椭圆曲线。里面列出了曲线的所有参数。SigVer.c,同上一个签名例子里的文件SigGen.c一样,是从NIST-CAVP测试向量中选择的一个测试样本。提供待测消息,其签名值,以及公钥点。
PKA的HAL驱动封装出了对用户非常友好简便的接口,只要在输入参数中指定好两大部分内容,所用的曲线,和所用的消息哈希值,公钥点即可。
|