package com.ivan.security.algorithm;
/**
* RSA加密算法的使用
* @author Ivan
* @DataTime 2006-12-12 16:38
* Java 本身不提供 RSA 算法的支持
* 需下载 assembla_msks_jce.ar 或 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的缺陷。一般来说只用于少量数据 加密。
*/
import javax.crypto.Cipher;
import com.iuxi.security.util.Tool;
import java.security.*;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.interfaces.RSAPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.math.BigInteger;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import se.assembla.jce.provider.ms.MSProvider;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class RSAUtil ...{
public static RSAPublicKey pubKey;
public static RSAPrivateKey priKey;
public static void init() ...{
Security.insertProviderAt(new MSProvider(), 2);
}
public static boolean saveKeys(String pubfile, String prifile) ...{
try ...{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(pubfile));
oos.writeObject(pubKey);
oos = new ObjectOutputStream(new FileOutputStream(prifile));
oos.writeObject(priKey);
oos.close();
return true;
}catch(IOException e) ...{
System.err.println("保存密钥失败!");
e.printStackTrace();
}
return false;
}
public static boolean readKeys(String pubfile, String prifile) ...{
try ...{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(pubfile));
pubKey = (RSAPublicKey)ois.readObject();
ois = new ObjectInputStream(new FileInputStream(prifile));
priKey = (RSAPrivateKey)ois.readObject();
return true;
}catch(IOException e) ...{
System.err.println("读取密钥失败!");
e.printStackTrace();
}catch(Exception e) ...{
e.printStackTrace();
}
return false;
}
/** *//**
* 生成密钥对
* @return 返回该密钥对 KeyPair
* @throws Exception 指定的算法无效
*/
public static KeyPair genKeyPair() throws Exception ...{
try ...{
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
final int KEY_SIZE = 1024;
keyPairGen.initialize(KEY_SIZE,new SecureRandom());
KeyPair keyPair = keyPairGen.genKeyPair();
pubKey = (RSAPublicKey)keyPair.getPublic();
priKey = (RSAPrivateKey)keyPair.getPrivate();
return keyPair;
}catch(NoSuchAlgorithmException e) ...{
System.err.println("生成密钥对错误,无效算法!");
throw new Exception(e.getMessage());
}
}
/** *//**
* 生成加密用的公钥
* @param module 系数
* @param publicExponent 公用指数
* @return 生成的公钥
* @throws Exception 指定的算法无效
*/
public static RSAPublicKey genRSAPublicKey(byte[] module, byte[] publicExponent) throws Exception ...{
System.out.println("正在生成公钥...");
try ...{
KeyFactory keyFac = null;
keyFac = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(module),new BigInteger(publicExponent));
pubKey = (RSAPublicKey)keyFac.generatePublic(pubKeySpec);
return pubKey;
}catch(NoSuchAlgorithmException e) ...{
System.err.println("生成公钥错误,无效算法!");
throw new Exception(e.getMessage());
}catch(InvalidKeySpecException e) ...{
throw new Exception(e.getMessage());
}
}
/** *//**
* 生成加密用的私钥
* @param module 系数
* @param privateExponent 公用指数
* @return 生成的私钥
* @throws Exception 指定的算法无效
*/
public static RSAPrivateKey genRSAPrivateKey(byte[] module, byte[] privateExponent) throws Exception ...{
System.out.println("正在生成私钥...");
try ...{
KeyFactory keyFac = KeyFactory.getInstance("RSA");
RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(module), new BigInteger(privateExponent));
priKey = (RSAPrivateKey)keyFac.generatePrivate(priKeySpec);
return priKey;
}catch(NoSuchAlgorithmException e) ...{
System.err.println("生成私钥错误,无效算法");
throw new Exception(e.getMessage());
}
}
/** *//**
* 对 byte[] 类型数据进行加密
* @param data 原始数据
* @return cipherData 加密后的数据
* @throws Exception
*/
public static byte[] encryptData(byte[] rawData) throws Exception ...{
if(pubKey == null) ...{
System.err.println("加密失败,原因:加密密钥不存在!");
return null;
}
try ...{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
int blockSize = cipher.getBlockSize(); //获取加密数据块的大小
int outputSize = cipher.getOutputSize(rawData.length); //获取加密后数据块的大小
int leavedSize = rawData.length % blockSize;
int blocksNum = (leavedSize == 0)?(rawData.length / blockSize):(rawData.length / blockSize +1); //获取加密块数
byte[] cipherData = new byte[outputSize * blocksNum];
// System.err.println("rawData.length = " + rawData.length);
// System.err.println("cipherData.length = " + cipherData.length);
// System.err.println("blockSize = " + blockSize);
// System.err.println("outputSize = " + outputSize);
// System.err.println("blocksNum = " + blocksNum);
//对每块数据分别加密
// for(int i=0; i<blocksNum; i++) {
// System.err.println(i + " * blockSize = " + (i * blockSize));
// System.err.println(i + " * outputSize = " + (i * outputSize));
// System.err.println("rawData.length - " + i + " * blockSize = " + (rawData.length - i * blockSize));
// if((rawData.length - i * blockSize) > blockSize)
// cipher.doFinal(rawData, i * blockSize, blockSize, cipherData);
// else
// cipher.doFinal(rawData, i * blockSize, rawData.length - i * blockSize, cipherData);
// }
cipherData = cipher.doFinal(rawData);
return cipherData;
}catch(Exception e) ...{
e.printStackTrace();
throw new Exception(e.getMessage());
}
}
/** *//**
* 解密 cipherData 为明文
* @param cipherData 原始密文
* @return 解密后的明文
* @throws Exception
*/
public static byte[] decryptData(byte[] cipherData) throws Exception ...{
System.out.println("正在解密数据...");
if(priKey == null) ...{
System.err.println("解密失败,原因:解密密钥不存在!");
return null;
}
try ...{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(cipher.DECRYPT_MODE, priKey);
int blockSize = cipher.getBlockSize();
// System.err.println("Decrypt: BlockSize = " + blockSize);
// System.err.println("Decrypt: CipherLength = " + cipherData.length);
ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
int j = 0;
//分别对各块数据进行解密
while((cipherData.length - j * blockSize) > 0) ...{
bout.write(cipher.doFinal(cipherData, j * blockSize, blockSize));
j++;
}
return bout.toByteArray();
}catch(Exception e) ...{
e.printStackTrace();
throw new Exception(e.getMessage());
}
}
public static void main(String[] args) throws Exception...{
byte[] rawData = Tool.readRawData("Order.xml");
RSAUtil.init();
KeyPair keyPair = RSAUtil.genKeyPair();
if(RSAUtil.saveKeys("RSAPubKey.dat", "RSAPriKey.dat"));
else
System.err.println("保存密钥失败...");
// byte[] pubModBytes = pubKey.getModulus().toByteArray();
// byte[] pubPubExpBytes = pubKey.getPublicExponent().toByteArray();
// byte[] priModBytes = priKey.getModulus().toByteArray();
// byte[] priPriExpBytes = priKey.getPrivateExponent().toByteArray();
//
// RSAPublicKey recoveryPubKey = RSA.genRSAPublicKey(pubModBytes, pubPubExpBytes);
// System.out.println("生成恢复性RSA公钥成功");
// RSAPrivateKey recoveryPriKey = RSA.genRSAPrivateKey(priModBytes, priPriExpBytes);
// System.out.println("生成恢复性RSA私钥成功");
byte[] cipherData = RSAUtil.encryptData(rawData);
String cipher = new String();
cipher = new BASE64Encoder().encode(cipherData);
System.err.println(cipher);
// System.out.println("加密后的密文为:" + Tool.byte2hex(cipherData));
// System.out.println("加密成功");
rawData = RSAUtil.decryptData(new BASE64Decoder().decodeBuffer(cipher));
System.out.println("解密后的明文为: " + new String(rawData));
}
}