RSA Public-Key Encryption and Signature Lab
本次实验的目的是对RSA有个手动的实际的体验。
BIGNUM APIs
一些库函数要求临时变量。在重复的子程序调用时,创建BIGNUM所需的动态内存分配是非常昂贵的,一个BN_CTX结构被创建来放置库函数会使用的BIGNUM临时变量。我们需要创建这种结构并将其传递给需要它的函数
BN_CTX *ctx = BN_CTX_new()
初始化一个BIGNUM变量
BIGNUM *a = BN_new()
给BIGNUM变量分配值有如下方法
//分配一个10进制字符值
BN_dec2bin(&a,”1125654765”);
//分类一个16进制数字
BN_hex2bin(&a,”2A2B”);
//生成128位的随机数
BN_rand(a,128,0,0);
//生成128位的随机素数
BN_generate_prime_ex(a,128,1,NULL,NULL,NULL);
打印一个大数
Void printBN(char *msg,BIGBUM *a)
{
//把BIGNUM转为number string
Char *number_str = BN_dn2dec(a);
//打印number string
Printf(“%s %s\n”,msg,number_str);
//释放动态分配的内存
OPENSSL_free(number_str);
}
计算res=a-b和res=a+b;
BN_sub(res,a,b);
BN_add(res,a,b);
计算res=a*b(注意,在这个API中需要BN_CTX结构)
BN_mul(res,a,b,ctx)
计算res=a*b mod n:
BN_mod_mul(res,a,b,n,ctx)
计算res=a^c mod n:
BN_mod_exp(res,a,c,n,ctx)
计算模逆,比如给定a,计算b,使得a*b mod n =1,b则称为a在模n下的逆
BN_mod_inverse(b,a,n,ctx)
一个典型的代码如下
#include <stdio.h>
#include <openssl/bn.h>
#define NBITS 256
void printBN(char *msg,BIGNUM *a)
{
char * number_str = BN_bn2hex(a);
printf("%s %s\n",msg,number_str);
OPENSSL_free(number_str);
}
int main()
{
BN_CTX *ctx = BN_CTX_new();
BIGNUM *a = BN_new();
BIGNUM *b = BN_new();
BIGNUM *n = BN_new();
BIGNUM *res = BN_new();
BN_generate_prime_ex(a,NBITS,1,NULL,NULL,NULL);
BN_dec2bn(&b,"273489463796838501848592769467194369268");
BN_rand(n,NBITS,0,0);
BN_mul(res,a,b,ctx);
printBN("a*b=",res);
BN_mod_exp(res,a,b,n,ctx);
printBN("a^c mod n=",res);
return 0;
}
编译时记得加上-lcrypto,告诉编译器使用crypto库
从结果可以看出,确实成功实现了大数的运算
Task1 得到私钥
已知
Task2:加密消息
首先将ascii字符串转成16进制,然后使用hex-to-bn的API BN_hex2bin()将其转为BIGNUM
将ascii转16进制可以类似如下代码
将16进制转ascii可以用python实现
手动获取百度的证书
其中
s是subject,可以看到是百度,i是issuer,是签发者
这里是第二个证书
Root ca的证书可以从浏览器中得到
找到和issuer对应的
将其证书导出
然后我们分别将两个证书(Begin和End之间的部分)保存为c0.pem,c1.pem
接下来我们要从签发者的证书中提取出公钥(e,n)
提取n:
打印出所有的域,来找e
然后从服务器证书中提取签名,openssl没有命令可以直接提取,我们需要首先将全部的域打印出来,然后将签名部分复制粘贴保存到一个文件
我们需要移除数据中的空格、冒号等
提取服务器证书的主体body
CA首先会为服务器证书计算hash,然后对hash签名。为了验证签名,我们需要从证书中生成hash。由于hash是在签名前生成的,所以我们在计算时需要排除证书中的签名部分。
如果不理解证书的格式的话,找出证书的哪部分用于生成hash还是由难度的。
X.509证书使用ASN.1标准进行编码,如果我们可以解析ASN.1结构,我们就可以很容易提取出证书的任何域。openssl有相关命令可以用于解析
红色框开始是签名部分
他们的偏移就是每行最前面的数字
在我们的情况中,证书的body是从4到2333,而签名是从2334直到文件末尾
对于x.509证书而言,起始的偏移都是一样的,从4开始。
我们可以使用如下命令提取:
上图顺便计算了hash
然后就可以验证签名了