上信息安全课,老师布置了几个大作业,其中一个为RSA加密算法的实现,不能用Java写。出于兴趣,决定尝试。完成之后,为了便于查找,于是写下这篇文章,以备后续查看。也供大家一起学习,一起进步。
1、预备知识
1.1 快速幂算法
顾名思义,快速幂就是快速算底数的$n$次幂。其时间复杂度为${\rm{O(log n)}}$,与朴素的$O\left( n \right)$相比,效率有了极大的提高。具体可以参考百度百科:快速幂。
1.2 扩展欧几里得算法
扩展欧几里得算法(英语:Extended Euclidean algorithm)是欧几里得算法(又叫辗转相除法)的扩展。已知整数a、b,扩展欧几里得算法可以在求得a、b的最大公约数的同时,能找到整数x、y(其中一个很可能是负数),使它们满足贝祖等式
\[ax{\rm{ }} + {\rm{ }}by{\rm{ }} = {\rm{ }}gcd\left( {a,b} \right).\]
如果$a$是负数,可以把问题转化成
$\left| a \right|\left( { - x} \right){\rm{ }} + {\rm{ }}by{\rm{ }} = {\rm{ }}gcd\left( {\left| a \right|,b} \right)$($\left| a \right|$为a的绝对值),然后令$x\prime {\rm{ }} = {\rm{ }}\left( { - x} \right)$。具体可以参考维基百科:扩展欧几里得。
1.3 米勒-拉宾素性检验算法
要测试${\rm{N}}$是否为素数,首先将${\rm{N - 1}}$分解为${2^s}d$。在每次测试开始时,先随机选一个介于$[1,N - 1]$的整数$a$,之后如果对所有的$r \in [0,s - 1]$,若${a^d}\bmod N \ne 1$且${a^{{2^r}d}}\bmod N \ne - 1$,则$N$是合数。否则,$N$有$3/4$的概率为素数。
构成该算法的思想是,如果${a^d} \ne 1\left( {{\rm{mod n}}} \right)$以及$n = 1{\rm{ }} + {\rm{ }}{2^s}d$是素数,则值序列
\[{a^d}mod n,{a^{2d}}mod n,{a^{4d}}mod n, \ldots ,{a^{{2^s}d}}mod n\]
将以$1$结束,而且在头一个$1$的前边的值将是$n-1$(当$p$是素数时,对于${y^2} \equiv 1\left( {mod p} \right)$,仅有的解是$y \equiv \pm 1\left( {mod p} \right)$,因为$\left( {y + 1} \right)\left( {y - 1} \right)$必须是$p$的倍数)。注意,如果在该序列中出现了$n-1$,则该序列中的下一个值一定是$1$,因为${\left( {n-1} \right)^2} \equiv {n^2}-2n + 1 \equiv 1\left( {mod n} \right)$。具体可以参考维基百科:米勒-拉宾素性检验。
1.4 RSA加密算法
1.4.1 公钥与私钥的产生
假设Alice想要通过一个不可靠的媒体接收Bob的一条私人消息。她可以用以下的方式来产生一个公钥和一个私钥:
1、随意选择两个大的质数$p$和$q$,$p$不等于$q$,计算$N = pq$。
2、根据欧拉函数,求得$r = \varphi (N) = \varphi (p)\varphi (q) = (p - 1)(q - 1)$。
3、选择一个小于$r$的整数$e$,使$e$与$r$互质。并求得$e$关于$r$的模反元素,命名为$d$(求$d$令$ed \equiv 1(\bmod \;r)$)。(模反元素存在,当且仅当$e$与$r$互质)
4、将$p$和$q$的记录销毁。
$\left( {N,e} \right)$是公钥,$\left( {N,d} \right)$是私钥。Alice将她的公钥$\left( {N,e} \right)$传给Bob,而将她的私钥$\left( {N,d} \right)$藏起来。
1.4.2 加密消息
假设Bob想给Alice送一个消息$m$,他知道Alice产生的$N$和$e$。他使用起先与Alice约好的格式将$m$转换为一个小于$N$,且与$N$互质的整数$n$,比如他可以将每一个字转换为这个字的Unicode码,然后将这些数字连在一起组成一个数字。假如他的信息非常长的话,他可以将这个信息分为几段,然后将每一段转换为$n$。用下面这个公式他可以将$n$加密为$c$:
\[{n^e} \equiv c({\rm{mod\;}}N)\]
计算$c$并不复杂。Bob算出$c$后就可以将它传递给Alice。
1.4.3 解密消息
Alice得到Bob的消息$c$后就可以利用她的密钥$d$来解码。她可以用以下这个公式来将$c$转换为$n$:
\[{c^d} \equiv n({\rm{mod\;}}N)\]
得到$n$后,她可以将原来的信息$m$重新复原。
解码的原理是
\[{c^d} \equiv {n^{ed}}({\rm{mod}}\:N)\]
已知$ed \equiv 1(\bmod \;r)$,即$ed = 1 + h\varphi (N)$。由欧拉定理得:
\[{n^{ed}} = {n^{1 + h\varphi (N)}} = n{\left( {{n^{\varphi (N)}}} \right)^h} \equiv n{(1)^h}(\bmod \;N) \equiv n(\bmod \;N)\]
RSA也可用作数字签名。具体可以参考维基百科:RSA。
2、模块设计
2.1 BigInteger类
因为该加密算法涉及的数可能很大,而C++中并没有像Java一样,内置大整数类BigInteger,故需自己实现,我的实现大概是模仿Java的BigInteger设计的。
该模块包含两个文件:BigInteger.h和BigInteger.cpp。代码如下所示。
BigInteger.h代码如下。
1 /** 2 * @Name : BigInteger.h 3 * @Date : 2017-04-11-22.11.39 4 * @Author : Silenceneo (silenceneo_xw@163.com) 5 * @Link : http://www.cnblogs.com/Silenceneo-xw/ 6 * @Version : 2.0 7 */ 8 9 #ifndef __BIGINTEGER_H__ 10 #define __BIGINTEGER_H__ 11 12 #include <string> 13 #include <vector> 14 #include <ostream> 15 class BigInteger { 16 public: 17 typedef long long long_t; 18 typedef unsigned base_t; 19 BigInteger(): is_negative(false) { data.push_back(0); }// 默认为0 20 BigInteger(const BigInteger &); // 利用给定的大整数初始化 21 BigInteger(const std::string &);// 利用给定的十六进制字符串初始化 22 BigInteger(const long_t &); // 利用给定的long_t类型数据初始化 23 ~BigInteger() {} 24 25 BigInteger add(const BigInteger &); // 大整数加法 26 BigInteger subtract(const BigInteger &);// 大整数减法 27 BigInteger multiply(const BigInteger &) const;// 大整数乘法 28 BigInteger divide(const BigInteger &); // 大整数整除 29 BigInteger remainder(const BigInteger &); // 大整数取余 30 BigInteger mod(const BigInteger &); // 大整数取模 31 BigInteger divideAndRemainder(const BigInteger &, BigInteger &);// 大整数整除和取余 32 BigInteger pow(const BigInteger &); // 大整数幂乘 33 BigInteger modPow(const BigInteger &, const BigInteger &) const;// 大整数幂模运算 34 BigInteger modInverse(const BigInteger &);// 用扩展欧几里得算法求乘法逆元 35 36 BigInteger shiftLeft(const unsigned); // 移位运算,左移 37 BigInteger shiftRight(const unsigned); // 移位运算,右移 38 39 int compareTo(const BigInteger &) const;// 比较运算 40 bool equals(const BigInteger &) const;// 判断是否等于给定数 41 static BigInteger valueOf(const long_t &);// 将给定数转换为大整数并返回 42 std::string toString() const; // 将大整数转换为十六进制字符串 43 BigInteger abs() const; // 求大整数的绝对值 44 protected: 45 // 以下运算符重载函数主要用于像基本类型一样使用大整数类型 46 friend BigInteger operator + (const BigInteger &, const BigInteger &); 47 friend BigInteger operator - (const BigInteger &, const BigInteger &); 48 friend BigInteger operator * (const BigInteger &, const BigInteger &); 49 friend BigInteger operator / (const BigInteger &, const BigInteger &); 50 friend BigInteger operator % (const BigInteger &, const BigInteger &); 51 friend bool operator < (const BigInteger &, const BigInteger &); 52 friend bool operator > (const BigInteger &, const BigInteger &); 53 friend bool operator == (const BigInteger &, const BigInteger &); 54 friend bool operator <= (const BigInteger &, const BigInteger &); 55 friend bool operator >= (const BigInteger &, const BigInteger &); 56 friend bool operator != (const BigInteger &, const BigInteger &); 57 58 // 重载版本,使其能用于long_t类型 59 friend BigInteger operator + (const BigInteger &, const long_t &); 60 friend BigInteger operator - (const BigInteger &, const long_t &); 61 friend BigInteger operator * (const BigInteger &, const long_t &); 62 friend BigInteger operator / (const BigInteger &, const long_t &); 63 friend BigInteger operator % (const BigInteger &, const long_t &); 64 friend bool operator < (const BigInteger &, const long_t &); 65 friend bool operator > (const BigInteger &, const long_t &); 66 friend bool operator == (const BigInteger &, const long_t &); 67 friend bool operator <= (const BigInteger &, const long_t &); 68 friend bool operator >= (const BigInteger &, const long_t &); 69 friend bool operator != (const BigInteger &, const long_t &); 70 71 friend std::ostream & operator << (std::ostream &, const BigInteger &); 72 BigInteger operator = (const std::string & str) { return (*this) = BigInteger(str); } 73 BigInteger operator = (const long_t & num) { return (*this) = BigInteger(num); } 74 private: 75 BigInteger trim(); // 去掉高位无用的0 76 int hexToNum(char); // 十六进制字符转换为十进制数 77 public: 78 static const int base_bit = 5; // 2^5=32,大整数每位存储的二进制位数 79 static const int base_char = 8; // 组成大整数的一位需要的十六进制位数 80 static const int base_int = 32; // 大整数一位对应的二进制位数 81 static const int base_num = 0xffffffff;// 截取低位的辅助 82 static const int base_temp = 0x1f; // 截取模32的余数的辅助 83 static const BigInteger ZERO; // 大整数常量0 84 static const BigInteger ONE; // 大整数常量1 85 static const BigInteger TWO; // 大整数常量2 86 static const BigInteger TEN; // 大整数常量10 87 private: 88 bool is_negative;// 是否为负数 89 std::vector<base_t> data;// 按位数据存储,高位在后 90 class bit { // 便于大整数运算的二进制处理类 91 public: 92 bit(const BigInteger &);// 根据大整数初始化 93 94 size_t size() { return length; } // 返回大整数对应的二进制位数 95 bool at(size_t); // 返回第i位二进制是否为1 96 private: 97 std::vector<base_t> bit_vector; // 二进制数据存储,每一个元素对应32位二进制 98 size_t length; // 二进制的总位数 99 }; 100 friend class RSA; // RSA为其友元类 101 }; 102 103 #endif // __BIGINTEGER_H__