假定作为通讯的双方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();
}
}
}
通信的对称密钥还是通过发送随机数各自生成。