zoukankan      html  css  js  c++  java
  • java在非安全网络上建立可信任安全的通道(2/3)

    在不安全的网络环境下进行密钥交互(1/3,前面那一节),容易遭受中间人攻击,什么是中间人攻击,请google it。

    通信的双方必须是相互信任的,在这个基础上再进行密钥协商才是可靠的。那么,如何建立信任关系呢?

    我以前的几篇博文介绍了用如何 用  Java编程方式生成CA证书 以及用CA证书签发客户证书。

    现在假设,Alice和Bob的证书都是被同一个CA atlas签发的(见我前面的博文),那么他们之间如何安全的交互密钥呢?

    Alice:

    • 发送自己的证书Certa;
    • 发送DH 密钥对的公钥PDa;
    • 发送用自己的私钥 对DH公钥的签名Sa。
    Bob与Alice执行相同的步骤,下面是Bob处理Alice发送的东西的步骤:
    • 接收Alice的公钥Certa、DH公钥PDa、和签名Sa
    • 使用CA的证书验证Certa,如果通过,就证明了Alice的证书Certa是合法的。
    • 使用证书Certa验证签名Sa,如果通过,就证明了Certa确实是Alice发送过来的,因为只有Alice用自己的私钥才可以对PDa进行签名。
    Alice和Bob是对等的。
    经过上面的过程,可以看出Alice和Bob在相互信任的基础上交互了DH算法的公钥,即通过这种方式避免了中间人攻击。

    下面该上代码了:

    /**
     * 安全的密钥交互类。
     * 这个交互工具可以校验双方的身份,并对发送的DH公钥进行签名,防止中间者攻击。
     * @author atlas
     * @date 2012-9-6
     */
    public class SecureKeyExchanger extends DHKeyExchanger {
    	/**
    	 * 签名算法
    	 */
    	private static String signAlgorithm = "SHA1withRSA";
    
    	/**
    	 * 此方的私钥
    	 */
    	private PrivateKey privateKey;
    	/**
    	 * 此方的证书
    	 */
    	private Certificate certificate;
    	/**
    	 * 用于校验彼方公钥的CA证书,此证书来自此方的CA或者此方可信任的CA
    	 */
    	private Certificate caCertificate;
    	
    	/**
    	 * 彼方的证书,在DH公钥交换之前进行交互获取的
    	 */
    	private Certificate peerCert;
    	
    	/**
    	 * 
    	 * @param out
    	 * @param in
    	 * @param privateKey 此方的私钥
    	 * @param certificate 此方的证书
    	 * @param caCertificate 用于校验彼方公钥的CA证书,此证书来自此方的CA或者此方可信任的CA
    	 */
    	public SecureKeyExchanger(Pipe pipe,
    			PrivateKey privateKey, Certificate certificate,
    			Certificate caCertificate) {
    		super(pipe);
    		this.privateKey = privateKey;
    		this.certificate = certificate;
    		this.caCertificate = caCertificate;
    	}
    
    	// Send the public key.
    	public void sendPublicKey() throws IOException,
    			CertificateEncodingException {
    		byte[] keyBytes = certificate.getEncoded();
    		write(keyBytes);
    	}
    
    	public void receivePublicKey() throws IOException, SkipException {
    		byte[] keyBytes =read();
    		try {
    			CertificateFactory cf = CertificateFactory.getInstance("X.509");
    			peerCert = cf
    					.generateCertificate(new ByteArrayInputStream(keyBytes));
    			peerCert.verify(caCertificate.getPublicKey());
    		} catch (CertificateException e) {
    			throw new SkipException("Unsupported certificate type X.509", e);
    		} catch (InvalidKeyException e) {
    			throw new SkipException(
    					"Peer's certificate was not invlaid or not signed by current CA.",
    					e);
    		} catch (NoSuchAlgorithmException e) {
    			throw new SkipException("Signature algorithm not supported.", e);
    		} catch (NoSuchProviderException e) {
    			throw new SkipException("No signature Provider.", e);
    		} catch (SignatureException e) {
    			throw new SkipException(
    					"Peer's certificate was not invlaid or not signed by current CA.",
    					e);
    		}
    	}
    
    	@Override
    	public void receiveDHPublicKey() throws IOException, SkipException {
    		// receiver public key
    		receivePublicKey();
    
    		// receive dh public key
    		byte[] publicKeyBytes = read();
    
    		// receive signature of dh public key
    		byte[] sign = read();
    		KeyFactory kf;
    		try {
    			// verify signature using peer certificate
    			Signature sig = Signature.getInstance(signAlgorithm);
    			sig.initVerify(peerCert);
    			sig.verify(sign);
    			kf = KeyFactory.getInstance("DH");
    			X509EncodedKeySpec x509Spec = new X509EncodedKeySpec(publicKeyBytes);
    			peerDHPublicKey = kf.generatePublic(x509Spec);
    		} catch (NoSuchAlgorithmException e) {
    			throw new SkipException("Signature algorithm " + signAlgorithm
    					+ " not supported.", e);
    		} catch (InvalidKeySpecException e) {
    			throw new SkipException("Peer's public key invalid.", e);
    		} catch (InvalidKeyException e) {
    			throw new SkipException("Peer's public key invalid.", e);
    		} catch (SignatureException e) {
    			throw new SkipException("Invalid signature.", e);
    		}
    	}
    
    	@Override
    	public void sendDHPublicKey() throws IOException, SkipException {
    		try {
    			// send public key
    			sendPublicKey();
    			// send dh public key
    			byte[] keyBytes = dhKeyPair.getPublic().getEncoded();
    			write(keyBytes);
    			
    			// sign dh public key using my private key and send the signature
    			Signature sig;
    			sig = Signature.getInstance(signAlgorithm);
    			sig.initSign(privateKey);
    			sig.update(keyBytes);
    			byte[] sign = sig.sign();
    			write(sign);
    		} catch (NoSuchAlgorithmException e) {
    			throw new SkipException("Signature algorithm " + signAlgorithm
    					+ " not supported.", e);
    		} catch (InvalidKeyException e) {
    			throw new SkipException("My private key invalid.", e);
    		} catch (SignatureException e) {
    			throw new SkipException(
    					"Signature exception when sending dh public key.", e);
    		} catch (CertificateEncodingException e) {
    			throw new SkipException("error when sending dh public key.", e);
    		}
    
    	}
    }
     

    测试代码:

    public class KeyInfo {
    	PrivateKey privateKey;
    	Certificate certificate;
    	Certificate caCertificate;
    
    	public KeyInfo(PrivateKey privateKey, Certificate certificate,
    			Certificate caCertificate) {
    		super();
    		this.privateKey = privateKey;
    		this.certificate = certificate;
    		this.caCertificate = caCertificate;
    	}
    
    	public Certificate getCaCertificate() {
    		return caCertificate;
    	}
    
    	public Certificate getCertificate() {
    		return certificate;
    	}
    
    	public PrivateKey getPrivateKey() {
    		return privateKey;
    	}
    }
    public class Server4Alice {
    	public static void main(String[] args) throws Exception {
    		int port = Integer.parseInt("1111");
    		System.out.println(Base64.encode(exchangeFrom(port)));
    	}
    
    	public static byte[] exchangeFrom(int port) throws SkipException,
    			IOException {
    		InputStream file = SkipServer4Alice.class
    				.getResourceAsStream("atlas-alice.jks");
    		KeyInfo key = Reader.read(file, "alice", "alice");
    
    		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 SecureKeyExchanger(pipe,
    				key.getPrivateKey(), key.getCertificate(),
    				key.getCaCertificate());
    		exchanger.exchange();
    		s.close();
    		ss.close();
    		return exchanger.getKey();
    	}
    }
    public class Client4Bob {
    	public static void main(String[] args) throws Exception {
    		String host = "localhost";
    		int port = Integer.parseInt("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 {
    		InputStream file = SkipServer4Alice.class
    				.getResourceAsStream("atlas-bob.jks");
    		KeyInfo key = Reader.read(file, "bob", "bob");
    		Socket s = new Socket(host, port);
    		DataOutputStream out = new DataOutputStream(s.getOutputStream());
    		DataInputStream in = new DataInputStream(s.getInputStream());
    		Pipe pipe = new DataPipe(in, out);
    		KeyExchanger exchanger = new SecureKeyExchanger(pipe,
    				key.getPrivateKey(), key.getCertificate(),
    				key.getCaCertificate());
    		exchanger.exchange();
    		s.close();
    		return exchanger.getKey();
    	}
    }
     

    几个JKS文件:

    atlas-alice.jks:包含一个alice的私钥和证书,证书是用atlas的CA签发的

    atlas-bob.jks:包含一个bob的私钥和证书,证书是用atlas的CA签发的

    CA atlas的证书分别在alice和bob的信任证书列表里面有一个copy

    Reader.read()是个工具方法,负责把jks文件里面的证书信息读取出来:

    public class Reader {
    
    	public static KeyInfo read(InputStream file, String alias, String password) {
    		try {
    			KeyStore store = KeyStore.getInstance("JKS");
    			store.load(file, password.toCharArray());
    			PrivateKeyEntry ke = (PrivateKeyEntry) store.getEntry(alias,
    					new PasswordProtection(password.toCharArray()));
    			KeyInfo info = new KeyInfo(ke.getPrivateKey(), ke.getCertificate(),
    					ke.getCertificateChain()[1]);
    			return info;
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return null;
    	}
    }
  • 相关阅读:
    [na][dhcp]华为DHCP-重要
    [na]win PPTP场景与搭建
    [na]锐起无盘机并发部署多台windows
    [na]wireshark抓包排错-tcp.flags.reset
    [svc]mousedos网络批量部署xp
    [na]诺顿ghost磁盘对刻(备份系统分区或数据分区)
    [na]代理arp导致的问题(路由卷)
    [na]pc加入域认证细节
    【VS开发】【智能语音处理】VS中声音的采集实现
    【VS开发】【智能语音处理】MATLAB 与 音频处理 相关内容摘记
  • 原文地址:https://www.cnblogs.com/cwjcsu/p/8433076.html
Copyright © 2011-2022 走看看