RSA加解密(优化---大数加密)

上一篇博客已经简单的完成了RSA加密,建议看完上一篇博客再来查看本文章:
https://blog.csdn.net/Watery________1314/article/details/96719658
这次我们将对之前的简单加密进行优化,实现大数加密,还有一部分性能优化。
首先要添加外部依赖库boost库,具体添加库方法请见:
https://blog.csdn.net/Watery________1314/article/details/96981400
添加好boost库后我们就可以对之前的数据进行优化了,这里引入以下三个头文件:
#include
#include
#include
先将之前的数据类型long替换成int1024_t,其次对产生素数函数produce_prime()和生成dkey函数produce_dkey()分别进行优化。
1.产生素数函数produce_prime()

bm::int1024_t RSA::produce_prime() { //srand(time(nullptr)); bm::int1024_t prime = 0; //mt19937:一种随机数产生器 boost::random::mt19937 gen(time(nullptr)); //指定随机数的范围 2 ~ (1<<128) boost::random::uniform_int_distribution dist(2, bm::int1024_t(1) << 128); while (1) { prime = dist(gen); if (is_prime_bigInt(prime)) break; } return prime; }

这里使用了boost库中的mt19937(一种随机数产生器)来产生一个随机数,这里的随机数范围发生了变化,我们这里让它最大可以到(1<<128),这里的判断是否为素数也进行一个优化,如下代码:
bool RSA::is_prime_bigInt(const bm::int1024_t digit) { boost::random::mt11213b gen(time(nullptr)); if (miller_rabin_test(digit, 25, gen)) //素数测试算法miller_rabin_test() { if (miller_rabin_test((digit - 1) / 2, 25, gen)) { return true; } } return false; }

这里的判断是否是素数,并不是按照之前的那种从2开始一个个模运算来判断的方法,这里使用了素数测试算法Miller-Rabin,这个算法我看了一下,没有理解的很深刻,如果有需要可以去看看其他博客。
2.生成ekey函数produce_ekey()
bm::int1024_t RSA::produce_dkey(bm::int1024_t ekey, bm::int1024_t orla) { bm::int1024_t x, y; exgcd(ekey, orla, x, y); return (x % orla + orla) % orla; }/* 扩展的欧几里得算法 x = y1; y = x1 - [a/b]*y1 */bm::int1024_t RSA::exgcd(bm::int1024_t ekey, bm::int1024_t orla, bm::int1024_t &x, bm::int1024_t &y) { if (orla == 0) { x = 1; y = 0; return ekey; } bm::int1024_t ret = exgcd(orla, ekey % orla, x, y); bm::int1024_t x1 = x, y1 = y; x = y1; y = x1 - (ekey / orla) * y1; return ret; }


这里就需要看一下扩展的欧几里得算法:
扩展的欧几里得算法:不仅要求出(a,b)的最大公约数gcd,也要求出其中的一组解(x,y), 满足等式ax + by = gcd。从上
面的算法可知当b=0时,gcd即可求出,所以可以在求出gcd的同时也求出(x,y)。
我们观察一下等式,ax + by = gcd, 当b = 0时, 等式变成了ax = gcd,此时我们返回a的值,a既是所求的最大公约
数gcd,故此时x = 1, y可以是任意值, 所以,简单的一组解即为(1, 0)。
现在再让我们回头看模的逆元的等式:ab%n = 1。 ab - 1为n的倍数, 即 ab + kn = 1, 这里放入加密算法中对应的即
为: ed + kφ(n) = 1, 其中e为加密密钥, d为解密密钥, e与φ(n)互质,他们的最大公约数即为1,所以这里的解密密
钥d和k就相当于等式的一组解,此解可以用扩展的欧几里得算法求解。
这里我们假设d = x, k = y, e = a, φ(n) = b, 则等式ed + kφ(n) = 1即变为ax + by = 1, 通过欧几里得递归算法,当b=0
时,可求得一组解(1,0)和最大公约数1。递归的时候,在获取最终结果之前,已经求出了下一个状态:b 和 a%b 的最大公约数,假设此时求得了一组解(x1,y1),使得bx1 + (a % b)y1 = 1。
而这里 a % b = a - [a / b] * b, 其中[a/b]表示向下取整, 带入上述等式,即为:
bx1 + (a - [a / b] * b)y1 = 1,继续变形:
bx1 + ay1 - [a/b]*by1 = 1,继续变形:
ay1 + b(x1 - [a/b]y1) = 1
当我们去求解(x,y)使ax + by = 1,可以看到此解和bx1 + (a % b)y1 = 1的关系如下:
x = y1, y = x1 - [a/b]y1
即在递归的过程中最终的结果可以通过上次递归的结果推导出来,关系如上所示。算法最终求得一组解(x,y)和最大公
约数1。此时我们一般会找出最小的那个解对应的x,只需要x%b即可。如果x为一个解,则ax + by = 1, 则它的通解为x + k*b,使a(x + k * b) % b = 1,这里ax % b = 1, (k * b) % b = 0, 总体结果还是为1。所以a关于b的逆元x是一个关于b的同余数,所以一定存在一个最小的正整数,它是a关于b的逆元,而最小的肯定在(0,b)之间。
有时候我们得到的解x是一个负数,所以统一处理,可以直接进行操作: (x % b +b) % b。这里的b也就是程序中的orla,替换即可。
以上就是对之前程序的优化,下面将附上完整的代码:
1.RSA.h
#pragma once #include #include #include #include #include namespace bm = boost::multiprecision; struct Key { bm::int1024_t pkey; //公钥(ekey, pkey): (e,n) bm::int1024_t ekey; //私钥(dkey, pkey): (d, n) bm::int1024_t dkey; }; class RSA { public: RSA(); Key getKey() { return _key; } void ecrept(const char* plain_file_in, const char* ecrept_file_out, bm::int1024_t ekey, bm::int1024_t pkey); //加密 void decrept(const char* ecrept_file_in, const char* plain_file_out, bm::int1024_t dkey, bm::int1024_t pkey); //解密 std::vector ecrept(std::string& str_in, bm::int1024_t ekey, bm::int1024_t pkey); //字符串加密 std::string decrept(std::vector& ecrept_str, bm::int1024_t dkey, bm::int1024_t pkey); //解密为字符串 void printInfo(std::vector& ecrept_str); //打印信息 private: bm::int1024_t ecrept(bm::int1024_t msg, bm::int1024_t key, bm::int1024_t pkey); //加密单个信息 bm::int1024_t produce_prime(); //产生素数 bool is_prime(bm::int1024_t prime); //是否为素数 bool is_prime_bigInt(bm::int1024_t prime); void produce_keys(); bm::int1024_t produce_pkey(bm::int1024_t prime1, bm::int1024_t prime2); //计算pq乘积n bm::int1024_t produce_orla(bm::int1024_t prime1, bm::int1024_t prime2); //计算欧拉函数φ(n) bm::int1024_t produce_ekey(bm::int1024_t orla); //产生e bm::int1024_t produce_gcd(bm::int1024_t ekey, bm::int1024_t orla); //产生最大公约数 bm::int1024_t produce_dkey(bm::int1024_t ekey, bm::int1024_t orla); //产生d bm::int1024_t exgcd(bm::int1024_t ekey, bm::int1024_t orla, bm::int1024_t &x, bm::int1024_t &y); private: Key _key; }; // 1. 随机选择两个不相等的质数p和q(实际应用中,这两个质数越大,就越难破解)。 // 2. 计算p和q的乘积n,n = pq。 // 3. 计算n的欧拉函数φ(n)。 // 4. 随机选择一个整数e,条件是1 < e < φ(n),且e与φ(n) 互质。 // 5. 计算e对于φ(n)的模反元素d,使得de≡1 mod φ(n),即: //(de)modφ(n) = 1 // 6. 产生公钥(e, n),私钥(d, n)。

2.RSA.cpp
#include"RSA.h" #include #include #include #includeRSA::RSA() { produce_keys(); }void RSA::ecrept(const char* plain_file_in, const char* ecrept_file_out, bm::int1024_t ekey, bm::int1024_t pkey)//加密 { std::ifstream fin(plain_file_in, std::ifstream::binary); std::ofstream fout(ecrept_file_out, std::ofstream::binary); if (!fin.is_open()) { std::cout << "open file failed" << std::endl; return; } const int NUM = 128; char buffer[NUM]; bm::int1024_t buffer_out[NUM]; int curNum; while (!fin.eof()) { fin.read(buffer, NUM); curNum = fin.gcount(); for (int i = 0; i < curNum; ++i) { buffer_out[i] = ecrept(buffer[i], ekey, pkey); } fout.write((char *)buffer_out, curNum * sizeof(bm::int1024_t)); } fin.close(); fout.close(); } void RSA::decrept(const char* ecrept_file_in,const char* plain_file_out, bm::int1024_t dkey, bm::int1024_t pkey)//解密 { std::ifstream fin(ecrept_file_in, std::ifstream::binary); std::ofstream fout(plain_file_out, std::ofstream::binary); if (!fin.is_open()) { std::cout << "open file failed" << std::endl; return; } const int NUM = 256; bm::int1024_t buffer[NUM]; char buffer_out[NUM]; int curNum; while (!fin.eof()) { fin.read((char *)buffer, NUM * sizeof(bm::int1024_t)); curNum = fin.gcount() / sizeof(bm::int1024_t); for (int i = 0; i < curNum; ++i) { buffer_out[i] = (char)ecrept(buffer[i], dkey, pkey); } fout.write(buffer_out, curNum); } fin.close(); fout.close(); }std::vector RSA::ecrept(std::string& str_in, bm::int1024_t ekey, bm::int1024_t pkey)//字符串加密 { std::vector vecout; size_t sz = str_in.size(); for (const auto& e : str_in) { vecout.push_back(ecrept(e, ekey, pkey)); } return vecout; } std::string RSA::decrept(std::vector& ecrept_str, bm::int1024_t dkey, bm::int1024_t pkey)//解密为字符串 { std::string strout; for (const auto& e : ecrept_str) { strout.push_back((char)ecrept(e, dkey, pkey)); } return strout; }void RSA::printInfo(std::vector& ecrept_str)//打印信息 { for (const auto & e : ecrept_str) { std::cout << e << ' '; } std::cout << std::endl; }//模幂运算(a^b)%c bm::int1024_t RSA::ecrept(bm::int1024_t msg, bm::int1024_t key, bm::int1024_t pkey) { bm::int1024_t msg_out = 1; //A0:a^(2^0) = a^1 = a bm::int1024_t a = msg; bm::int1024_t b = key; bm::int1024_t c = pkey; while (b) { if (b & 1) //msg_out = (A0 * A1 ...Ai ... An) % c msg_out = (msg_out * a) % c; b >>= 1; //Ai = (A(i - 1) * A(i - 1)) % c a = (a * a) % c; } return msg_out; }//随机产生一个素数 bm::int1024_t RSA::produce_prime() { //srand(time(nullptr)); bm::int1024_t prime = 0; //mt19937:一种随机数产生器 boost::random::mt19937 gen(time(nullptr)); //指定随机数的范围 2 ~ (1<<128) boost::random::uniform_int_distribution dist(2, bm::int1024_t(1) << 128); while (1) { prime = dist(gen); if (is_prime_bigInt(prime)) break; } return prime; }bool RSA::is_prime(bm::int1024_t prime) { if (prime < 2) return false; for (bm::int1024_t i = 2; i < sqrt(prime); ++i) { if (prime % i == 0) return false; } return true; }bool RSA::is_prime_bigInt(const bm::int1024_t digit) { boost::random::mt11213b gen(time(nullptr)); if (miller_rabin_test(digit, 25, gen)) //素数测试算法miller_rabin_test() { if (miller_rabin_test((digit - 1) / 2, 25, gen)) { return true; } } return false; }void RSA::produce_keys() { bm::int1024_t prime1 = produce_prime(); bm::int1024_t prime2 = produce_prime(); while (prime1 == prime2) prime2 = produce_prime(); _key.pkey = produce_pkey(prime1, prime2); bm::int1024_t orla = produce_orla(prime1, prime2); _key.ekey = produce_ekey(orla); _key.dkey = produce_dkey(_key.ekey, orla); }bm::int1024_t RSA::produce_pkey(bm::int1024_t prime1, bm::int1024_t prime2) { return prime1 * prime2; }bm::int1024_t RSA::produce_orla(bm::int1024_t prime1, bm::int1024_t prime2) { return (prime1 - 1) * (prime2 - 1); }//随机选择一个整数e,条件是1 < e < φ(n),且e与φ(n) 互质 bm::int1024_t RSA::produce_ekey(bm::int1024_t orla) { bm::int1024_t ekey; srand(time(nullptr)); while (1) { ekey = rand() % orla; if (ekey > 1 && produce_gcd(ekey, orla) == 1) break; } return ekey; }//求最大公约数 bm::int1024_t RSA::produce_gcd(bm::int1024_t ekey, bm::int1024_t orla) { //gcd(a, b)------gcd(b ,a%b) bm::int1024_t ret; while (ret = ekey % orla) { ekey = orla; orla = ret; } return orla; }bm::int1024_t RSA::produce_dkey(bm::int1024_t ekey, bm::int1024_t orla) { bm::int1024_t x, y; exgcd(ekey, orla, x, y); return (x % orla + orla) % orla; }/* 扩展的欧几里得算法 x = y1; y = x1 - [a/b]*y1 */bm::int1024_t RSA::exgcd(bm::int1024_t ekey, bm::int1024_t orla, bm::int1024_t &x, bm::int1024_t &y) { if (orla == 0) { x = 1; y = 0; return ekey; } bm::int1024_t ret = exgcd(orla, ekey % orla, x, y); bm::int1024_t x1 = x, y1 = y; x = y1; y = x1 - (ekey / orla) * y1; return ret; }

3.test.cpp
#include"RSA.h" #includevoid teststring() { RSA rsa; Key key = rsa.getKey(); std::string strin; while (1) { std::cout << "输入要加密的信息:" << std::endl; std::cin >> strin; std::vectorstrecrept = rsa.ecrept(strin, key.ekey, key.pkey); std::string strout = rsa.decrept(strecrept, key.dkey, key.pkey); std::cout << "加密后的信息:" << std::endl; rsa.printInfo(strecrept); std::cout << "解密后的信息:" << std::endl; std::cout << strout << std::endl; std::cout << std::endl; } }void testFile() { RSA rsa; Key key = rsa.getKey(); std::string filename; std::cout << "输入文件名:" << std::endl; std::cin >> filename; rsa.ecrept(filename.c_str(), (filename + ".ecrept.jpg").c_str(), key.ekey, key.pkey); rsa.decrept((filename + ".ecrept.jpg").c_str(), (filename + ".decrept.jpg").c_str(), key.dkey, key.pkey); //IO标准库使用C风格字符串而不是C++ string类型字符串作为文件名,所以需要用c_str获取C风格字符串 //c风格的字符串是可以隐式转换成string的,但string无法隐式转换成c风格的字符串 //为了把string转换成ifstream可以接受的类型,必须把string转换为c风格的字符串。 }//void testRandom() //{ // //mt19937:一种随机数产生器 // boost::random::mt19937 gen(time(nullptr)); // std::cout << "random" << std::endl; // //指定随机数的范围 0 ~ (1<<786) // boost::random::uniform_int_distribution dist(0, bm::cpp_int(1) << 768); // std::cout << dist(gen) << std::endl; //}int main() { //teststring(); testFile(); //testBigInt(); system("pause"); return 0; }

【RSA加解密(优化---大数加密)】

    推荐阅读