CRsa.java
资源名称:security.rar [点击查看]
上传用户:lior1029
上传日期:2013-05-07
资源大小:209k
文件大小:21k
源码类别:
CA认证
开发平台:
Java
- package org.infosecurity.cryptography;
- /**
- * <p>Title: RSA算法的软件实现 </p>
- * <p>Description: RSA算法的软件实现,功能包括:公钥加密私钥解密</p>
- * <p>数字签名和签名验证,密钥对(公私钥)的生成,遵循PKCS标准</p>
- * <p>Copyright: Copyright (c) 2003</p>
- * <p>Company: 中信信息安全组织(CISO)</p>
- * @author 张荣华
- * @version 1.0.2003.0704
- */
- import java.io.*;
- import java.math.*;
- import java.util.*;
- import java.security.SecureRandom;
- import org.bouncycastle.asn1.*;
- import org.bouncycastle.asn1.x509.*;
- import org.bouncycastle.util.encoders.*;
- public class CRsa extends Object implements Serializable {
- // HASH算法的缺省摘要的信息
- private final static byte[] SHA1_DIGEST_INFO = {
- (byte)0x30, (byte)0x21, (byte)0x30, (byte)0x09, (byte)0x06,
- (byte)0x05, (byte)0x2b, (byte)0x0e, (byte)0x03, (byte)0x02,
- (byte)0x1a, (byte)0x05, (byte)0x00, (byte)0x04, (byte)0x14,
- (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
- (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
- (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
- (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00
- };
- private final static byte[] MD5_DIGEST_INFO = {
- (byte)0x30, (byte)0x20, (byte)0x30, (byte)0x0c, (byte)0x06,
- (byte)0x08, (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86,
- (byte)0xf7, (byte)0x0d, (byte)0x02, (byte)0x05, (byte)0x05,
- (byte)0x00, (byte)0x04, (byte)0x10, (byte)0x00, (byte)0x00,
- (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
- (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
- (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00
- };
- private byte[] mTDefault=null;
- private int mLen=0;
- //
- private SecureRandom secureRd=new SecureRandom();
- private static BigInteger ONE = BigInteger.valueOf(1);
- private static BigInteger TWO = BigInteger.valueOf(2);
- // ebase为17
- private static BigInteger eBase = BigInteger.valueOf(0x11);
- RSAPublicKey pukParam=null;
- RSAPrivateKey pvkParam=null;
- public CRsa() {
- }
- /**
- * 设置公钥
- */
- public void setPublicKey(RSAPublicKey puk)
- {
- this.pukParam = puk;
- }
- /**
- * 设置私钥
- */
- public void setPrivateKey(RSAPrivateKey pvk)
- {
- this.pvkParam = pvk;
- this.pukParam = new RSAPublicKey(pvk.getModulus(),pvk.getExponent());
- }
- /**
- * 公钥加密
- */
- public byte[] PublicKeyEncrypt(byte[] indata,int indatalen)
- throws DataLengthException
- {
- int k=getInputBlockSize(true);
- byte EncryptBlock[]=null;
- // PS依据输入数据的长度>8
- if (indatalen > getInputBlockSize(true)-10)
- {
- throw new DataLengthException("输入RSA加密的数据太长.n");
- }
- ByteArrayOutputStream baos=new ByteArrayOutputStream();
- byte[] PS=new byte[(getOutputBlockSize(true)-indatalen-2)];
- for(int i=0;i<PS.length;i++)
- {
- PS[i]=(byte)(secureRd.nextInt(255)+1);
- }
- try
- {
- baos.write((byte)0x02);
- baos.write(PS);
- baos.write((byte)0x00);
- baos.write(indata);
- }catch(IOException ioe){
- ioe.printStackTrace();
- }
- EncryptBlock=baos.toByteArray();
- BigInteger input = new BigInteger(1, EncryptBlock);
- byte[] output=null;
- output = input.modPow(pukParam.getExponent(), pukParam.getModulus()).toByteArray();
- if (output[0] == 0 && output.length > getOutputBlockSize(true))//比输出长度长,截断
- {
- byte[] tmp = new byte[output.length - 1];
- System.arraycopy(output, 1, tmp, 0, tmp.length);
- return tmp;
- }
- if (output.length < getOutputBlockSize(true)) // 比输出长度短,增长
- {
- byte[] tmp = new byte[getOutputBlockSize(true)];
- System.arraycopy(output, 0, tmp, tmp.length - output.length, output.length);
- return tmp;
- }
- return output;
- }
- /**
- * 私钥解密
- */
- public byte[] PrivateKeyDecrypt(byte[] indata,int indatalen)
- throws DataLengthException
- {
- int padLength=0;
- if (indatalen > getInputBlockSize(false))
- {
- throw new DataLengthException("输入RSA解密的数据太长.");
- }
- byte[] output=null;
- BigInteger input=new BigInteger(1,indata);
- output = input.modPow(pvkParam.getPrivateExponent(), pukParam.getModulus()).toByteArray();
- if(output.length<10)
- throw new DataLengthException("消息格式不对.");
- if(output[0]!=(byte)0x02)
- {
- throw new DataLengthException("不是公钥操作的结果");
- }
- int start=0;
- int outLen=output.length;
- while(output[start]!=(byte)0x00)
- {
- start++;
- if(start>=outLen)
- throw new DataLengthException("无效的填充数据!");
- }
- start++; // 跳过0
- byte tm[]=new byte[outLen-start];
- try {
- System.arraycopy(output,start,tm,0,tm.length);
- }
- catch (Exception ex) {
- return null;
- }
- return tm;
- }
- /**
- * 数字签名
- * @param HashAlgorith 散列算法(5--md5 3--sha1)
- * @param indata 输入数据
- */
- public byte[] signData(int HashAlgorithm,byte[] indata)
- throws Exception
- {
- int indatalen=indata.length;
- byte[] hashRes=null;
- int blockLen=getInputBlockSize(true);
- if(HashAlgorithm==5)
- hashRes=new byte[16];
- else if(HashAlgorithm==3)
- hashRes=new byte[20];
- else
- throw new Exception("不支持的散列算法!");
- if(indata==null||indata.length==0)
- throw new Exception("输入数据为空");
- if(HashAlgorithm==5)
- {
- // 生成摘要
- mTDefault=new byte[MD5_DIGEST_INFO.length];
- mLen=16;
- System.arraycopy(MD5_DIGEST_INFO,0,mTDefault,0,mTDefault.length);
- CMd5 md5=new CMd5();
- for(int i=0;i<indatalen;i++)
- md5.update(indata[i]);
- md5.doFinal(hashRes,0);
- // 摘要编码
- // 待编码的长度要比密钥的长度小1
- byte inbyte[]=encode(hashRes,getOutputBlockSize(true)-1,16);
- // 签名
- byte[] signData=null;
- BigInteger input=new BigInteger(1,inbyte);
- signData = input.modPow(pvkParam.getPrivateExponent(), pukParam.getModulus()).toByteArray();
- // 如果是正数转成一个字节数组,我们将得到一个以0开头的结果
- if (signData[0] == 0 && signData.length > getOutputBlockSize(true))//比输出长度长,截断
- {
- byte[] tmp = new byte[signData.length - 1];
- System.arraycopy(signData, 1, tmp, 0, tmp.length);
- return tmp;
- }
- if (signData.length < getOutputBlockSize(true)) // 比输出长度短,增长
- {
- byte[] tmp = new byte[getOutputBlockSize(true)];
- System.arraycopy(signData, 0, tmp, tmp.length - signData.length, signData.length);
- return tmp;
- }
- return signData;
- }
- if(HashAlgorithm==3)
- {
- mTDefault=new byte[SHA1_DIGEST_INFO.length];
- mLen=20;
- System.arraycopy(SHA1_DIGEST_INFO,0,mTDefault,0,mTDefault.length);
- CSha1 sha1=new CSha1();
- for(int i=0;i<indatalen;i++)
- sha1.update(indata[i]);
- sha1.doFinal(hashRes,0);
- // 摘要编码
- byte inbyte[]=encode(hashRes,getOutputBlockSize(true)-1,20);
- // 签名
- byte[] signData=null;
- BigInteger input=new BigInteger(1,inbyte);
- signData = input.modPow(pvkParam.getPrivateExponent(), pukParam.getModulus()).toByteArray();
- if (signData[0] == 0 && signData.length > getOutputBlockSize(true))//比输出长度长,截断
- {
- byte[] tmp = new byte[signData.length - 1];
- System.arraycopy(signData, 1, tmp, 0, tmp.length);
- return tmp;
- }
- if (signData.length < getOutputBlockSize(true)) // 比输出长度短,增长
- {
- byte[] tmp = new byte[getOutputBlockSize(true)];
- System.arraycopy(signData, 0, tmp, tmp.length - signData.length, signData.length);
- return tmp;
- }
- return signData;
- }
- return null;
- }
- /**
- * 验证数字签名
- */
- public int verifySignData(byte[] indata,byte[] plainData)throws Exception
- {
- try {
- if(indata.length>getInputBlockSize(false))
- throw new Exception("签名的输入长度过长!");
- BigInteger input=new BigInteger(1,indata);
- byte[] out = input.modPow(pukParam.getExponent(), pukParam.getModulus()).toByteArray();
- byte[] bEncodedHash=decode(out);
- ByteArrayInputStream bIn=null;
- bIn = new ByteArrayInputStream(bEncodedHash);
- DERInputStream dIn = new DERInputStream(bIn);
- ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
- if(seq.size()==2)
- {
- DigestInfo digestInf=DigestInfo.getInstance(seq);
- AlgorithmIdentifier aID=digestInf.getAlgorithmId();
- if(aID.getObjectId().getId().equals("1.2.840.113549.2.5"))//MD5
- {
- // 生成摘要
- int plainDataLength=0;
- plainDataLength=plainData.length;
- byte[] plainHash=new byte[16];
- CMd5 md5=new CMd5();
- for(int i=0;i<plainDataLength;i++)
- md5.update(plainData[i]);
- md5.doFinal(plainHash,0);
- byte[] digest=digestInf.getDigest();
- for(int i=0;i<md5.getDigestSize();i++)
- {
- //System.out.println("result="+digest[i]+"plain="+plainHash[i]);
- if(digest[i]==plainHash[i])
- {
- //调试输出语句
- continue;
- }
- else
- return 0;
- }
- return 1;
- }
- else if(aID.getObjectId().getId().equals("1.3.14.3.2.26"))
- {
- // 生成摘要
- int plainDataLength=0;
- plainDataLength=plainData.length;
- byte[] plainHash=new byte[20];
- CSha1 sha1=new CSha1();
- for(int i=0;i<plainDataLength;i++)
- sha1.update(plainData[i]);
- sha1.doFinal(plainHash,0);
- byte[] digest=digestInf.getDigest();
- for(int i=0;i<sha1.getDigestSize();i++)
- {
- if(digest[i]==plainHash[i])
- continue;
- else
- return 0;
- }
- return 1;
- }
- else
- {
- // 目前不支持该算法
- return 0;
- }
- }
- else
- return 0;
- }
- catch (Exception e) {
- e.printStackTrace();
- return 0;
- }
- }
- // 最大输入长度
- private int getInputBlockSize(boolean forEncryption)
- {
- int bitSize = pukParam.getModulus().bitLength();
- if (forEncryption)
- {
- return (bitSize + 7) / 8 - 1;
- }
- else
- {
- return (bitSize + 7) / 8;
- }
- }
- // 最大的输出长度
- private int getOutputBlockSize(boolean forEncryption)
- {
- int bitSize =
- pukParam.getModulus().bitLength();
- if (forEncryption)
- {
- return (bitSize + 7) / 8;
- }
- else
- {
- return (bitSize + 7) / 8 - 1;
- }
- }
- // 密钥对的生成
- public int generateKeyPair(int length)
- {
- BigInteger p, q, n, d, e, pSub1, qSub1, phi;
- BigInteger dP, dQ, qInv;
- int pbitlength = (length + 1) / 2;
- int qbitlength = (length- pbitlength);
- //e在标准中推荐使用3或65537
- e=new BigInteger("65537",10);
- //生成素数p,并且使p-1与e互素
- for (;;)
- {
- p = new BigInteger(pbitlength, 50,new SecureRandom());
- if (e.gcd(p.subtract(ONE)).equals(ONE)) break;
- }
- for (;;)
- {
- //生成素数q,并且使q-1与e互素,与p不相等
- for (;;)
- {
- q = new BigInteger(qbitlength,50,new SecureRandom());
- if (e.gcd(q.subtract(ONE)).equals(ONE) && !p.equals(q)) break;
- }
- //模数n=p*q
- n = p.multiply(q);
- if (n.bitLength() == length) break;
- p = p.max(q);
- }
- //pSub1=p-1
- //qSub1=q-1
- pSub1 = p.subtract(ONE);
- qSub1 = q.subtract(ONE);
- //计算(p-1)*(q-1)
- phi = pSub1.multiply(qSub1);
- //求私钥指数d: 按公式d*e=n mod (p-1)(q-1)
- d = e.modInverse(phi);
- //应用中国剩余定理
- //求CRT指数:dQ=d mod (q-1)
- //求CRT指数:dP=d mod (p-1)
- dP = d.remainder(pSub1);
- dQ = d.remainder(qSub1);
- //1/q mod p0
- qInv = q.modInverse(p);
- pukParam=new RSAPublicKey(n, e);
- pvkParam=new RSAPrivateKey(n, e, d, p, q, dP, dQ, qInv);
- return 1;
- }
- public byte[] encode(byte[] H, int outLen,int mHLen)
- throws Exception
- {
- if (outLen < mTDefault.length + 10) {
- throw new Exception("encoding too short");
- }
- byte[] T = new byte[mTDefault.length];
- System.arraycopy(mTDefault,0,T,0,T.length);
- System.arraycopy(H,0,T,T.length - mHLen,mHLen);
- byte[] PS = new byte[outLen - T.length - 2];
- for (int i = 0; i < PS.length; i++) {
- PS[i] = (byte)0xFF;
- }
- // Create the output block, 01 || PS || 00 || T.
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- baos.write((byte)0x01);
- baos.write(PS);
- baos.write((byte)0x00);
- baos.write(T);
- } catch (IOException ioe) {
- // This should never happen
- ioe.printStackTrace();
- }
- byte[] EM = baos.toByteArray();
- return EM;
- }
- public byte[] decode(byte[] indata) throws Exception
- {
- if(indata.length<34)
- throw new Exception("消息格式不对.");
- if(indata[0]!=(byte)0x01)
- {
- throw new Exception("不是签名的结果");
- }
- int start=0;
- int outLen=indata.length;
- while(indata[start]!=(byte)0x00)
- {
- start++;
- if(start>=outLen)
- throw new Exception("无效的填充数据!");
- }
- start++; // 跳过0
- byte tm[]=new byte[outLen-start];
- try {
- System.arraycopy(indata,start,tm,0,tm.length);
- }
- catch (Exception ex) {
- return null;
- }
- return tm;
- }
- public RSAPublicKey getPublicKey()
- {
- return pukParam;
- }
- public RSAPrivateKey getPrivateKey()
- {
- return pvkParam;
- }
- /**
- * 将公钥读入
- * @author 张荣华
- */
- public RSAPublicKey readPuk(String strPukFileName)
- throws IOException
- {
- FileInputStream fis = new FileInputStream(strPukFileName);
- int fLength = fis.available();
- byte[] bytePuk = new byte[fLength];
- fis.read(bytePuk,0,fLength);
- fis.close();
- ByteArrayInputStream bIn = new ByteArrayInputStream(bytePuk);
- DERInputStream dIn = new DERInputStream(bIn);
- ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
- if(seq.size()==2)
- {
- DERInteger n = (DERInteger)seq.getObjectAt(0);
- DERInteger e = (DERInteger)seq.getObjectAt(1);
- return new RSAPublicKey(n.getValue(),e.getValue());
- }
- return null;
- }
- /**
- * 将公钥写入到文件(DER)编码
- * @author 张荣华
- */
- public int writePuk(RSAPublicKey puk,String strPukFileName)
- throws IOException
- {
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
- DEROutputStream dOut = new DEROutputStream(bOut);
- dOut.writeObject(puk.getDERObject());
- byte[] m_bPuk=bOut.toByteArray();
- dOut.close();
- FileOutputStream fos = new FileOutputStream(strPukFileName);
- fos.write(m_bPuk);
- fos.flush();
- fos.close();
- return 1;
- }
- /**
- * 将私钥写入到文件(DER编码)
- * @author 张荣华
- */
- public int writePvk(RSAPrivateKey pvk,String strPvkFileName)
- throws IOException
- {
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
- DEROutputStream dOut = new DEROutputStream(bOut);
- dOut.writeObject(pvk.getDERObject());
- byte[] m_bPvk=bOut.toByteArray();
- dOut.close();
- FileOutputStream fos = new FileOutputStream(strPvkFileName);
- fos.write(m_bPvk);
- fos.flush();
- fos.close();
- return 1;
- }
- /**
- * 从文件读入公钥
- * @author 张荣华
- */
- public RSAPrivateKey readPvk(String strPvkFileName)
- throws IOException
- {
- FileInputStream fis = new FileInputStream(strPvkFileName);
- int fLength = fis.available();
- byte[] bytePvk = new byte[fLength];
- fis.read(bytePvk,0,fLength);
- fis.close();
- ByteArrayInputStream bIn = new ByteArrayInputStream(bytePvk);
- DERInputStream dIn = new DERInputStream(bIn);
- ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
- if(seq.size()==9)
- {
- DERInteger n = (DERInteger)seq.getObjectAt(1);
- DERInteger e = (DERInteger)seq.getObjectAt(2);
- DERInteger d = (DERInteger)seq.getObjectAt(3);
- DERInteger p = (DERInteger)seq.getObjectAt(4);
- DERInteger q = (DERInteger)seq.getObjectAt(5);
- DERInteger dp = (DERInteger)seq.getObjectAt(6);
- DERInteger dq = (DERInteger)seq.getObjectAt(7);
- DERInteger qInv = (DERInteger)seq.getObjectAt(8);
- return new RSAPrivateKey(
- n.getValue(),e.getValue(),d.getValue(),
- p.getValue(),q.getValue(),dp.getValue(),
- dq.getValue(),qInv.getValue());
- }
- return null;
- }
- /**
- * 以下是RSA算法的软件实现测试程序
- * @author 张荣华
- */
- public static void main(String[] args) {
- CRsa rsa= new CRsa();
- // 密钥生成测试
- // 密钥长度支持512 768 1024 2048 4096 再长也支持,但怕你的机器受不了
- System.out.println("=====================密钥生成测试======================");
- rsa.generateKeyPair(512);
- //rsa.savePukToFile("E:\JavaProj\temp\puk.key");
- //rsa.savePvkToFile("E:\JavaProj\temp\pvk.key");
- try {
- rsa.writePuk(rsa.getPublicKey(),"E:\JavaProj\temp\puk.key");
- rsa.writePvk(rsa.getPrivateKey(),"E:\JavaProj\temp\pvk.key");
- // rsa.readPuk("E:\JavaProj\temp\puk.key");
- // rsa.readPvk("E:\JavaProj\temp\pvk.key");
- }
- catch (IOException ex) {
- }
- System.out.println(rsa.getPublicKey().getModulus().toString(16));
- // 公钥加密私钥解密测试
- System.out.println("==================公钥加密私钥解密测试==================");
- String str="你好,张荣华!";
- byte[] indata=str.getBytes();
- int indatalen=indata.length;
- byte[] cipherData=null;
- byte[] plainData=null;
- try {
- cipherData=rsa.PublicKeyEncrypt(indata,indatalen);
- }
- catch (Exception ex) {
- //ex.printStackTrace();
- }
- try {
- plainData=rsa.PrivateKeyDecrypt(cipherData,cipherData.length);
- }
- catch (Exception ex) {
- //ex.printStackTrace();
- }
- System.out.println("解出的明文:t"+new String(plainData));
- System.out.println("长度(字节)=t"+plainData.length);
- // 数字签名及签名验证测试
- System.out.println("==================数字签名及签名验证测试==================");
- String strSign="这是一个签名测试!";
- byte[] signRes=null;
- try {
- // MD5WithRSA
- signRes=rsa.signData(5,strSign.getBytes());
- }
- catch (Exception ex) {
- ex.printStackTrace();
- }
- try {
- int success=rsa.verifySignData(signRes,strSign.getBytes());
- if(success==1)
- System.out.println("签名验证成功!");
- else
- System.out.println("签名验证失败!");
- }
- catch (Exception ex) {
- }
- }
- }