最近在应用Java中须要应用PQ模式的私钥进行RSA加解密运算,原本认为Java中应该很多相似的例子,发现所有的例子都是从ND模式的私钥,居然没有人用重量P和Q计算N和D进行运算。对Java应用RSA运算不太熟,只能本人一点一点搞了。身边的Java 的仙们,如同身边都没人中国残余定理,所以也不会遇到P和Q?不论他们了,动工了。

1.BigInteger类

Java中有现成的大数运算的BigInteger类,间接应用这个类进行运算即可,总结一下应用中遇到的坑。Java的大数多1bit示意符号,所以如果1024byte的N在BigInteger中是1025bit,最高位多了1bit符号位,所以如果用BigInteger中的toByteArray()能够取得大数的二进制补码,如果须要导出BigInteger中的数据,须要疏忽符号位,从第二字节开始拷贝,如果从第一字节就拷贝,那么会失落最初一字节,把符号位存下来。
BigInteger类提供modInverse办法,能够间接求$d=e^{-1} = mod \\phi(n)$,这样就省事多了。

2.Cipher类

javax.crypto.Cipher类有个getInstance()办法,参数是“算法/模式/填充形式”,因为我只有一块定长128字节数据进行RSA运算,本人进行填充和去填充,依照sun的文档中的阐明,填写"RSA/None/NoPadding",然而编译的时候报错,提醒不反对,网上搜了搜,都说默认的Crypt Provider不反对NoPadding,必须是PKCS#1的填充,感觉很不靠谱啊,起初发现是在Jdk1.7还是哪个版本之后,不反对None的模式,用ECB模式就行了,之前的版本是不是反对None也没去验证。

3.代码

RSACrtUtil.java

package com.zhantianzuo.alg;import java.math.BigInteger;import java.security.Key;import java.security.KeyFactory;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.NoSuchAlgorithmException;import java.security.Security;import java.security.interfaces.RSAPrivateCrtKey;import java.security.interfaces.RSAPublicKey;import java.security.spec.RSAPrivateKeySpec;import java.security.spec.RSAPublicKeySpec;import javax.crypto.Cipher;/** *  * RSACrtUtil    RSA加解密  * 应用中国残余定理类型的密钥 * 私钥是P和Q,公钥是N,E固定0x10001 * * @Date 2016.9.6 * * @version v1.0 * * @author 赵洋 cnrgc@163.com */public class RSACrtUtil {        public static final int RSA_MODULUS_LEN = 128;    public static final int RSA_P_LEN = RSA_MODULUS_LEN/2;    public static final int RSA_Q_LEN = RSA_MODULUS_LEN/2;    public static final int publicExponent = 65537;    public static final String KEY_ALGORITHM_MODE_PADDING = "RSA/ECB/NoPadding"; //不填充    public static final String KEY_ALGORITHM = "RSA"; //不填充        /**     * prikey_crt_decrypt 应用PQ的RSA私钥解密     * 私钥格局前半部分是P,后半局部是Q     *      * */    public static byte[] prikey_crt_decrypt(byte[] data, byte[] prikey) throws Exception{                        byte[] buf_p = new byte[RSA_P_LEN];        byte[] buf_q = new byte[RSA_Q_LEN];        //buf_p[0] = (byte)0x00;        //buf_q[0] = (byte)0x00;        System.arraycopy(prikey, 0, buf_p, 0, RSA_P_LEN);        System.arraycopy(prikey, RSA_P_LEN, buf_q, 0, RSA_Q_LEN);        //        /**         *  1.p,q计算n         * */        BigInteger p = new BigInteger(1, buf_p);        BigInteger q = new BigInteger(1, buf_q);        BigInteger n = p.multiply(q); //n = p * q        /**         *     2. 计算d = (p-1) * (q-1) mod e         * */        BigInteger p1 = p.subtract(BigInteger.valueOf(1));        BigInteger q1 = q.subtract(BigInteger.valueOf(1));        BigInteger h = p1.multiply(q1);// h = (p-1) * (q-1)        BigInteger e = BigInteger.valueOf(publicExponent);        //BigInteger d = h.mod(e);        BigInteger d = e.modInverse(h);        /**         *     3. 创立 RSA私钥         * */        RSAPrivateKeySpec keyspec = new RSAPrivateKeySpec(n, d);        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);           Key privateKey = keyFactory.generatePrivate(keyspec);        /**         *     4. 数据解密          * */        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_MODE_PADDING);           cipher.init(Cipher.DECRYPT_MODE, privateKey);           /**         *     5. 返回后果         * */        return cipher.doFinal(data);      }    /**     * pubkey_encrypt 公钥加密     * 密钥是N     * */    public static byte[] pubkey_encrypt(byte[] data, byte[] pubkey) throws Exception{                /**         *  1.初始化大数模n和公钥指数e         * */        byte[] pubkey_buf = new byte[RSA_MODULUS_LEN+1];//多一字节符号位        pubkey_buf[0] = (byte)0x00;        System.arraycopy(pubkey, 0, pubkey_buf, 1, RSA_MODULUS_LEN);        //        BigInteger e = BigInteger.valueOf(publicExponent);        BigInteger n = new BigInteger(pubkey_buf);        /**         *  2.创立RSA公钥         * */        //        RSAPublicKeySpec keyspec = new RSAPublicKeySpec(n, e);        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);           Key publicKey = keyFactory.generatePublic(keyspec);        /**         *  3.数据加密         * */        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_MODE_PADDING);        cipher.init(Cipher.ENCRYPT_MODE, publicKey);           /**         *     5. 返回后果         * */        return cipher.doFinal(data);    }        public static void generateKeyPair(byte[] pubkey, byte[] prikey) throws Exception{                KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);        keyPairGenerator.initialize(RSA_MODULUS_LEN*8);                KeyPair keyPair = keyPairGenerator.generateKeyPair();        RSAPublicKey publicKey = (RSAPublicKey)keyPair.getPublic();        RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey)keyPair.getPrivate();        //        BigInteger n = publicKey.getModulus();        BigInteger p = privateKey.getPrimeP();        BigInteger q = privateKey.getPrimeQ();        /**         *  BigInteger 里有一个bit的符号位,所以间接用toByteArray会蕴含符号位,         *  在c的代码里没符号位,所以1024bit的n,java里BigInteger是1025bit长         *  间接拷贝128byte进去,负数第一个字节是是0,前面会丢掉最初一字节         * */        System.arraycopy(n.toByteArray(), 1, pubkey, 0, 128);        System.arraycopy(p.toByteArray(), 1, prikey, 0, 64);        System.arraycopy(q.toByteArray(), 1, prikey, 64, 64);        //    }}

Test.java

package com.zhantianzuo.alg;import java.math.BigInteger;import java.security.Key;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.NoSuchAlgorithmException;import java.security.interfaces.RSAPrivateCrtKey;import java.security.interfaces.RSAPublicKey;public class Test {    private static final String ALGORITHM = "RSA";    private static final int key_len = 128;        public static void main(String[] args) {        //        byte[] pubkey = new byte[128];        byte[] prikey = new byte[128];        try {            RSACrtUtil.generateKeyPair(pubkey, prikey);        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        //        int i;        byte[] plaintext = null;        byte[] ciphertext = null;        byte[] data = new byte[key_len];        for(i=0; i<key_len; i++){                        data[i] = (byte)i;        }        //        try {            ciphertext = RSACrtUtil.pubkey_encrypt(data, pubkey);        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        //                try {            plaintext = RSACrtUtil.prikey_crt_decrypt(ciphertext, prikey);        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }            }}