• java在非安全网络上建立可信任安全的通道(1/3)


          看到标题,几乎所有人都会想到SSL,但SSL比较重量级,我想做的是只利用java的JCE体系(不是JSSE)在非安全网络环境下建立起一个可信任的、安全的通道。

          所以这篇博文包括两个主题:可信任和安全。

    这一节只考虑如何交互密钥。下一节(2/3)讨论如何建立信任关系,并在可信关系上交换密钥(防止中间人攻击)。

         非对称密钥不适合做通道加密,通道加密必然使用对称密钥。既然如此,通信的双方(或多方)如何获取一个共同的密钥呢?

          DH算法(Diffie-Hellman)是一种密钥协商算法,不理解原理的可以看这里:http://zh.wikipedia.org/wiki/Diffie-Hellman%E5%AF%86%E9%92%A5%E4%BA%A4%E6%8D%A2

    下面的代码使用Java security api在socket通道上面演示密钥交换:

    参考《Java security,2nd edition》

    核心代码

    public class DHKeyExchanger implements KeyExchanger {
    
    	protected Pipe pipe;
    	protected KeyPair dhKeyPair;
    
    	protected PublicKey peerDHPublicKey;
    
    	private byte[] key;
    
    	/**
    	 * 
    	 * @param pipe 密钥交互管道
    	 */
    	public DHKeyExchanger(Pipe pipe) {
    		this.pipe = pipe;
    	}
    
    	// 初始化DH密钥对
    	protected void init() throws SkipException {
    		try {
    			// Create a Diffie-Hellman key pair.
    			KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH");
    			kpg.initialize(SKIP.DHParameterSpec);
    			dhKeyPair = kpg.genKeyPair();
    		} catch (InvalidAlgorithmParameterException e) {
    			throw new SkipException("Invalid DH algorithm parameter.", e);
    		} catch (NoSuchAlgorithmException e) {
    			throw new SkipException("DH algorithm not supported.", e);
    		}
    	}
    
    	// 发送dh公钥
    	protected void sendDHPublicKey() throws IOException, SkipException {
    		byte[] keyBytes = dhKeyPair.getPublic().getEncoded();
    		write(keyBytes);
    	}
    
    	// 接收对方的dh公钥
    	protected void receiveDHPublicKey() throws IOException, SkipException {
    		byte[] publicKeyBytes = read();
    		KeyFactory kf;
    		try {
    			kf = KeyFactory.getInstance("DH");
    			X509EncodedKeySpec x509Spec = new X509EncodedKeySpec(publicKeyBytes);
    			peerDHPublicKey = kf.generatePublic(x509Spec);
    		} catch (NoSuchAlgorithmException e) {
    			throw new SkipException("DH algorithm not supported.", e);
    		} catch (InvalidKeySpecException e) {
    			throw new SkipException("Invalid public key", e);
    		}
    	}
    
    	// 生成密钥
    	public byte[] generateKey() throws SkipException {
    		KeyAgreement ka;
    		try {
    			ka = KeyAgreement.getInstance("DH");
    			ka.init(dhKeyPair.getPrivate());
    			ka.doPhase(peerDHPublicKey, true);
    			return ka.generateSecret();
    		} catch (NoSuchAlgorithmException e) {
    			throw new SkipException("DH algorithm not supported.", e);
    		} catch (InvalidKeyException e) {
    			throw new SkipException("Invalid private key.", e);
    		}
    	}
    
    	// all in one
    	public void exchange() throws SkipException, IOException {
    		this.init();
    		this.sendDHPublicKey();
    		this.receiveDHPublicKey();
    		this.key = generateKey();
    	}
    
    	// read a byte array
    	protected byte[] read() throws IOException {
    		return pipe.read();
    	}
    
    	// write a byte array
    	protected void write(byte[] bytes) throws IOException {
    		pipe.write(bytes);
    	}
    
    	@Override
    	public byte[] getKey() {
    		return key;
    	}
    }
    public interface KeyExchanger {
    
    	public void exchange() throws SkipException, IOException;
    	/**
    	 * @return 协商好的密钥
    	 */
    	byte[] getKey();
    }
    public class SKIP {
    	// SKIP's 1024 DH parameters
    	private static final String SKIP1024String = "F488FD584E49DBCD20B49DE49107366B336C380D451D0F7C88B31C7C5B2D8EF6"
    			+ "F3C923C043F0A55B188D8EBB558CB85D38D334FD7C175743A31D186CDE33212C"
    			+ "B52AFF3CE1B1294018118D7C84A70A72D686C40319C807297ACA950CD9969FAB"
    			+ "D00A509B0246D3083D66A45D419F9C7CBD894B221926BAABA25EC355E92F78C7";
    	// Modulus
    	private static final BigInteger SKIP1024Modulus = new BigInteger(
    			SKIP1024String, 16);
    	// Base
    	private static final BigInteger SKIP1024Base = BigInteger.valueOf(2);
    	public static final DHParameterSpec DHParameterSpec = new DHParameterSpec(
    			SKIP1024Modulus, SKIP1024Base);
    
    }

    数据交互通道: 

    public interface Pipe {
    	byte[] read() throws IOException;
    
    	void write(byte[] data) throws IOException;
    }
    
    public class DataPipe implements Pipe {
    	DataInput in;
    	DataOutput out;
    
    	public DataPipe(InputStream in, OutputStream out) {
    		super();
    		if (in instanceof DataInputStream) {
    			this.in = (DataInputStream) in;
    		} else {
    			this.in = new DataInputStream(in);
    		}
    		if (out instanceof DataOutputStream) {
    			this.out = (DataOutputStream) out;
    		} else {
    			this.out = new DataOutputStream(out);
    		}
    	}
    
    	@Override
    	public byte[] read() throws IOException {
    		byte[] bytes = new byte[in.readInt()];
    		in.readFully(bytes);
    		return bytes;
    	}
    
    	@Override
    	public void write(byte[] data) throws IOException {
    		out.writeInt(data.length);
    		out.write(data);
    	}
    
    }

    测试代码:

    public class Client {
    	public static void main(String[] args) throws Exception {
    		String host = "localhost";
    		int port =1111;
    		// Open the network connection.
    		byte[] key = exchangeFrom(host, port);
    		System.out.println(Base64.encode(key));
    	}
    
    	public static byte[] exchangeFrom(String host, int port)
    			throws SkipException, IOException {
    		Socket s = new Socket(host, port);
    		Pipe pipe = new DataPipe(s.getInputStream(), s.getOutputStream());
    		KeyExchanger exchanger = new DHKeyExchanger(pipe);
    		exchanger.exchange();
    		s.close();
    		return exchanger.getKey();
    	}
    }
    //
    public class Server {
    	public static void main(String[] args) throws Exception {
    		System.out.println(Base64.encode(exchangeFrom(1111)));
    	}
    	
    
    	public static byte[] exchangeFrom(int port)
    			throws SkipException, IOException {
    		ServerSocket ss = new ServerSocket(port);
    		// Wait for a connection.
    		Socket s = ss.accept();
    		DataOutputStream out = new DataOutputStream(s.getOutputStream());
    		DataInputStream in = new DataInputStream(s.getInputStream());
    		Pipe pipe = new DataPipe(in, out);
    		KeyExchanger exchanger = new DHKeyExchanger(pipe);
    		exchanger.exchange();
    		s.close();
    		ss.close();
    		return exchanger.getKey();
    	}
    }
    
    
     
  • 相关阅读:
    17个Web前端开发工程师必看的国外网站
    CSS 绘制三角形气泡框
    Javascript冒泡事件
    页面文本框的只读属性readonly的设置与使用focus-blur事件方法的区别
    javascript中的类型的准确检测
    认识Console,调试Javascript
    仿美团页面
    EDM开发之四:错误记录
    EDM开发之一:系统概述
    EDM开发之二:SMTP服务器
  • 原文地址:https://www.cnblogs.com/cwjcsu/p/8433077.html
Copyright © 2020-2023  润新知