JAva-信頼性の高い安全なチャネルを非安全なネットワーク上に確立(1/3)
7123 ワード
タイトルを見ると、ほとんどの人がSSLを思い浮かべますが、SSLは比較的重量級で、javaのJCEシステム(JSSEではありません)だけを利用して非安全なネットワーク環境の下で信頼できる、安全な通路を構築したいと思っています.
だから、このブログには2つのテーマが含まれています.信頼性と安全です.
このセクションでは、キーをインタラクティブにする方法だけを考慮します.次のセクション(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,2 nd edition』
コアコード
データインタラクティブチャネル:
テストコード:
だから、このブログには2つのテーマが含まれています.信頼性と安全です.
このセクションでは、キーをインタラクティブにする方法だけを考慮します.次のセクション(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,2 nd 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();
}
}