基于JCE的密钥分配------------------------(三)利用公钥密码技术实现对称密码技术密钥的分配

假定作为通讯的双方A和B已经拥有对方的公钥

===================Provider.java,加密解密算法工具类======================

package third_hard;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

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.ByteArrayOutputStream;
import java.math.BigInteger;

public class Provider {

    /**
     * 生成密钥对
     *
     * @return KeyPair
     * @throws EncryptException
     */
    public static 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
     */
    public static 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
     */
    public static 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());
        }
    }
   
    /**
  * 加密数据,RSA
  *
  * @param key
  * @param data
  * @return
  * @throws Exception
  */
 public static 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);
            int blockSize = cipher.getBlockSize();//获得加密块大小,如:加密前数据为128个byte,而key_size=1024 加密块大小为127 byte,加密后为128个byte;因此共有2个加密块,第一个127 byte第二个为1个byte
            int outputSize = cipher.getOutputSize(data.length);//获得加密块加密后块大小
            int leavedSize = data.length % blockSize;//最后一块的大小,若为0,表示刚好分块
            int blocksSize = leavedSize != 0 ? data.length / blockSize + 1 : data.length / blockSize;//若leavedSize不为0,块数需加1,因为最后还一块

            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());
        }
 }
 
 /**
  * 解密,RSA
  *
  * @param key
  *    解密密钥
  * @param data
  *    待解密数据
  * @return
  * @throws Exception
  */
 public static 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(128);
            int j = 0;
            while (raw.length - j * blockSize > 0) {
                bout.write(cipher.doFinal(raw, j * blockSize, blockSize));
                j++;
            }
           
            return bout.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
 }
 /**
  * 生成密钥
  *
  * @return
  *   密钥
  */
 public static Key generateKey(String str){
  try {
   KeyGenerator kg = KeyGenerator.getInstance("DES");
   SecureRandom sr = new SecureRandom(str.getBytes());//随机数源
   kg.init(sr);//初始化
   
   Key key = kg.generateKey();//生成密钥
   return key;
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   return null;
  }
 }
 
 /**
  *
  * @param key
  * @return
  */
 public static SecretKey generateSecretKey(byte[] key){
  SecretKeyFactory fac = null;
  try {
   //创建一个密钥工厂
   fac = SecretKeyFactory.getInstance("DES");
   DESKeySpec spec = new DESKeySpec(key);//从原始密匙数据创建一个DESKeySpec对象
   
   return fac.generateSecret(spec);
   
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   return null;
  }
 }
 
 /**
  * 加密数据,DES
  *
  * @param key
  * @param data
  * @return
  * @throws Exception
  */
 public static byte[] encrypt(SecretKey key,byte[] data) throws Exception{
  Cipher cipher = Cipher.getInstance("DES",new org.bouncycastle.jce.provider.BouncyCastleProvider());
  SecureRandom sr = new SecureRandom();
  cipher.init(Cipher.ENCRYPT_MODE, key,sr);
  
  return cipher.doFinal(data);
 }
 
 /**
  * 解密,DES
  *
  * @param key
  *    解密密钥
  * @param data
  *    待解密数据
  * @return
  * @throws Exception
  */
 public static byte[] decrypt(SecretKey key,byte[] data) throws Exception{
  Cipher cipher = Cipher.getInstance("DES",new org.bouncycastle.jce.provider.BouncyCastleProvider());
  cipher.init(Cipher.DECRYPT_MODE, key);
  
  return cipher.doFinal(data);
 }
}

=======================User.java,用户类==========================

package third_hard;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.*;
import java.security.Key;
import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Random;

import javax.crypto.*;
import javax.swing.*;

/**
 * 会话用户类
 *
 * @author Administrator
 *
 */
public class User extends JFrame {

 /**
  *
  */
 private static final long serialVersionUID = 7267580701580372205L;

 private JButton jb; // 按钮
 private JTextArea jta; // 文本显示区
 private Container cta;

 private String orgData; // 保存要加密发送的明文
 private int id; // 用户ID
 private SecretKey secretKey;
 private KeyPair keyPairSelf;
 private RSAPublicKey pubKeyOther;
 private RSAPublicKey pubKeySelf = null;// 公钥
 private RSAPrivateKey priKeySelf = null;// 私钥

 private boolean working = false; // 是否正在发送或接收
 private ObjectInputStream sendin, receivein; // 发起会话请求的用户(A)的输入输出流
 private ObjectOutputStream sendout, receiveout;// 接受会话请求的用户(B)的输入输出流
 private Socket s;
 private ServerSocket receiveSocket;

 Thread thread;
 private int N1, N2; // 随机数

 /**
  * 构造函数
  *
  * @param id
  *            用户ID
  * @param secretKey
  *            共享会话主密钥
  */
 public User(int id, KeyPair keyPairSelf, RSAPublicKey pubKeyOther) {
  this.id = id;
  this.keyPairSelf = keyPairSelf;
  this.pubKeyOther = pubKeyOther;

  cta = getContentPane();
  jta = new JTextArea();
  jta.setEditable(false);
  jta.setLineWrap(true);
  jb = new JButton("SEND");
  jb.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent e) {
    if (!working) {
     SendMsg sm = new SendMsg();
     Thread threadsm = new Thread(sm);
     threadsm.start(); // 启动请求会话线程
    } else
     jta.append("/n正在发送或接收数据,请稍后!");
   }
  });
  cta.setLayout(new BorderLayout());
  cta.add(jb, BorderLayout.SOUTH);
  cta.add(new JScrollPane(jta), BorderLayout.CENTER);
  setSize(300, 300);
  setVisible(true);

  try {
   initKeys();
  } catch (Exception e1) {
   // TODO Auto-generated catch block
   e1.printStackTrace();
  }
  WaitForMsg wfm = new WaitForMsg(id);
  thread = new Thread(wfm);
  thread.start(); // 启动等待会话线程
 }

 /**
  * 产生自己的公钥和密钥
  *
  * @throws Exception
  */
 public void initKeys() throws Exception {
  RSAPublicKey pubKey = (RSAPublicKey) keyPairSelf.getPublic();// 公钥
  RSAPrivateKey priKey = (RSAPrivateKey) keyPairSelf.getPrivate();// 私钥
  byte[] pubModBytes = pubKey.getModulus().toByteArray();
  byte[] pubPubExpBytes = pubKey.getPublicExponent().toByteArray();
  byte[] priModBytes = priKey.getModulus().toByteArray();
  byte[] priPriExpBytes = priKey.getPrivateExponent().toByteArray();
  this.pubKeySelf = Provider.generateRSAPublicKey(pubModBytes,
    pubPubExpBytes);
  this.priKeySelf = Provider.generateRSAPrivateKey(priModBytes,
    priPriExpBytes);
 }

 /**
  * 从文件中读入要发送的明文
  *
  * @throws Exception
  */
 private void readin() throws Exception {
  File file = new File("test-1.txt");
  FileInputStream fin;
  fin = new FileInputStream(file);
  ByteArrayOutputStream bout = new ByteArrayOutputStream();
  byte[] tmpbuf = new byte[1024];
  int count = 0;
  while ((count = fin.read(tmpbuf)) != -1) {
   bout.write(tmpbuf, 0, count);
   tmpbuf = new byte[1024];
  }
  fin.close();
  orgData = bout.toString(); // 明文
 }

 /**
  * 利用Socket发送数据,先发送数据长度,再发送数据
  *
  * @param data
  *            要发送的数据
  * @param out
  *            输出流
  * @throws Exception
  */
 public void sendData(byte[] data, ObjectOutputStream out) throws Exception {
  int num = data.length;
  out.writeInt(num);
  out.flush();

  out.write(data);
  out.flush();
 }

 /**
  * 接收数据,先接收数据长度,然后接收真正的数据
  *
  * @param in
  *            输入流
  * @return 接收到的数据
  * @throws Exception
  */
 public byte[] recData(ObjectInputStream in) throws Exception {
  int len = in.readInt();
  byte[] rec1 = new byte[len];
  in.read(rec1);

  return rec1;
 }

 /**
  * 产生一个随机数,在0~999之间
  *
  * @return 产生的随机数
  */
 public int rand() {
  return (new Random()).nextInt() % 1000;
 }

 /**
  * 当请求会话时,调用该函数
  */
 public void send() {
  InetAddress ip;
  int sendport = id == 10000 ? 20000 : 10000; // 请求连接对方的端口号
  Socket connect;

  try {
   ip = InetAddress.getByName("localhost"); // 连接到本机
   connect = new Socket(ip, sendport);
   sendout = new ObjectOutputStream(connect.getOutputStream());// 获得输出流
   sendin = new ObjectInputStream(connect.getInputStream()); // 获得输入流

   N1 = rand(); // 产生随机数N1
   String strSend1 = N1 + "//" + id; // 拼接上 IDA

   byte[] strSend2 = Provider
     .encrypt(pubKeyOther, strSend1.getBytes());// 用B的公钥加密
   sendData(strSend2, sendout); // 发送

   byte[] rec1 = recData(sendin);
   byte[] datatemp1 = Provider.decrypt(priKeySelf, rec1); // 用自己的密钥解密,得到N1/N2
   String datatemp2 = new String(datatemp1);
   String[] datatemp3 = datatemp2.split("//");

   if (N1 == Integer.parseInt(datatemp3[0])) { // 确认N1
    byte[] strSend3 = Provider.encrypt(pubKeyOther, datatemp3[1]
      .getBytes());

    sendData(strSend3, sendout);
    int keyNum = rand();
    Key keys = Provider.generateKey(keyNum + "");
    this.secretKey = Provider.generateSecretKey(keys.getEncoded());

    byte[] datatemp4 = Provider.encrypt(priKeySelf, (keyNum + "")
      .getBytes());
    byte[] strSend4 = Provider.encrypt(pubKeyOther, datatemp4);

    sendData(strSend4, sendout);

    readin(); // 从文件中读入明文

    byte[] strSend6 = Provider.encrypt(secretKey, orgData
      .getBytes()); // 用会话密钥加密明文
    sendData(strSend6, sendout); // 发送
   } else {
    jta.append("/n获得N1有误,可能不是B用户或解析错误");
   }
   sendout.close();
   sendin.close();
   connect.close();
   // } else {
   // JOptionPane.showMessageDialog(null, "获得N1有误,可能不是B用户或解析错误");
   // }
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }

 /**
  * 当收到会话请求时,调用该函数
  *
  * @param data
  */
 public void dealWith(String data) throws Exception {
  String[] datas = data.split("//"); // 分割收到的数据,IDA//N1
  N2 = rand(); // 生成随机数N2

  byte[] strSend1 = Provider.encrypt(pubKeyOther, (datas[0] + "//" + N2)
    .getBytes());

  sendData(strSend1, receiveout);

  byte[] rec1 = recData(receivein);
  byte[] datatemp1 = Provider.decrypt(priKeySelf, rec1); // N2
  // 确认N2
  if (N2 == Integer.parseInt(new String(datatemp1))) {
   byte[] rec2 = recData(receivein);
   byte[] datatemp2 = Provider.decrypt(priKeySelf, rec2);
   byte[] datatemp3 = Provider.decrypt(pubKeyOther, datatemp2);

   String datatemp4 = new String(datatemp3);

   Key keys = Provider.generateKey(datatemp4);

   this.secretKey = Provider.generateSecretKey(keys.getEncoded());

   byte[] rec3 = recData(receivein);

   byte[] result = Provider.decrypt(secretKey, rec3);

   jta.append("/n收到数据:" + new String(result));
  } else {
   jta.append("/n对方不是A或者N2解释错误");
  }

  receivein.close();
  receiveout.close();
 }

 /**
  * 发起会话请求的线程
  *
  * @author Administrator
  *
  */
 private class SendMsg implements Runnable {
  public void run() {
   // TODO Auto-generated method stub
   working = true;
   jta.append("/n正在发送数据。");
   send();
   working = false;
   jta.append("/n数据发送完成。");

  }
 }

 /**
  * 等待会话请求的线程
  *
  * @author Administrator
  *
  */
 private class WaitForMsg implements Runnable {
  byte[] datatemp1 = null;
  private byte[] rev;

  /**
   * 构造函数
   *
   * @param port
   *            监听的端口号
   */
  public WaitForMsg(int port) {
   try {
    receiveSocket = new ServerSocket(port, 5);
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }

  /**
   * 循环监听会话请求,如果有会话,处理会话
   */
  public void run() {
   // TODO Auto-generated method stub
   while (true) {
    try {
     s = receiveSocket.accept();

     receiveout = new ObjectOutputStream(s.getOutputStream());
     receivein = new ObjectInputStream(s.getInputStream());

     rev = recData(receivein);
     working = true;
     jta.append("/n收到会话请求,正在接收数据.");

     byte[] datatemp1 = Provider.decrypt(priKeySelf, rev);
     dealWith(new String(datatemp1));

     working = false;
    } catch (Exception e1) {
     e1.printStackTrace();
     JOptionPane.showMessageDialog(null, "出错");
     System.exit(0);
    }
   }
  }
 }
}
=======================test.java=================================

package third_hard;

import java.security.KeyPair;
import java.security.interfaces.RSAPublicKey;

import javax.swing.JFrame;

/**
 * 测试类
 *
 * @author Administrator
 *
 */
public class test {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  // 为A,B产生共享的会话主密钥
  try
  {
   KeyPair keyPairA = Provider.generateKeyPair();//生成密钥对A
   KeyPair keyPairB = Provider.generateKeyPair();//生成密钥对B
  
         RSAPublicKey pubKeyA = (RSAPublicKey) keyPairA.getPublic();//公钥
         RSAPublicKey pubKeyB = (RSAPublicKey) keyPairB.getPublic();//密钥
         byte[] pubModBytesA = pubKeyA.getModulus().toByteArray();
         byte[] pubPubExpBytesA = pubKeyA.getPublicExponent().toByteArray();
         byte[] pubModBytesB = pubKeyB.getModulus().toByteArray();
         byte[] pubPubExpBytesB = pubKeyB.getPublicExponent().toByteArray();
         RSAPublicKey pubKeyAs = Provider.generateRSAPublicKey(pubModBytesA,pubPubExpBytesA);
         RSAPublicKey pubKeyBs = Provider.generateRSAPublicKey(pubModBytesB,pubPubExpBytesB);
        
   User u1 = new User(10000, keyPairA, pubKeyBs); // 初始化用户
   User u2 = new User(20000, keyPairB, pubKeyAs); // 初始化用户

   u1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   u2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  }catch(Exception e)
  {
   e.printStackTrace();
  }

 }

}
通信的对称密钥还是通过发送随机数各自生成。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值