在坑里面折腾了两天时间,搞的是心力憔悴。最后问题解决后才发现,在这个坑里折腾这么久当真不应该。分享下心路历程,后来者引以为戒。
问题描述
RSA算法最典型的使用方式是在客户端生成公钥私钥对,将公钥发送到服务器。然后服务器与客户端间的通信数据就可以通过这一对公钥私钥加解密了。这个典型流程也可以参考我这篇文章。
提交公钥数据最常见的方式是将公钥信息转化成一串字符串后提交。还有一种方式是同时提取出公钥中的modules与exponent数据上传,而这个坑就出现在后一种方式上。
struct rsa_st {
/*
* The first parameter is used to pickup errors where this is passed
* instead of aEVP_PKEY, it is set to 0
*/
int pad;
long version;
const RSA_METHOD *meth;
/* functional reference if 'meth' is ENGINE-provided */
ENGINE *engine;
BIGNUM *n;
BIGNUM *e;
BIGNUM *d;
BIGNUM *p;
BIGNUM *q;
BIGNUM *dmp1;
BIGNUM *dmq1;
BIGNUM *iqmp;
/* be careful using this if the RSA structure is shared */
CRYPTO_EX_DATA ex_data;
int references;
int flags;
/* Used to cache montgomery values */
BN_MONT_CTX *_method_mod_n;
BN_MONT_CTX *_method_mod_p;
BN_MONT_CTX *_method_mod_q;
/*
* all BIGNUM values are actually in the following data, if it is not
* NULL
*/
char *bignum_data;
BN_BLINDING *blinding;
BN_BLINDING *mt_blinding;
};
在一次破解实践中,我注意到自己demo中用openssl生成的公钥信息结构中n、e的值与动态调试app中的数据恰好互换了位置:即app中n与demo中的e一致,app中e与demo中n一致。给人的感觉好像是这个app重写了openssl里的RSA对象结构,导致了n、e的位置与公开的头文件不一致。当时我也有想到可能是openssl版本不一致导致,但偷懒的情绪使我完全没有在这条路上深入下去。
我按照第一种想法简单的将n、e的值手动互换并上报到服务器,然后服务器也成功接受并返回了加密的数据,只是无法用私钥成功解密。如此这样成功入坑,并在坑里反复折腾,想尽各种办法,就是没有任何效果。
问题解决
最终无奈之下决定下载个低版本试试,在openssl官网下载了一个1.0.0版本。编译后引入工程,测试发现n、e值不在像以前那样错位了,服务器返回数据也成功解密了。天终于又亮了,心情瞬间阳光普照了。。。。
问题反思
这个问题的本质是目标app使用的openssl版本与我使用的版本不一致,而这两个版本在RSA对象结构上的细微差别恰好导致了问题的出现。
回头反思整个入坑过程,最主要的原因还是自己对openssl中RSA结构不熟悉导致。如果能够对RSA结构体内的每个成员变量的含义了如指掌、对RSA的算法原理洞若观火,相信应该一眼就能看出问题的本质来。看来后面要补一补基本算法方面的缺了,有人能给推荐本常用加密算法的书籍么?