대칭키를 이용한 암호화와 복호화
지난글 에서는 서로 다른 키를 사용하는 암호화와 복호화, 즉 비대칭 암호화(asymmetric encryption)에 관해 설명했다. 하지만 암호화와 복호화는 대칭적으로 작업할 수도 있다. 이 글에서 데이터를 암호화하고 복호화하는데 같은 키를 사용하고 있는 예를 볼 수 있다. 양쪽 다 동일한 키를 사용하기 때문에 복호화는 암호화 과정의 일부를 역으로 적용하면 된다. Blowfish 알고리즘이 대칭 키의 한 예이다. Blowfish 알고리즘은 Java Cryptography Extension (JCE)에 의해 지원되고 javax.crypto.*
packages에서 적절한 APIs를 찾을 수가 있다. 현재 JCE에 의해 지원되는 암호 알고리즘(cipher algorithm)은 Blowfish뿐만 아니라, Digital Encryption Standard (DES), Triple DES Encryption (DESede), Password-based encryption algorithm (PBEWithMD5AndDES)이 있다.
대칭 키 알고리즘은 비대칭 키 알고리즘보다 훨씬 빠른 경향이 있다. 게다가 첫번째 글에서 본 것과 같이 암호화될 수 있는 텍스트의 사이즈가 공개 키와 비밀 키를 생성할 때 사용되었던 두개의 소인수 곱의 크기에 의해 좌우된다. 하지만 대칭 키 알고리즘을 사용하면 암호화하고자 하는 대상의 전체 크기에 전혀 제한을 받지 않는다. 대칭 암호 알고리즘(symmetric cipher algorithms)의 종류에 따라 다르지만, 전제 입력 사이즈는 블록 사이즈의 배수여야하고 패딩(padding)이 요구될 수도 있다. 대칭 키와 관련한 문제는 이 키들이 암호화나 복호화에 관련된 파티내에서는 공유되어야만 한다는 데에 있다. 그렇기 때문에 차단이 되거나 공인되지 않은 사용자가 공유하는 등의 문제가 생길 수 있다.
대칭 키를 생성하는 것은 키 쌍을 생성했던 것과 매우 흡사하다. KeyGenerator
클래스의 factory 메소드를 사용하고 스트링값을 알고리즘에 대입하자. generateKey()
메소드를 호출하면 KeyPair
인터페이스 대신 Key
인터페이스를 구현하는 객체를 되받을 수 있다.
SecretKey key =
KeyGenerator.getInstance("DES").generateKey();
다음으로 Cipher
를 생성하는데, 이는 JCE를 이용할 때 편리하다. 애플리케이션을 바꿀 필요 없이 서로 다른 제공자의 이점을 취하기 위해서 Cipher
클래스의 factory 메소드를 재사용하자. 이하의 방법으로 Cipher
를 생성한다.
Cipher cipher = Cipher.getInstance("DES");
는 바이트 어레이 형태로 넘겨진 데이터를 암호화 혹은 복호화하는데 사용된다. 어떤 동작이 호출될지를 지정하는
Cipherinit()
과 그 연산을 실행하는 doFinal()
메소드가 꼭 사용해야만 하는 필수 메소드들이다. 가령, 다음 2줄의 코딩은 바이트 어레이를 암호화하기 위해 생성한 textBytes
라고 불리는 cipher
와 key
인스턴스를 사용하고 있다. 결과는 encryptedBytes
라고 불리는 바이트 어레이 내에 저장된다.
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes =
cipher.doFinal( textBytes );
다음 프로그램은 위의 값을 모으면서 입력 스트링을 받은 후에 그것을 암호화한다. 그리고나서 암호화된 스트링은 다시 복호화된다.
-
import javax.crypto.Cipher;
-
import javax.crypto.BadPaddingException;
-
import javax.crypto.IllegalBlockSizeException;
-
import javax.crypto.KeyGenerator;
-
import java.security.Key;
-
import java.security.InvalidKeyException;
-
-
public class LocalEncrypter {
-
-
private static Cipher cipher = null;
-
-
key = KeyGenerator.getInstance(algorithm).generateKey();
-
cipher = Cipher.getInstance(algorithm);
-
}
-
-
setUp();
-
if (args.length !=1) {
-
"USAGE: java LocalEncrypter " +
-
"[String]");
-
}
-
byte[] encryptionBytes = null;
-
encryptionBytes = encrypt(input);
-
"Recovered: " + decrypt(encryptionBytes));
-
}
-
-
throws InvalidKeyException,
-
BadPaddingException,
-
IllegalBlockSizeException {
-
cipher.init(Cipher.ENCRYPT_MODE, key);
-
byte[] inputBytes = input.getBytes();
-
return cipher.doFinal(inputBytes);
-
}
-
-
throws InvalidKeyException,
-
BadPaddingException,
-
IllegalBlockSizeException {
-
cipher.init(Cipher.DECRYPT_MODE, key);
-
byte[] recoveredBytes =
-
cipher.doFinal(encryptionBytes);
-
String recovered =
-
return recovered;
-
}
-
}
커맨드 라인의 파라미터로 어떤 텍스트나 입력할 수 있다. 가령, 커맨드 라인에 다음을 입력하면,
java LocalEncrypter "Whatever phrase we would like to
input at this point"
이하의 출력값을 보게 된다.
Entered: Whatever phrase we would like to
input at this point
Recovered: Whatever phrase we would like to
input at this point
위의 예에서 암호화와 복호화 모두 동일한 Key
객체를 사용해서 이뤄졌다. 암호화와 복호화는 대게 서로 다른 버츄얼 머신에서 발생하기 때문에 안전하게 키를 전송할 수 있는 메소드가 필요하다.
첫번째 글에서 비대칭 암호 알고리즘을 위한 키 쌍을 생성하는 방법을 공부했고, 두번째 글에서는 대칭 키를 사용하는 방법을 살펴보았다. 하지만 비대칭 키와 대칭 키를 결합해서 사용하는 또 다른 테크닉이 있다. 이 기법은 임의대로 대칭 키를 선택해서 데이터를 암호화하는데 사용한다. 그리고는 다른 파티의 공개 키를 이용해서 대칭 키 그 자체가 암호화된다. 그러면 받는 사람은 대칭 키를 암호화하기 위해서 그들의 비밀 키를 이용하고 메시지를 복호화하기 위해 복호화된 키를 이용한다. 비대칭 기법에서 사용되는 모듈러스는 대칭 키를 암호화할 정도의 크기만 되면 된다. 대칭 키는 단일 전송을 위해서 사용된 후 제거된다. 이러한 방법으로 각각의 타입의 단점이 보완된다. 각 주제에 대한 자세한 정보는 다음을 참고하기 바란다.
DES Encryption
- Triple DES
- AES encryption (FIPS-197)- DES의 대안으로 제시되었다.
- Blowfish