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;

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值