userDisconnected
@Override
public void userDisconnected(Client client) {
// TODO Auto-generated method stub
System.out.println("Connection disconnected " + client.getIPPort());
}
userDisconnected 는 서버에서 클라이언트 연결이 어떠한 이유로든 끊겼을 때 호출되는 부분입니다. 로그인 오류에 의해 연결이 중지 된 경우는 userDisconnected 에 의해 처리자가 호출되지 않습니다. 매개변수에 Client 객체를 같이 넘김으로써 어떤 클라이언트가 연결 스트림을 종료했는지 알 수 있습니다.
userConnected
@Override
public void userConnected(Client client) {
// TODO Auto-generated method stub
System.out.println("Connection connected " + client.getIPPort());
}
userConnected는 클라이언트 세션의 연결이 수락되었을 때 호출합니다. 단지 네트워크 TCP 스트림이 접속되면 콜백되는 함수입니다.
userLoginError
@Override
public void userLoginError(Client client) {
// TODO Auto-generated method stub
System.out.println("Connection login error " + client.getIPPort());
}
userLoginError는 서버에 접속한 클라이언트와의 패킷을 주고 받을 때 잘못된 암호화 정보로 접속을 하는 경우 발생합니다. 서버에 클라이언트가 접속을 하였더라도 최초 암호화 절차가 성사되지 않으면 Login 할 수 없으며, 이 경우 LoginError 됩니다.
userLogined
@Override
public void userLogined(EncryptedClient client) {
// TODO Auto-generated method stub
System.out.println("Connection logined " + client.getIPPort());
}
userLogined는 클라이언트가 서버에 접속하고 성공적으로 암호키를 교환하고 인증이 성사되면 호출됩니다. 이 때 부터 본격적으로 라이브러리를 활용하여 클라이언트와 안전한 암호화 통신을 수행할 수 있습니다.
packetQueueReceived
@Override
public void packetQueueReceived(EncryptedClient client, ByteWrapper byteWrapper) {
// TODO Auto-generated method stub
System.out.println("Connection data receive " + client.getIPPort() + " : " + new ByteToRawString(byteWrapper.getBuffer()));
}
});
packetQueueReceived는 클라이언트가 암호화된 메시지를 보내왔을 때 해독하여 알려주는 콜백 함수입니다. 이 메소드로 넘어오는 매개변수를 통해 해독된 바이트를 바로 받아볼 수 있기 때문에 라이브러리를 사용하는 입장에서는 암호화를 처리하거나 복호를 처리 할 필요가 전혀 없습니다. 모든 것은 라이브러리를 통해 처리됩니다. 이 때 Client 정보와 같이 넘어옴으로써 어떤 클라이언트가 어떤 데이터를 보냈는지 분류하여 확인할 수 있습니다.
클라이언트측 라이브러리
서버 라이브러리를 통해 서버를 구축한 경우 클라이언트 라이브러리를 통해 암호화된 서버에 접속하고 통신할 수 있도록 구현하였습니다.
connected
@Override
public void connected() {
// TODO Auto-generated method stub
System.out.println("서버 접속 완료.");
}
connected는 서버에 접속한 경우 콜백합니다. 다만 어떤 서버든 tcp 연결에 성공하면 콜백되는 함수입니다.
disconnected
@Override
public void disconnected() {
// TODO Auto-generated method stub
System.out.println("연결 끊김.");
}
disconnected는 서버와의 연결이 종료된 경우 호출되는 부분입니다. 실제 데이터를 통신하다 서버와의 연결이 끊기는 경우 호출됩니다.
logined
@Override
public void logined() {
// TODO Auto-generated method stub
System.out.println("서버에 로그인 했습니다.");
}
logined는 서버에 로그인된 경우 콜백하는 함수입니다. 로그인을 했다는 것은 암호화 정보를 성공적으로 주고 받았다는 의미이며 인증을 성사했다는 것을 의미합니다.
loginError
@Override
public void loginError() {
// TODO Auto-generated method stub
System.out.println("로그인 오류.");
}
loginError은 암호 정보를 송수신하는 로그인 작업 중 오류가 발생한 경우 호출됩니다.
packetReceived
@Override
public void packetReceived(ByteWrapper bytes) {
// TODO Auto-generated method stub
System.out.println("데이터 수신 : " + bytes.getBuffer().length+ ": " + new ByteToRawString(bytes.getBuffer()).toString());
}
packetReceived는 암호화 데이터의 인증 성사 작업인 로그인이 완료된 후 암호화된 데이터가 들어오는 경우 복호화된 값을 반환합니다.
특이점
client.getClientMemory().setPublicKey("GfMA0GC...");
기본적으로 모든 암호 통신의 기본은 암호키라고 생각합니다. 원격 서버와 클라이언트가 안전하게 통신을 하기 위해서는 서로간의 동일한 암호키를 가지고 있어야 하는데 동일한 암호키를 가지기 위해서는 서로간 암호키를 교환하는 작업이 필요합니다. 하지만 기본적으로 암호키를 교환하기 위해 평문 통신을 통해 전송하게 되는 경우 중간자 공격 또는 패킷 스니핑에 의해 암호키가 노출 또는 유출될 우려가 존재합니다. 그렇기 때문에 두 접속 세션이 일면식이 있는 경우 미리 만나서... 비밀키를 교환하는 방법으로 암호화를 성사할 수 있습니다만... 네트워크에서는 기본적으로 서버와 접속자의 일면식이 전혀 없는 익명성이 강조되기 때문에 평문 통신 환경에서 안전하게 암호키를 전달할 수 있어야 합니다. 그러기 위해서는 RSA 단방향 암호화 방식을 활용하여 안전하게 키를 전송할 수 있지만 이 중간자 공격 기법을 활용하여 위조된 단방향 암호키로 실제 키를 받아내서 데이터를 중계할 수 있다는 문제가 존재합니다. 이를 방지하기 위해서는 신뢰할 수 있는 루트인증서를 활용하여 인증된 공개키인지 확인하는 작업이 필요하지만, 이 도구는 기본적으로 내부 또는 개인용임을 고려하여 공개키를 직접 검증하는식으로 구현하였습니다. 서버에서 제공한 공개키와 사전에 배포된 공개가 일치하지 않는 경우 위조된 서버로 판단하며, 공개키가 일치하는 경우만 안전하게 소켓 통신을 수행합니다. 이로써 접속자를 모르는 상황이라고 하더라도 인증된 서버에 접속함으로써 안전하게 AES 암호키를 교환하고 그 후 AES 암호키로 암호화된 데이터를 송수신하며 안전하게 데이터를 보호합니다. 특히 데이터는 IV 벡터를 랜덤 난수로 활용하여 같은 데이터에 대해서도 유추할 수 없도록 차단하는식으로 구현하였습니다. (기본 방식)
오우 쓰고나니까 길다
사용예