最近在使用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 φ(n),这样就省事多了。

2.Cipher类

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

3.代码

package net.sms.datatool.algorithm;

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 RSACrtUtils { 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 void prikey_crt_test(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 = e.modInverse(h); BigInteger qinV; qinV = q.modInverse(p); String strQinV = qinV.toString(16);//QinV的十六进制形式 /**
* 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 ;
} /**
* 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);
} /**
* 产生RSA密钥对
*
* @param pubkey 公钥
* @param prikey 私钥
* @throws Exception
*/
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);
//
} }

  

参考文章: http://blog.csdn.net/youngbug/article/details/52709507?locationNum=8

JAVA中使用P和Q分量计算N和D进行RSA运算的更多相关文章

  1. Java中使用LocalDate根据日期来计算年龄

    Java中和日期直接相关的类有很多,平时最常用到的就是java.util package下面的Date和Calendar,需要用到格式的时候还会用到java.text.SimpleDateFormat ...

  2. Java中String的哈希值计算

    下面都是从String类的源码中粘贴出来的 private int hash; // Default to 0 public int hashCode() { int h = hash; if (h ...

  3. java 中数据的强制转换 和计算的补码运算

    原码 反码 补码的定义与运算 1原码: 原码是将十进制或者其他进制的数转换为二进制表示(且要根据数据的类型转换) 如:130 (默认是Int类型,则是4个字节) 原码是:00000000 000000 ...

  4. Java基础扫盲系列(二)—— Java中BigDecimal和浮点类型

    一直以来我几乎未使用过BigDecimal类型,只有在DB中涉及到金额字段时听说要用Decimal类型,但是今天再项目代码中看到使用BigDecimal表示贷款金额. 本篇文章不是介绍BigDecim ...

  5. Tensorflow 保存模型 & 在java中调用

    本节涉及: 保存TensorFlow 的模型供其他语言使用 java中调用模型并进行预测计算 一.保存TensorFlow 的模型供其他语言使用 如果用户选择“y” ,则执行下面的步骤: 判断程序执行 ...

  6. Java中 a+=b 和 a=a+b 有什么区别?

    今天舍友突然问我"在java中 a+=b 和a=a+b 有什么区别",说这是一道面试题.当时就不假思索的回答:"一样啊",然后他说有位面试者也回答说一样,所以被 ...

  7. Java中int和short的转化

    例子[1]: 第一种情况: short a = 1; a = a + 1; // 这一步会报错 System.out.print(a); 编译器会报错,原因如下: 第二种情况: short a = 1 ...

  8. Java中short和int的转换

    例子[1]: 第一种情况: short a = 1; a = a + 1; // 这一步会报错 System.out.print(a); 编译器会报错,原因如下: 第二种情况: short a = 1 ...

  9. Java中Double类型计算问题

    public class Test{    public static void main(String args[]){        System.out.println(0.05+0.01);  ...

随机推荐

  1. yum安装 lnmp (linux+nginx+php7.1+mysql5.7)

    1.第一步先更新yum update 2.yum安装nginx安装nginx最新源:yum localinstall http://nginx.org/packages/centos/7/noarch ...

  2. 流畅的python第一章python数据模型学习记录

    python中有些特殊的方法,以双上下划线开头,并以双下划线结束的方法.如__getitem__,这些方法是特殊的方法,供python解释权内部使用,一般来说不需要调用 还有一种是以双下划线开头的,如 ...

  3. Fragment与Activity传递数据

    MainActivity如下: package cc.testsimplefragment0; import android.os.Bundle; import android.app.Activit ...

  4. jQuery选择器的灵活用法

    // 摘自: http://hi.baidu.com/274084093/item/47a4ce696e89e534ad3e836b jQuery中选择器很强大,可以根据元素名称.ID.class等多 ...

  5. OpenCV 4.1 编译和配置

    OpenCV 4.0 版本,历时3年半,终于在2018年圣诞节前发布了,该版本增加的新功能如下: 1) 更新代码支持 c++11 特性,需要兼容 c++11 语法的编译器 2)增加 dnn 中的模块功 ...

  6. Java基础大家必看啊

    写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java语言代码把思路体现出来.   学习 ...

  7. Win7盗版提示,屏幕右下角出现 Windows内部版本7601此Windows副本不是正版怎么办

    Windows7 屏幕右下角出现 Windows内部版本7601此Windows副本不是正版 有很多人反应windows7会出现提示"Win7内部版本7600此Windows副本不是正版&q ...

  8. springMVC 头像裁剪上传并等比压

    第一次写头像裁剪上传,原本想着直接本地预览裁剪再上传,可是时间有限,jquery.jcrop貌似并没有对 假设是ie下图片预览效果是滤镜做的  做出对应处理,也没有时间去改;仅仅好将就一下先把图片上传 ...

  9. MPlayer源代码分析

    http://blog.csdn.net/leixiaohua1020/article/details/11885509 一.Mplayer支持的格式 MPlayer是一个LINUX下的视频播放器,它 ...

  10. win7之64位下安装oracle11g遇到问题和不能删除干净的问题

    今天在win7下装了oracle11g 删了又卸 来来回回重启了4.5次,结合网上是解释归纳下几点: 一.win64_11gR2_database_1of2.zip和win64_11gR2_datab ...