Loading

RSA算法学习

package com.test.rsa;

/*
 * 为了选择公钥和私钥,Bob必须执行如下步骤:
 * 1)选择两个大素数p和q.那么p和q应该多大呢?该值越大,RSA越难于破解,但是执行加密和解密所用的时间也越长。RSA实验室推
 * 荐,公司使用时,p和q的乘积为1024比特的数量级,对于"价值不太高的信息",p和q的乘积应为768比特的数量级[RSA Key 2007]
 * (这导致人们想知道为什么在公司的使用被认为比在其他场合下的使用重要得多!).对于选择大素数的方法的讨论参见[Caldwell 2007]
 * 2)计算n=pq和z=(p-1)(q-1)
 * 3)选择小于n的一个数e,且使e和z没有(非1的)公因数(这时称e与z互素).使用字母e表示这个数是因为这个值将用于加密.
 * 4)找到一个数d,使得ed-1可以被z整除(就是说,没有余数).使用字母d表示这个数是因为这个值将被用于解密.换句话说,给定e,
 * 然后选择d使得ed被z除的整数余数为1.(当整数x被整数n除时,整数余数表示为x mod n.)
 * 5)Bob对外公布的公钥就是二元组(n,e);其私钥就是二元组(n,d). 
 * 
 * 
 * 假设Bob想给Alice送一个消息m,他知道Alice产生的n和e。他使用起先与Alice约好的格式将m转换为一个小于n的整数num,
 * 比如他可以将每一个字转换为这个字的Unicode码,然后将这些数字连在一起组成一个数字。假如他的信息非常长的话,
 * 他可以将这个信息分为几段,然后将每一段转换为num。用下面这个公式他可以将num加密为c:
 *                         num^e ≡ c (mod n)
 * 计算c并不复杂。Bob算出c后就可以将它传递给Alice。
 * 
*/

/**
 * @author shalltear@shalltear.com
 * RSA 简单实现学习
 */
public class Main {
    
    public static void main(String[] args) {
        int p = 2;
        int q = 11;
        int n = p*q;
        int z = (p-1)*(q-1);
        int e = 3;
        
        Main main =new Main();
        int d = main.getd(e, z);
        
        System.out.println("n: "+n);
        System.out.println("*****");
        int enc = main.encrypt(20, e, n);
        System.out.println("*****");
        main.decrypt(enc, d, n);
        
    }
    /**
    计算e对于z的模反元素d,所谓"模反元素"就是指有一个整数d,可以使得 ed 被φ(n)除的余数为1。
    ed ≡ 1 (mod φ(n)) 这个式子等价于 ed - 1 = kφ(n)
    于是,找到模反元素d,实质上就是对下面这个二元一次方程求解。
    ed + zk = 1
    已知 e=5, φ(n)=96,
    5d + 96k = 1
    这个方程可以用"扩展欧几里得算法"求解,此处省略具体过程。
    */
    public int getd(int e,int z) {
        //实际上即使需要找到一个整数d满足  ed-1=kz -> d= (kz+1)/e,其中k当然也是整数
        /*
        int k=1;
        Object object = (k*z+1)/e;
        while(!(object instanceof Integer)) {
            k++;
        }
        System.out.println("d: "+object.toString());
        return Integer.parseInt(object.toString());
        */
        int k=1;
        while(true) {
            if((k*z+1)%e==0) {
                System.out.print("k: "+k+"    ");
                System.out.print("z: "+z+"    ");
                System.out.print("e: "+e+"    ");
                System.out.println("d: "+(k*z+1)/e);
                return (k*z+1)/e;
            }
            k++;
        }
    }
    
    /**
     * 加密函数 输入明文num,密钥(e,n),输出密文c,c满足 num^e ≡ c (mod n)
     * @param msg 待加密信息
     * @param e 密钥
     * @param n 密钥
     * @return 密文
     */
    public int encrypt(int num,int e,int n) {
        System.out.println("待加密数字: "+num);
        System.out.println("加密后数字: "+(int)(Math.pow(num, e)%n));
        return (int)(Math.pow(num, e)%n);
    }
    /**
     * 解密函数 输入密文num,密钥(d,n),输出明文msg,msg满足 num^d ≡ msg (mod n)
     * @param num 密文
     * @param d 密钥
     * @param n 密钥
     * @return 明文
     */
    public int decrypt(int num,int d,int n) {
        System.out.println("待解密数字: "+num);
        System.out.println("解密后数字: "+(int)(Math.pow(num, d)%n));
        return (int)(Math.pow(num, d)%n);
    }
}

运行结果:
k: 2    z: 10    e: 3    d: 7
n: 22
*****
待加密数字: 20
加密后数字: 14
*****
待解密数字: 14
解密后数字: 20

2016.04.03
– 此前一直得到错误的运行结果,后来才知道被加密的整数是必须要小于n的。至于为什么,等明白了再回来补。
– 整理:
密文 c = m^e mod n (1)
明文 m = c^d mod n (2)
(2)式是可以根据(1)式进行证明的。

posted @ 2016-04-13 15:31  注销111  阅读(174)  评论(0编辑  收藏  举报