RSA PKCS#1在java中怎么实现?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RSA PKCS#1在java中怎么实现?相关的知识,希望对你有一定的参考价值。

只要写个demo就可以了 分至少给200!
项目文档上写的“RSA:使用RSA进行安全验证,其中RSA的填充方式为PKCS#1,在合作伙伴平台中RSA加密方式是用私钥加密用公钥解密,双方互换公钥。“ 怎么实现这个私钥加密呢
1楼的却认真,但这些我都已经知道的了 继续提高悬赏
2楼你的是RSA算法不是我要的PKCS#1 继续提高悬赏

楼主看看下面的代码是不是你所需要的,这是我原来用的时候收集的
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.io.*;
import java.math.BigInteger;

/**
* RSA 工具类。提供加密,解密,生成密钥对等方法。
* 需要到http://www.bouncycastle.org下载bcprov-jdk14-123.jar。
* RSA加密原理概述
* RSA的安全性依赖于大数的分解,公钥和私钥都是两个大素数(大于100的十进制位)的函数。
* 据猜测,从一个密钥和密文推断出明文的难度等同于分解两个大素数的积
* ===================================================================
* (该算法的安全性未得到理论的证明)
* ===================================================================
* 密钥的产生:
* 1.选择两个大素数 p,q ,计算 n=p*q;
* 2.随机选择加密密钥 e ,要求 e 和 (p-1)*(q-1)互质
* 3.利用 Euclid 算法计算解密密钥 d , 使其满足 e*d = 1(mod(p-1)*(q-1)) (其中 n,d 也要互质)
* 4:至此得出公钥为 (n,e) 私钥为 (n,d)
* ===================================================================
* 加解密方法:
* 1.首先将要加密的信息 m(二进制表示) 分成等长的数据块 m1,m2,...,mi 块长 s(尽可能大) ,其中 2^s<n
* 2:对应的密文是: ci = mi^e(mod n)
* 3:解密时作如下计算: mi = ci^d(mod n)
* ===================================================================
* RSA速度
* 由于进行的都是大数计算,使得RSA最快的情况也比DES慢上100倍,无论是软件还是硬件实现。
* 速度一直是RSA的缺陷。一般来说只用于少量数据加密。
* 文件名:RSAUtil.java<br>
* @author 赵峰<br>
* 版本:1.0.1<br>
* 描述:本算法摘自网络,是对RSA算法的实现<br>
* 创建时间:2009-7-10 下午09:58:16<br>
* 文件描述:首先生成两个大素数,然后根据Euclid算法生成解密密钥<br>
*/
public class RSAUtil

//密钥对
private KeyPair keyPair = null;

/**
* 初始化密钥对
*/
public RSAUtil()
try
this.keyPair = this.generateKeyPair();
catch (Exception e)
e.printStackTrace();



/**
* 生成密钥对
* @return KeyPair
* @throws Exception
*/
private KeyPair generateKeyPair() throws Exception
try
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA",new org.bouncycastle.jce.provider.BouncyCastleProvider());
//这个值关系到块加密的大小,可以更改,但是不要太大,否则效率会低
final int KEY_SIZE = 1024;
keyPairGen.initialize(KEY_SIZE, new SecureRandom());
KeyPair keyPair = keyPairGen.genKeyPair();
return keyPair;
catch (Exception e)
throw new Exception(e.getMessage());




/**
* 生成公钥
* @param modulus
* @param publicExponent
* @return RSAPublicKey
* @throws Exception
*/
private RSAPublicKey generateRSAPublicKey(byte[] modulus, byte[] publicExponent) throws Exception

KeyFactory keyFac = null;
try
keyFac = KeyFactory.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
catch (NoSuchAlgorithmException ex)
throw new Exception(ex.getMessage());

RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(publicExponent));
try
return (RSAPublicKey) keyFac.generatePublic(pubKeySpec);
catch (InvalidKeySpecException ex)
throw new Exception(ex.getMessage());




/**
* 生成私钥
* @param modulus
* @param privateExponent
* @return RSAPrivateKey
* @throws Exception
*/
private RSAPrivateKey generateRSAPrivateKey(byte[] modulus, byte[] privateExponent) throws Exception
KeyFactory keyFac = null;
try
keyFac = KeyFactory.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
catch (NoSuchAlgorithmException ex)
throw new Exception(ex.getMessage());

RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(modulus), new BigInteger(privateExponent));
try
return (RSAPrivateKey) keyFac.generatePrivate(priKeySpec);
catch (InvalidKeySpecException ex)
throw new Exception(ex.getMessage());



/**
* 加密
* @param key 加密的密钥
* @param data 待加密的明文数据
* @return 加密后的数据
* @throws Exception
*/
public byte[] encrypt(Key key, byte[] data) throws Exception
try
Cipher cipher = Cipher.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(Cipher.ENCRYPT_MODE, key);
// 获得加密块大小,如:加密前数据为128个byte,而key_size=1024 加密块大小为127 byte,加密后为128个byte;
// 因此共有2个加密块,第一个127 byte第二个为1个byte
int blockSize = cipher.getBlockSize();
// System.out.println("blockSize:"+blockSize);
int outputSize = cipher.getOutputSize(data.length);// 获得加密块加密后块大小
// System.out.println("加密块大小:"+outputSize);
int leavedSize = data.length % blockSize;
// System.out.println("leavedSize:"+leavedSize);
int blocksSize = leavedSize != 0 ? data.length / blockSize + 1 : data.length / blockSize;
byte[] raw = new byte[outputSize * blocksSize];
int i = 0;
while (data.length - i * blockSize > 0)
if (data.length - i * blockSize > blockSize)
cipher.doFinal(data, i * blockSize, blockSize, raw, i * outputSize);
else
cipher.doFinal(data, i * blockSize, data.length - i * blockSize, raw, i * outputSize);
// 这里面doUpdate方法不可用,查看源代码后发现每次doUpdate后并没有什么实际动作除了把byte[]放到ByteArrayOutputStream中
// 而最后doFinal的时候才将所有的byte[]进行加密,可是到了此时加密块大小很可能已经超出了OutputSize所以只好用dofinal方法。
i++;

return raw;
catch (Exception e)
throw new Exception(e.getMessage());



/**
* 解密
* @param key 解密的密钥
* @param raw 已经加密的数据
* @return 解密后的明文
* @throws Exception
*/
@SuppressWarnings("static-access")
public byte[] decrypt(Key key, byte[] raw) throws Exception
try
Cipher cipher = Cipher.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(cipher.DECRYPT_MODE, key);
int blockSize = cipher.getBlockSize();
ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
int j = 0;
while (raw.length - j * blockSize > 0)
bout.write(cipher.doFinal(raw, j * blockSize, blockSize));
j++;

return bout.toByteArray();
catch (Exception e)
throw new Exception(e.getMessage());



/**
* 返回公钥
* @return
* @throws Exception
*/
public RSAPublicKey getRSAPublicKey() throws Exception
//获取公钥
RSAPublicKey pubKey = (RSAPublicKey) keyPair.getPublic();
//获取公钥系数(字节数组形式)
byte[] pubModBytes = pubKey.getModulus().toByteArray();
//返回公钥公用指数(字节数组形式)
byte[] pubPubExpBytes = pubKey.getPublicExponent().toByteArray();
//生成公钥
RSAPublicKey recoveryPubKey = this.generateRSAPublicKey(pubModBytes,pubPubExpBytes);
return recoveryPubKey;


/**
* 获取私钥
* @return
* @throws Exception
*/
public RSAPrivateKey getRSAPrivateKey() throws Exception
// 获取私钥
RSAPrivateKey priKey = (RSAPrivateKey) keyPair.getPrivate();
// 返回私钥系数(字节数组形式)
byte[] priModBytes = priKey.getModulus().toByteArray();
// 返回私钥专用指数(字节数组形式)
byte[] priPriExpBytes = priKey.getPrivateExponent().toByteArray();
// 生成私钥
RSAPrivateKey recoveryPriKey = this.generateRSAPrivateKey(priModBytes,priPriExpBytes);
return recoveryPriKey;


/**
* 测试
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception
RSAUtil rsa = new RSAUtil();
String str = "天龙八部、神雕侠侣、射雕英雄传白马啸西风";
RSAPublicKey pubKey = rsa.getRSAPublicKey();
RSAPrivateKey priKey = rsa.getRSAPrivateKey();
// System.out.println("加密后==" + new String(rsa.encrypt(pubKey,str.getBytes())));
String mw = new String(rsa.encrypt(pubKey, str.getBytes()));
System.out.println("加密后:"+mw);
// System.out.println("解密后:");
System.out.println("解密后==" + new String(rsa.decrypt(priKey,rsa.encrypt(pubKey,str.getBytes()))));

参考技术A 使用RSA加密解密我倒是见过 不过这个所谓的填充方式...搞不懂
下面是经我测试通过的rsa加密解密
包括私钥加密用公钥解密和公钥加密用私钥解密2中方式
一共涉及2个类

import java.security.*;

/**
* <p>
* 计算字符串和byte[]的数字摘要
* </p>
*
* @Copyright:WDSsoft
* @ad:WDSsoft “企业多级数字签名系统”- 最佳的企业电子文档多级数字签名方案
*/
public class Digest

/**
* 计算字符串的SHA数字摘要,以byte[]形式返回
*/
public static byte[] MdigestSHA(String source)
//byte[] nullreturn = 0 ;
try
MessageDigest thisMD = MessageDigest.getInstance("SHA");
byte[] digest = thisMD.digest(source.getBytes("UTF8"));
return digest;
catch (Exception e)
return null;



/**
* 计算byte[]的SHA数字摘要,以byte[]形式返回
*/
public static byte[] MdigestSHA(byte[] source)
//byte[] nullreturn = 0 ;
try
MessageDigest thisMD = MessageDigest.getInstance("SHA");
byte[] digest = thisMD.digest(source);
return digest;
catch (Exception e)
return null;



/**
* 计算字符串的MD5数字摘要,以byte[]形式返回
*/
public static byte[] MdigestMD5(String source)
//byte[] nullreturn = 0 ;
try
MessageDigest thisMD = MessageDigest.getInstance("MD5");
byte[] digest = thisMD.digest(source.getBytes("UTF8"));
return digest;
catch (Exception e)
return null;



/**
* 计算byte[]的数MD5字摘要,以byte[]形式返回
*/
public static byte[] MdigestMD5(byte[] source)
//byte[] nullreturn = 0 ;
try
MessageDigest thisMD = MessageDigest.getInstance("MD5");
byte[] digest = thisMD.digest(source);
return digest;
catch (Exception e)
return null;




以上是获得数据的摘要的工具类
接下来
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import javax.crypto.Cipher;

/**
* <p>
* 封装同RSA非对称加密算法有关的方法,可用于数字签名,RSA加密解密
* </p>
*
* @Copyright:WDSsoft
*/

public class RSATool

public RSATool()


/**使用私钥加密数据
* 用一个已打包成byte[]形式的私钥加密数据,即数字签名
*
* @param keyInByte
* 打包成byte[]的私钥
* @param source
* 要签名的数据,一般应是数字摘要
* @return 签名 byte[]
*/
public static byte[] sign(byte[] keyInByte, byte[] source)
try
PKCS8EncodedKeySpec priv_spec = new PKCS8EncodedKeySpec(keyInByte);
KeyFactory mykeyFactory = KeyFactory.getInstance("RSA");
PrivateKey privKey = mykeyFactory.generatePrivate(priv_spec);
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initSign(privKey);
sig.update(source);
return sig.sign();
catch (Exception e)
return null;



/**
* 验证数字签名
*
* @param keyInByte
* 打包成byte[]形式的公钥
* @param source
* 原文的数字摘要
* @param sign
* 签名(对原文的数字摘要的签名)
* @return 是否证实 boolean
*/
public static boolean verify(byte[] keyInByte, byte[] source, byte[] sign)
try
KeyFactory mykeyFactory = KeyFactory.getInstance("RSA");
Signature sig = Signature.getInstance("SHA1withRSA");
X509EncodedKeySpec pub_spec = new X509EncodedKeySpec(keyInByte);
PublicKey pubKey = mykeyFactory.generatePublic(pub_spec);
sig.initVerify(pubKey);
sig.update(source);
return sig.verify(sign);
catch (Exception e)
return false;



/**
* 建立新的密钥对,返回打包的byte[]形式私钥和公钥
*
* @return 包含打包成byte[]形式的私钥和公钥的object[],其中,object[0]为私钥byte[],object[1]为公钥byte[]
*/
public static Object[] giveRSAKeyPairInByte()
KeyPair newKeyPair = creatmyKey();
if (newKeyPair == null)
return null;
Object[] re = new Object[2];
if (newKeyPair != null)
PrivateKey priv = newKeyPair.getPrivate();
byte[] b_priv = priv.getEncoded();
PublicKey pub = newKeyPair.getPublic();
byte[] b_pub = pub.getEncoded();
re[0] = b_priv;
re[1] = b_pub;
return re;

return null;


/**
* 新建密钥对
*
* @return KeyPair对象
*/
public static KeyPair creatmyKey()
KeyPair myPair;
long mySeed;
mySeed = System.currentTimeMillis();
try
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
random.setSeed(mySeed);
keyGen.initialize(1024, random);
myPair = keyGen.generateKeyPair();
catch (Exception e1)
return null;

return myPair;


/**
* 使用RSA公钥加密数据
*
* @param pubKeyInByte
* 打包的byte[]形式公钥
* @param data
* 要加密的数据
* @return 加密数据
*/
public static byte[] encryptByRSA(byte[] pubKeyInByte, byte[] data)
try
KeyFactory mykeyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec pub_spec = new X509EncodedKeySpec(pubKeyInByte);
PublicKey pubKey = mykeyFactory.generatePublic(pub_spec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
return cipher.doFinal(data);
catch (Exception e)
return null;



/**
* 用RSA私钥解密
*
* @param privKeyInByte
* 私钥打包成byte[]形式
* @param data
* 要解密的数据
* @return 解密数据
*/
public static byte[] decryptByRSA(byte[] privKeyInByte, byte[] data)
try
PKCS8EncodedKeySpec priv_spec = new PKCS8EncodedKeySpec(
privKeyInByte);
KeyFactory mykeyFactory = KeyFactory.getInstance("RSA");
PrivateKey privKey = mykeyFactory.generatePrivate(priv_spec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privKey);
return cipher.doFinal(data);
catch (Exception e)
return null;




/**
*测试
*/
public static void main(String[] args)
try
//私钥加密 公钥解密
//生成私钥-公钥对
Object[] v = giveRSAKeyPairInByte();
//获得摘要
byte[] source = Digest.MdigestSHA("假设这是要加密的客户数据");
//使用私钥对摘要进行加密 获得密文 即数字签名
byte[] sign = sign((byte[]) v[0], source);
//使用公钥对密文进行解密,解密后与摘要进行匹配
boolean yes = verify((byte[]) v[1], source, sign);
if (yes)
System.out.print("匹配成功 合法的签名!");

//公钥加密 私钥解密
//生成私钥-公钥对
KeyPair kp= creatmyKey();
//获得摘要
byte[] source1 = Digest.MdigestSHA("假设这是要加密的客户数据");

//使用公钥对摘要进行加密 获得密文
byte[] sign1 =encryptByRSA(kp.getPublic().getEncoded() ,source1);
//使用私钥对密文进行解密 返回解密后的数据
byte[] newSource1=decryptByRSA(kp.getPrivate().getEncoded(),sign1);
//对比源数据与解密后的数据
if(Arrays.equals(source1, newSource1))
System.out.print("匹配成功 合法的私钥!");

catch (Exception e)
e.printStackTrace();





以上主要代码收集于网络 我已经调试通过!
参考技术B 到图书馆找本相关的书看下就OK了。那里面也有代码的。

以上是关于RSA PKCS#1在java中怎么实现?的主要内容,如果未能解决你的问题,请参考以下文章

pkcs1与pkcs8格式RSA私钥互相转换

RSA加密算法--Java实现详细案例:

RSA公钥和私钥的生成以及PKCS#1与PKCE#8格式的转换

pkcs1padding怎么填充

python 实现RSA公钥加密,私钥解密

python 实现RSA公钥加密,私钥解密