2017-12-28 10 views
0

클라이언트와 서버간에 JSON 메시지를 암호화/해독하는 두 가지 방법이 있습니다. 서버에는 한 쌍의 RSA 키 (개인 키 하나와 공용 키)가 있으며 클라이언트도 마찬가지입니다. 또한 채널 자체가 안전하지 않기 때문에 JSON 메시지를 암호화하는 데 사용되는 통신을 처음 설정할 때 생성 된 대칭 세션 키에 액세스 할 수 있습니다. 클라이언트는 AES 키 (세션 키)를 생성 한 다음 서버의 공개 키 (모두에게 알려진)를 암호화한 다음이를 서버로 전송합니다. 서버는 세션 키를 해독하고 클라이언트 ID 아래의 HashMap에 저장합니다.JAVA - 일치하지 않는 AES 키 길이

그러나 문제는 다음과 같습니다. 전송하기 전에 키 길이를 확인했으며 길이는 16 바이트입니다. 서버가 암호화 된 세션 키를 받고 해독하면 24 바이트 길이입니다. 암호문이나 암호 해독 중일 때 뭔가 잘못됐다고 가정합니다. 이것은 클라이언트가 요청을 (암호화 된 JSON 메시지의 형태로) 보내기를 시작하려고 할 때 키의 크기가 잘못 되었기 때문에 서버가 암호를 해독하고 읽을 수 없기 때문입니다 (java.security.InvalidKeyException : Illegal key size 또는 기본 매개 변수).

사이퍼/방법은 아래에 게시되어 해독 :

encoder/ decoder
public String cipher(Key key, String alg, String msg){ 
    try { 
     Cipher c = Cipher.getInstance(alg); 
     c.init(Cipher.ENCRYPT_MODE, key); 
     return encoder.encodeToString(c.doFinal(msg.getBytes("UTF-8"))); 
    } catch (IllegalBlockSizeException e) { 
     (...) 
    } 
} 

java.util.Base64에서입니다.

public String decipher(Key key, String alg, String msg){ 
    try { 
     Cipher c = Cipher.getInstance(alg); 
     c.init(Cipher.DECRYPT_MODE,key); 
     return new String(c.doFinal(decoder.decode(msg)), "UTF-8"); 
    } catch (IllegalBlockSizeException e) { 
     (...) 
    } 
} 

클라이언트 암호화 세션 키 전송 :

SecretKey sk = KeyGenerator.getInstance("AES/CBC/PKCS5Padding").generateKey(); 

System.out.println(sk.getEncoded().length) //length = 16 bytes 

String sessionKey = cipher(client.getServerPublicKey(), 
    "RSA/ECB/PKCS5Padding", encoder.encodeToString(sk.getEncoded())); 

printWriter.write("{(...), \"key\":\"" + sessionKey + "\"}"); 

서버 암호화 된 세션 키를 받고 HashMap에 저장 :

byte[] aux = decipher(registry.getServerPrivateKey(), 
    "RSA/ECB/PKCS5Padding", data.get("key").toString().replace("\"", "")) 
     .getBytes("UTF-8"); 

System.out.println(aux.length) //length = 24 bytes 

registry.addSession(..., new SecretKeySpec(aux, 0, aux.length, "AES")); 

내가 시도 다른 알고리즘을 다른 패딩 ,하지만 오류가 어디 있는지 알 수는 없습니다.

답변

1

당신은 인코딩 base64로있는 키 이전이 문 암호화 :

String sessionKey = cipher(client.getServerPublicKey(), 
    "RSA/ECB/PKCS5Padding", encoder.encodeToString(sk.getEncoded())); 

..

가 24 문자 긴베이스 64 표현으로 16 바이트 키를 만들기. 암호화가 바이너리 데이터를 완벽하게 처리 할 수 ​​있기 때문에 암호화하기 전에 키를 base64로 인코딩 할 필요가 없습니다.

public byte[] decipher(Key key, String alg, String msg){ 
    try { 
     Cipher c = Cipher.getInstance(alg); 
     c.init(Cipher.DECRYPT_MODE,key); 
     return c.doFinal(decoder.decode(msg)); 
    } catch (IllegalBlockSizeException e) { 
     (...) 
    } 
} 
+0

이 : 또한, 같은뿐만 아니라 이진하기 위해 decipher(..)을 변경

String sessionKey = cipher(client.getServerPublicKey(), "RSA/ECB/PKCS5Padding", sk.getEncoded()); 

을 동시에 byte[]

public String cipher(Key key, String alg, byte[] msg){ try { Cipher c = Cipher.getInstance(alg); c.init(Cipher.ENCRYPT_MODE, key); return encoder.encodeToString(c.doFinal(msg)); } catch (IllegalBlockSizeException e) { (...) } } 

로 MSG를 허용하도록 cipher(..) 메도 변경이와 시도 확실하게 핵심 크기 문제를 해결했습니다. 이제 클라이언트 측과 서버 측 모두 16 바이트입니다. 감사합니다! 그'encoder.encodeToString (sk.getEncoded())'는 제가 시도한 이전 구현의 잔재였습니다. –