package org.rzo.netty.ahessian.crypto; import java.security.Key; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.SecureRandom; import javax.crypto.Cipher; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.rzo.netty.ahessian.log.OutLogger; public class ServerCryptoFilter extends SimpleChannelHandler implements CryptoConstants { KeyPair _serverKeyPair; Key _clientKey; ChannelStateEvent _connectedEvent; private StreamCipher _encodeCipher; private StreamCipher _decodeCipher; private byte[] _cryptedIvKeyMessage; private int _bytesRead; @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // send public key sendByteArray(ctx, getPublicKeyEncoded()); // remember this event, so that we can propagate it to the rest of the pipeline once we have // the client's secret key _connectedEvent = e; } private void sendByteArray(ChannelHandlerContext ctx, byte[] buffer) { try { Channel channel = ctx.getChannel(); ChannelFuture future = Channels.future(ctx.getChannel()); ChannelBuffer b = ChannelBuffers.dynamicBuffer(); // first send encoded key bytes size b.writeInt(buffer.length); // then the public key b.writeBytes(buffer); Channels.write(ctx, future, b); } catch (Exception e) { e.printStackTrace(); } } byte[] getPublicKeyEncoded() { try { // generate a key pair SecureRandom random = new SecureRandom(); KeyPairGenerator generator = KeyPairGenerator.getInstance(ASYM_KEY_TYPE); generator.initialize(ASYM_KEY_SIZE, random); _serverKeyPair = generator.generateKeyPair(); Key pubKey = _serverKeyPair.getPublic(); return pubKey.getEncoded(); } catch (Exception e) { e.printStackTrace(); } return null; } @Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) throws Exception { // have we sent our secret key ? if (_decodeCipher != null) { MessageEvent m = Util.code(_decodeCipher, e, true); ctx.sendUpstream(m); } else { ChannelBuffer b = (ChannelBuffer) e.getMessage(); // is this our first message ? if (_cryptedIvKeyMessage == null) { int size = b.readInt(); // consistency check, so we do not get an out of memory exception if (size > 1024) { ctx.getChannel().close(); return; } _cryptedIvKeyMessage = new byte[size]; } // readin the client's secret key and iv int available = b.readableBytes(); int toRead = Math.min(_cryptedIvKeyMessage.length - _bytesRead, available); b.readBytes(_cryptedIvKeyMessage, _bytesRead, toRead); _bytesRead += toRead; // we have completed receiption ? if (_bytesRead == _cryptedIvKeyMessage.length) { boolean ok = false; try { createCiphers(); ok = true; } catch (Exception ex) { ex.printStackTrace(); ctx.getChannel().close(); } // inform pipline that we are ready for encrypted communication if (ok) ctx.sendUpstream(_connectedEvent); } } } private void createCiphers() throws Exception { // first decode the received data String type = "".equals(ASYM_CIPHER_TYPE) ? ASYM_KEY_TYPE : ASYM_KEY_TYPE+"/"+ASYM_CIPHER_TYPE; Cipher asymCipher = Cipher.getInstance(type); asymCipher.init(Cipher.DECRYPT_MODE, _serverKeyPair.getPrivate()); byte[] data = asymCipher.doFinal(_cryptedIvKeyMessage); System.out.println("received iv+key: "+OutLogger.asString(data)); byte[] iv = new byte[SYM_IV_SIZE]; System.arraycopy(data, data.length-(SYM_IV_SIZE+SYM_KEY_SIZE), iv, 0, iv.length); System.out.println("received iv: "+OutLogger.asString(iv)); byte[] key = new byte[SYM_KEY_SIZE]; System.arraycopy(data, data.length-SYM_KEY_SIZE, key, 0, key.length); System.out.println("received key: "+OutLogger.asString(key)); _encodeCipher = StreamCipherFactory.createCipher(SYM_KEY_TYPE); _encodeCipher.engineInitEncrypt(key, iv); _decodeCipher = StreamCipherFactory.createCipher(SYM_KEY_TYPE); _decodeCipher.engineInitDecrypt(key, iv); } @Override public void writeRequested( ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (_encodeCipher != null) { MessageEvent m = Util.code(_encodeCipher, e, false); ctx.sendDownstream(m); } } public static void main(String[] args) { ServerCryptoFilter h = new ServerCryptoFilter(); h.getPublicKeyEncoded(); } }