上信息安全课,老师布置了几个大作业,其中一个为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__
View Code

相关文章: