[Cqoi2016] 密钥破解 Java 题解

密钥破解

题目描述

一种非对称加密算法的密钥生成过程如下:

  1. 任选两个不同的质数 p ,q
  2. 计算 N=pq , r=(p-1)(q-1)
  3. 选取小于r ,且与 r 互质的整数 e
  4. 计算整数 d ,使得 ed≡1 mod r
  5. 二元组 (N,e) 称为公钥,二元组 (N,d) 称为私钥

当需要加密消息 n 时(假设 n 是一个小于 N 整数,因为任何格式的消息都可转为整数表示),使用公钥 (N,e),按照

n^e≡c mod N

运算,可得到密文 c 。

对密文 c 解密时,用私钥 (N,d) ,按照

c^d≡n mod N

运算,可得到原文 n 。算法正确性证明省略。

由于用公钥加密的密文仅能用对应的私钥解密,而不能用公钥解密,因此称为非对称加密算法。通常情况下,公钥由消息的接收方公开,而私钥由消息的接收方自己持有。这样任何发送消息的人都可以用公钥对消息加密,而只有消息的接收方自己能够解密消息。

现在,你的任务是寻找一种可行的方法来破解这种加密算法,即根据公钥破解出私钥,并据此解密密文。

输入格式

输入文件内容只有一行,为空格分隔的j个正整数e,N,c。N<=2^62,c

输出格式

输出文件内容只有一行,为空格分隔的k个整数d,n。

样例输入

3 187 45

样例输出

107 12

提示

样例中 p = 11, q = 17

题解

这是一道RSA密钥破解题,我们需要通过公钥对( N N N, e e e)破解出私钥对( N N N, d d d)从而解出密文,计算的过程如下

  • 分解 N N N得到 p p p q q q,满足 p ∗ q = N p * q = N pq=N
  • 计算 r = ( p − 1 ) ∗ ( q − 1 ) r = (p - 1) * (q - 1) r=(p1)(q1)
  • 计算 d d d,满足 e d ≡ 1 m o d    r ed \equiv 1 \mod r ed1modr
  • 计算 n = c d m o d    N n = c^d \mod N n=cdmodN

其中,每一步分别需要使用到如下算法来加速计算的过程

  • Pollard’s rho 大数分解算法
  • Java自带的大数快速乘法
  • 扩展欧几里得算法(exgcd)
  • Java自带的大数快速幂

代码

import java.io.*;
import java.math.*;
import java.security.*;

public class Main {
   public static void main(String[] args) throws Exception {
       //读入e N c
       BigInteger e = rb();
       BigInteger N = rb();
       BigInteger c = rb();

       //用Pollard_rho算法分解N得到p q
       BigInteger p = rho_sec(N);
       BigInteger q = N.divide(p);

       //计算r d n
       BigInteger r = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));
       exgcd(e, r);
       BigInteger d = x.mod(r).add(r).mod(r);
       BigInteger n = c.modPow(d, N);

       //输出d n
       System.out.println(d + " " + n);
   }

   //exgcd
   private static BigInteger x;
   private static BigInteger y;

   public static BigInteger exgcd(BigInteger a, BigInteger b) {
       if (b.compareTo(BigInteger.ZERO) == 0) {
           x = BigInteger.ONE;
           y = BigInteger.ZERO;
           return a;
       } else {
           BigInteger d = exgcd(b, a.mod(b));
           BigInteger temp = x;
           x = y;
           y = temp.subtract(a.divide(b).multiply(y));
           return d;
       }
   }

   //Pollard_rho
   private final static BigInteger TWO = new BigInteger("2");
   private final static SecureRandom random = new SecureRandom();

   public static BigInteger rho(BigInteger N) {
       BigInteger divisor;
       BigInteger c = new BigInteger(N.bitLength(), random);
       BigInteger x = new BigInteger(N.bitLength(), random);
       BigInteger xx = x;

       if (N.mod(TWO).compareTo(BigInteger.ZERO) == 0) return TWO;

       do {
           x = x.multiply(x).mod(N).add(c).mod(N);
           xx = xx.multiply(xx).mod(N).add(c).mod(N);
           xx = xx.multiply(xx).mod(N).add(c).mod(N);
           divisor = x.subtract(xx).gcd(N);
       } while ((divisor.compareTo(BigInteger.ONE)) == 0);

       return divisor;
   }

   public static BigInteger rho_sec(BigInteger N) {
       BigInteger divisor = rho(N);
       while (!divisor.isProbablePrime(20)) {
           divisor = rho(N);
       }
       return divisor;
   }

   //基础控制台读取操作
   static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
   static String[] buffer = new String[0];
   static int pos = 0;

   static String rn() throws Exception {
       if (buffer.length <= pos) {
           buffer = br.readLine().split(" ");
           pos = 0;
       }
       return buffer[pos++];
   }

   static BigInteger rb() throws Exception {
       return new BigInteger(rn());
   }
}

参考

POJ 1061 青蛙的约会 扩展欧几里德 Java
https://blog.csdn.net/tinydolphin/article/details/76407351
pollard_rho大数分解Java版
https://blog.csdn.net/ACdreamers/article/details/9671633

你可能感兴趣的:(算法,OI,CUPOJ)