RSA加密算法的数学原理

RSA数学原理

获取两个不相等的质数pq

质数又称素数,在自然数中,除了1和自身外,不能被其他自然数整除。比如10以内的质数有:1,2,3,5,7。

把p和q相乘,得到n

比如:n=61*53=3233,用二进制表示为:110010100001。

我们常说的RSA算法中的多少位,就是n用二进制表示后的位数,在我们例子就是12位。目前商用中一般都是2048位。

计算出小于n的自然数中,有多少数与n互质(欧拉函数)

如果两个数的最大公约数为1,那么我们说这两个数互质,记:GCD(a,b)=1。其中GCD表示两个数的最大公约数。

使用欧拉函数来判断是否互质:

  • 情况1:如果n=1,那么与n互质的自然数只有1
    φ ( n ) = 1 φ(n)=1 φ(n)=1

  • 情况2:如果n是质数,那么与n互质的自然数有n-1个,
    φ ( n ) = n − 1 φ(n)=n-1 φ(n)=n1
    例:φ(7)=6例:φ(7)=6

  • 情况3:如果n可以因式分解为两个互质数的乘积,则:
    φ ( n ) = φ ( p ) × φ ( q ) = ( p − 1 ) × ( q − 1 ) 例: φ ( 56 ) = φ ( 7 ) ∗ φ ( 8 ) = 6 ∗ 7 = 42 φ(n)=φ(p)\times φ(q)=(p-1)\times (q-1) \\ 例:φ(56)=φ(7)*φ(8) = 6 * 7 = 42 φ(n)=φ(p)×φ(q)=(p1)×(q1)例:φ(56)=φ(7)φ(8)=67=42

  • 情况4:如果n可以写成某个数的质数次幂(其中k为质数),则:
    φ ( n ) = φ ( p k ) = p k − p k − 1 = p k ( 1 − 1 p ) 例: φ ( 49 ) = φ ( 7 2 ) = 7 2 − 7 1 = 42 φ(n)=φ(p^k)=p^k-p^{k-1}=p^k(1-\frac 1p) \\ 例:φ(49)=φ(7^2)=7^2 - 7^1 = 42 φ(n)=φ(pk)=pkpk1=pk(1p1)例:φ(49)=φ(72)=7271=42

  • 情况5:根据以上规律,总结出一个通用的公式:

n = p 1 k 1 × p 2 k 2 … p r k r 注:任意一个整数,都可以写成两个质数的乘积 \qquad n=p_1^{k^1} \times p_2^{k^2} \ldots p_r^{k^r} \quad 注:任意一个整数,都可以写成两个质数的乘积 n=p1k1×p2k2prkr注:任意一个整数,都可以写成两个质数的乘积
⇓ \qquad \Downarrow
φ ( n ) = φ ( p 1 k 1 ) × φ ( p 2 k 2 ) … φ ( p r k r ) \qquad φ(n)=φ(p_1^{k^1}) \times φ(p_2^{k^2})\ldots φ(p_r^{k^r}) φ(n)=φ(p1k1)×φ(p2k2)φ(prkr)
⇓ \qquad \Downarrow
φ ( n ) = p 1 k 1 ( 1 − 1 p 1 ) × p 2 k 2 ( 1 − 1 p 2 ) … p r k r ( 1 − 1 p r ) \qquad φ(n)= p_1^{k^1}(1- \frac 1p_1) \times p_2^{k^2}(1- \frac 1p_2) \ldots p_r^{k^r}(1- \frac 1p_r) φ(n)=p1k1(1p11)×p2k2(1p12)prkr(1p1r)
⇓ \qquad \Downarrow
φ ( n ) = p 1 k 1 × p 2 k 2 … p r k r × ( 1 − 1 p 1 ) × ( 1 − 1 p 2 ) … ( 1 − 1 p n ) \qquad φ(n)=p_1^{k^1} \times p_2^{k^2}\ldots p_r^{k^r}\times (1- \frac 1p_1)\times(1- \frac 1p_2)\ldots(1- \frac 1p_n) φ(n)=p1k1×p2k2prkr×(1p11)×(1p12)(1p1n)
⇓ \qquad \Downarrow
φ ( n ) = n × ( 1 − 1 p 1 ) × ( 1 − 1 p 2 ) … ( 1 − 1 p n ) \qquad φ(n)=n\times(1- \frac 1p_1)\times(1- \frac 1p_2)\ldots(1- \frac 1p_n) φ(n)=n×(1p11)×(1p12)(1p1n)

  • 总结:通过欧拉函数最后的通式,我们发现最后的结果只和n和p有关,和p的幂无关,这点很重要,在我们用程序实现时,能够大大的简化我们的逻辑代码。

回到算法中,我们需要计算与n互质的个数,也就是求φ(n),根据欧拉函数,计算过程如下:
φ ( n ) = φ ( 3233 ) = φ ( 61 ) × φ ( 53 ) = 60 × 52 = 3120 φ(n)=φ(3233)=φ(61)×φ(53)=60×52=3120 φ(n)=φ(3233)=φ(61)×φ(53)=60×52=3120

在1和φ(n)之间,选取一个随机质数e

即在1~3120中选取e=17。

求e和φ(n)的模反元素d(裴蜀定理、扩展欧几里得算法)

模反元素也称为模倒数,可以写成 a − 1 ≡ b   ( m o d   n ) a^{−1}≡b \ (mod \ n) a1b (mod n) a b ≡ 1   ( m o d   n ) ab≡1 \ (mod \ n) ab1 (mod n)。(ab和1关于n同模)

如果两个正整数a和n互质,那么一定可以找到整数b,使得a*b与n相除,余数为1,记作: ( a × b ) % n = 1 ⇒ ( a × b ) − 1 n = 1 (a \times b) \% n = 1 \Rightarrow \frac {(a \times b) - 1} n = 1 (a×b)%n=1n(a×b)1=1

例:求3和11的模反元素
( 3 × b ) − 1 11 = 1 = > b = 4 \frac {(3 \times b) - 1} {11} =1 => b = 4 11(3×b)1=1=>b=4

  • 通过上面的运算,我们可以算出一些简单数的模反元素,对于较大的数来说,我们需要引入新的计算工具:裴蜀定理,通过它,我们可以通过一个二元一次方程来得出模反元素。在求模反元素时,给予二个整数a、b,必存在整数x、y使得ax + by = gcd(a,b),而我们真正要获取的是x的值。
  • 定义:如果a与b互质,即GCD(a, b) = 1,二元一次方程 a x + b y = 1 ax + by = 1 ax+by=1有一对正整数解,其中x即为a、b的模反元素。同理,上面的例子我们可以化简成这样:3x + 11y = 1
  • 疑惑:对于二元一次方程,好像不可解(也可以说有无穷多个解),我们之前都是解方程组。即然定理已经解决,两个互素(质)数组成的二元一次方程有一对整数解,那肯定是能解,解法我们需要引入另一个数学工具:扩展欧几里得算法

扩展欧几里得算法这个算法其实就是上面我们求最大公约数时,用到的辗转相除法+它的逆运算,我们看个例子就明白是什么意思了

例1:求 47 x + 30 y = 1 47x + 30y = 1 47x+30y=1的解

解:使用辗转相除法,我们可以得到:
47 = 30 × 1 + 17   30 = 17 × 1 + 13   17 = 13 × 1 + 4     13 = 4 × 3 + 1       4 = 1 × 4 + 0        47 = 30 \times 1 + 17 \ \\ 30 = 17 \times 1 + 13 \ \\ 17 = 13 \times 1 + 4 \ \ \ \\ 13 = 4 \times 3 + 1 \ \ \ \ \ \\ 4 = 1 \times 4 + 0 \ \ \ \ \ \ 47=30×1+17 30=17×1+13 17=13×1+4   13=4×3+1     4=1×4+0      
我们可以得到GCD(47, 30) = 1,对到处第二行,我们移项处理:
1 = 13 − 4 × 3 4 = 17 − 13 × 1 13 = 30 − 17 × 1 17 = 47 − 30 × 1 1 = 13 - 4 \times 3 \\ 4 = 17 - 13 \times 1 \\ 13 = 30 - 17 \times 1 \\ 17 = 47 - 30 \times 1 \\ 1=134×34=1713×113=3017×117=4730×1
我们把第二行代入第一行中:
1 = 13 − ( 17 − 13 × 1 ) ⏞ 4 × 3 ⇓ 1 = 4 × 13 − 3 × 17 ⇓ 1 = 4 × ( 30 − 17 ) ⏞ 13 − 3 × s 17 ⇓ … 1 = ( − 7 ) × 47 + 11 × 30 解得: x = − 7 ( 即为我们要求的模反元素 d ) y = 11 1 = 13 - \overbrace{(17 - 13 \times 1)}^4 \times 3 \\ \Downarrow \\ 1 = 4 \times 13 - 3 \times 17 \\ \Downarrow \\ 1 = 4 \times \overbrace{(30 - 17)}^{13} - 3 \times s17 \\ \Downarrow \\ \ldots \\ 1 = (-7) \times 47 + 11 \times 30 \\ 解得:x=-7(即为我们要求的模反元素d) \quad y = 11 1=13(1713×1) 4×31=4×133×171=4×(3017) 133×s171=(7)×47+11×30解得:x=7(即为我们要求的模反元素d)y=11
回到算法中,我们根据e=17和φ(n)=3120,得到一个二元一次方程: 17 x + 3120 y = 1 17x + 3120y = 1 17x+3120y=1,再根据扩展欧几里得算法,我们可以得到方程的解: x = 2753 即: d = 2753 x = 2753 \quad 即:d = 2753 x=2753即:d=2753

把n和e封装成公钥,n和d封装成私钥
  • 公钥: ( 3233 , 17 ) (3233, 17) (3233,17)
  • 私钥: ( 3233 , 2753 ) (3233, 2753) (3233,2753)
实例

私钥和公钥获取:

  1. 取p=47, q=71;

  2. 则n = p * q = 3337, Φ(n)=(p-1)(q-1)=3220;

  3. 随机选择加密密钥e,e与Φ(n)互素,取e=79;

  4. 79 * d=1(mod n) =》 d = 10 1 9 101^9 1019

  5. 公钥为(3337,79),私钥为(3379,1019)

假设要加密的明文是m=6882326879666683:

  • 首先,根据n的大小将m进行分组,这里我们把明文m分成六个组,即:m1=688, m2=232, m3=687, m4=966, m5=668, m6=003;
  • 接着分别对各个分组进行加密运算,第一个分组加密为c1= 68 8 79 688^{79} 68879(mod 3337) = 1570,类似的,对其余各个分组分别进行加密运算,得到如下密文:c=1570 2756 2091 2276 2423 158;
  • 解密时用私钥1019分别对明文进行解密运算,即:m1= 157 0 1019 1570^{1019} 15701019(mod 3337) = 688,对其余的密文用同样的计算方法就可以把密文恢复出来,即得到密文。
RSA参数的选择

p和q的选择:

  • p和q要足够大

  • p和q应为强素数。如p满足以下三个条件,即为强素数:

    (1)P-1有大素数因子r

    (2)P+1有大素数因子s

    (3)R-1有大素数因子t

  • p和q的差不能太小

  • p-1和q-1的最大公因数应很小

公钥e的选择:e不能太小;最好选择e为modΦ(n)的阶数,意思就是要使i的值尽量大才能使得ei≡ (mod Φ(n))成立。i等于(p-1)(q-1)/2是最好的。一般建议取e= 2 16 2^{16} 216+1=65537

代码

(1)质数判断

import Gcd from './Gcd'
/**
 * 质数类
 */
class Prime {
    private static pNumArr: Array<number> = []
    /**
     * 判断一个数是否为质数
     * @param num 转入值
     */
    public static isPrimeNum(num: number): boolean {
        // 1和2都是质数
        if (num < 3) {
            return true
        }
        // i取开方,效率要比/2高出许多
        for (let i = 2; i <= Math.sqrt(num); i++) {
            if (num % i === 0) {
                return false
            }
        }
        return true
    }
    /**
     * 1. 任意两个质数构成互质关系,比如13和61。
      2. 一个数是质数,另一个数只要不是前者的倍数,两者就构成互质关系,比如3和10。
      3. 如果两个数之中,较大的那个数是质数,则两者构成互质关系,比如97和57。
      4. 1和任意一个自然数是都是互质关系,比如1和99。
      5. p是大于1的整数,则p和p-1构成互质关系,比如57和56。
      6. p是大于1的奇数,则p和p-2构成互质关系,比如17和15。
     */
    public static coprime(n1: number, n2: number): boolean {
        // 保证n1比n2要大
        if (n2 > n1) {
            let tmp = n1
            n1 = n2
            n2 = tmp
        }
        // 两个数中, 有一个是1, 则两数互质
        if (n1 === 1 || n2 === 1) {
            return true
        }
        // 如果两数相邻, 则两数互质
        if (n1 - n2 === 1) {
            return true
        }
        // 如果大数为奇数, 则n1-n2 = 2, 则两数互质
        if (n1 % 2 === 1 && n1 - n2 === 2) {
            return true
        }
        // 如果较大的数为质数, 则两数互质
        if (this.isPrimeNum(n1)) {
            return true
        }
        // 有一个是质数, 别一个不为此数的倍数, 则两数互质
        if ((this.isPrimeNum(n1) || this.isPrimeNum(n2)) && n1 % n2 !== 0) {
            return true
        }
        // 如果两个数都为质数, 则两个数互质
        if (this.isPrimeNum(n1) && this.isPrimeNum(n2)) {
            return true
        }
        // 如果两个数的最大公约数为1, 则两个数互质
        if (Gcd.gcd(n1, n2) === 1) {
            return true
        }
        return false
    }
    /**
     * 获取该数下所有的质数
     * @param num 转入的数
     */
    public static getAllPrimeNum(num: number) {
        let arr = []
        for (let i = 1; i <= num; i++) {
            if (this.isPrimeNum(i)) {
                arr.push(i)
            }
        }
        return arr
    }

    /**
     * 把一个正整数分解为两个质数的乘积
     * @param num
     */
    public static break(num: number) {
        this.getBreakArr(num)
        return this.pNumArr
    }

    /**
     * 把一个正整数分解为两个质数的乘积(中间步骤)
     * @param num
     */
    private static getBreakArr(num: number) {
        // 获取该数/2的所有质数
        let arr = this.getAllPrimeNum(Math.floor(num / 2))
        // 能被这个数整除的最大质数
        let maxNum = 1
        for (let i = 0; i < arr.length; i++) {
            if (num % arr[i] === 0) {
                maxNum = arr[i]
            }
        }
        // 除数
        let divNum = num / maxNum
        if (maxNum !== 1) {
            this.pNumArr.push(maxNum)
            return this.break(divNum)
        } else {
            this.pNumArr.push(divNum)
            return maxNum
        }
    }
}

export default Prime

(2)欧拉函数计算

import Prime from './Prime'
import Util from './Util'
/**
 * 欧拉函数
 */
class Euler {
    /**
     * 根据欧拉函数取与此数互质的个数
     * @param num 参数
     */
    public static getEulerNum(num: number) {
        Prime.break(num)
        let arr = Util.uniqueArr(Prime.break(num))
        let result = num
        for (let i = 0; i < arr.length; i++) {
            result *= 1 - 1 / arr[i]
        }
        return Math.floor(result)
    }
}

export default Euler

(3)最大公约数计算-欧几里得算法-辗转相除法

/**
 * 最大公约数
 */
class Gcd {
    /**
     * 计算2个数的最大公约数
     * @param n1 数1
     * @param n2 数2
     */
    public static gcd(n1: number, n2: number): number {
        let s = Math.floor(n1 / n2)
        let y = n1 % n2
        // console.log(n1 + ' = ' + n2 + '*' + s + ' + ' + y)
        if (y === 0) {
            return n2
        } else {
            return this.gcd(n2, y)
        }
    }
    /**
     * 扩展欧几里德算法 - 求方程的解 (详细注释版)
     * 我们要求:47x + 30y = 1的解,下面为辗转相除法的步骤:
     * 47 = 30*1 + 17
     * 30 = 17*1 + 13
     * 17 = 13*1 + 4
     * 13 = 4*3 + 1
     *
     *
     * @param num1 数1
     * @param num2 数2
     */
    public static gcdEx(n1: number, n2: number): Array<number> {
        // 两数相除的商
        let q = Math.floor(n1 / n2)
        // 两数相除的余数
        let r = n1 % n2
        // 当到 13 = 4*3 + 1 即4 % 1 = 0时 返回
        // 返回值为:1 | -4 即:x=1 y=-4
        if (n2 % r === 0) {
            // 转化为:1 = 13 + 4*(-3)
            // 所以返回:x=1 y=q*(-1)=-3
            return [1, q * -1]
        } else {
            let ret = this.gcdEx(n2, r)
            // x和y为上一步返回的值
            let x = ret[0]
            let y = ret[1]
            // x1和y1为当前步骤的值
            let x1 = 1
            let y1 = -q
            // console.log('----', x, y, x1, y1)
            // x2和y2为当前步骤计算得到的值
            // 1 = 13 + 4*(-3)
            // 4 = 17 + 13*(-1)
            // 代入得:1 = 13 + (17 + 13*(-1)) * (-3)
            // 计算得:1 = 17*(-3) + 13*4 ==> x=-3 | y=4
            let x2 = y * x1
            let y2 = y * y1 + x
            ret = [x2, y2]
            return ret
        }
    }
}
export default Gcd

(4)裴蜀定理的求解-扩展欧几里得算法

/**
 * 最大公约数
 */
class Gcd {
    /**
     * 计算2个数的最大公约数
     * @param n1 数1
     * @param n2 数2
     */
    public static gcd(n1: number, n2: number): number {
        let s = Math.floor(n1 / n2)
        let y = n1 % n2
        // console.log(n1 + ' = ' + n2 + '*' + s + ' + ' + y)
        if (y === 0) {
            return n2
        } else {
            return this.gcd(n2, y)
        }
    }
    /**
     * 扩展欧几里德算法 - 求方程的解 (详细注释版)
     * 我们要求:47x + 30y = 1的解,下面为辗转相除法的步骤:
     * 47 = 30*1 + 17
     * 30 = 17*1 + 13
     * 17 = 13*1 + 4
     * 13 = 4*3 + 1
     *
     *
     * @param num1 数1
     * @param num2 数2
     */
    public static gcdEx(n1: number, n2: number): Array<number> {
        // 两数相除的商
        let q = Math.floor(n1 / n2)
        // 两数相除的余数
        let r = n1 % n2
        // 当到 13 = 4*3 + 1 即4 % 1 = 0时 返回
        // 返回值为:1 | -4 即:x=1 y=-4
        if (n2 % r === 0) {
            // 转化为:1 = 13 + 4*(-3)
            // 所以返回:x=1 y=q*(-1)=-3
            return [1, q * -1]
        } else {
            let ret = this.gcdEx(n2, r)
            // x和y为上一步返回的值
            let x = ret[0]
            let y = ret[1]
            // x1和y1为当前步骤的值
            let x1 = 1
            let y1 = -q
            // console.log('----', x, y, x1, y1)
            // x2和y2为当前步骤计算得到的值
            // 1 = 13 + 4*(-3)
            // 4 = 17 + 13*(-1)
            // 代入得:1 = 13 + (17 + 13*(-1)) * (-3)
            // 计算得:1 = 17*(-3) + 13*4 ==> x=-3 | y=4
            let x2 = y * x1
            let y2 = y * y1 + x
            ret = [x2, y2]
            return ret
        }
    }
}
export default Gcd
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值