JAVA中使用P和Q分量計(jì)算N和D進(jìn)行RSA運(yùn)算

最近在使用Java中需要使用PQ形式的私鑰進(jìn)行RSA加解密運(yùn)算,本來(lái)以為Java中應(yīng)該很多類(lèi)似的例子,發(fā)現(xiàn)所有的例子都是從ND形式的私鑰,竟然沒(méi)有人用分量P和Q計(jì)算N和D進(jìn)行運(yùn)算。對(duì)Java使用RSA運(yùn)算不太熟,只能自己一點(diǎn)一點(diǎn)搞了。身邊的Java 的仙們,好像身邊都沒(méi)人中國(guó)剩余定理,所以也不會(huì)遇到P和Q?不管他們了,開(kāi)工了。

1.BigInteger類(lèi)

Java中有現(xiàn)成的大數(shù)運(yùn)算的BigInteger類(lèi),直接使用這個(gè)類(lèi)進(jìn)行運(yùn)算即可,總結(jié)一下使用中遇到的坑。Java的大數(shù)多1bit表示符號(hào),所以如果1024byte的N在BigInteger中是1025bit,最高位多了1bit符號(hào)位,所以如果用BigInteger中的toByteArray()可以獲得大數(shù)的二進(jìn)制補(bǔ)碼,如果需要導(dǎo)出BigInteger中的數(shù)據(jù),需要忽略符號(hào)位,從第二字節(jié)開(kāi)始拷貝,如果從第一字節(jié)就拷貝,那么會(huì)丟失最后一字節(jié),把符號(hào)位存下來(lái)。
BigInteger類(lèi)提供modInverse方法,可以直接求d=e^{-1} = mod \\phi(n),這樣就省事多了。

2.Cipher類(lèi)

javax.crypto.Cipher類(lèi)有個(gè)getInstance()方法,參數(shù)是“算法/模式/填充方式”,因?yàn)槲抑挥幸粔K定長(zhǎng)128字節(jié)數(shù)據(jù)進(jìn)行RSA運(yùn)算,自己進(jìn)行填充和去填充,按照sun的文檔中的說(shuō)明,填寫(xiě)"RSA/None/NoPadding",但是編譯的時(shí)候報(bào)錯(cuò),提示不支持,網(wǎng)上搜了搜,都說(shuō)默認(rèn)的Crypt Provider不支持NoPadding,必須是PKCS#1的填充,感覺(jué)很不靠譜啊,后來(lái)發(fā)現(xiàn)是在Jdk1.7還是哪個(gè)版本之后,不支持None的模式,用ECB模式就行了,之前的版本是不是支持None也沒(méi)去驗(yàn)證。

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加解密 
 * 使用中國(guó)剩余定理類(lèi)型的密鑰
 * 私鑰是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計(jì)算n
         * */
        BigInteger p = new BigInteger(1, buf_p);
        BigInteger q = new BigInteger(1, buf_q);
        BigInteger n = p.multiply(q); //n = p * q
        /**
         *  2. 計(jì)算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. 創(chuàng)建 RSA私鑰
         * */
        RSAPrivateKeySpec keyspec = new RSAPrivateKeySpec(n, d);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);   
        Key privateKey = keyFactory.generatePrivate(keyspec);
        /**
         *  4. 數(shù)據(jù)解密 
         * */
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_MODE_PADDING);   
        cipher.init(Cipher.DECRYPT_MODE, privateKey);   
        /**
         *  5. 返回結(jié)果
         * */
        return cipher.doFinal(data);  
    }
    /**
     * pubkey_encrypt 公鑰加密
     * 密鑰是N
     * */
    public static byte[] pubkey_encrypt(byte[] data, byte[] pubkey) throws Exception{
        
        /**
         *  1.初始化大數(shù)模n和公鑰指數(shù)e
         * */
        byte[] pubkey_buf = new byte[RSA_MODULUS_LEN+1];//多一字節(jié)符號(hào)位
        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.創(chuàng)建RSA公鑰
         * */
        //
        RSAPublicKeySpec keyspec = new RSAPublicKeySpec(n, e);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);   
        Key publicKey = keyFactory.generatePublic(keyspec);
        /**
         *  3.數(shù)據(jù)加密
         * */
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_MODE_PADDING);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);   
        /**
         *  5. 返回結(jié)果
         * */
        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 里有一個(gè)bit的符號(hào)位,所以直接用toByteArray會(huì)包含符號(hào)位,
         *  在c的代碼里沒(méi)符號(hào)位,所以1024bit的n,java里BigInteger是1025bit長(zhǎng)
         *  直接拷貝128byte出來(lái),正數(shù)第一個(gè)字節(jié)是是0,后面會(huì)丟掉最后一字節(jié)
         * */
        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();
        }
        
    }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容