1. 시저 암호화란?
매우 간단한 치환 암호화이다. 암호화 하고자 하는 plain text를 알파벳 순서 기준으로 일정 거리만큼 밀어서 치환하는 알고리즘을 사용한다.
그림을 보면 더 설명할 것이 없을 정도로 쉽다.
알파벳은 A B C D ... X Y Z까지 순서를 가진다.
2. 초간단 실습
파일의 내용을 줄 단위로 읽어서, 시저암호화를 한 뒤 저장하는 자바 프로그램을 작성하고자 한다.
2-1) 실제 암호/복호화를 하는 기능
CaesarEncryption 클래스는 실제 암호화를 하는 encrypt(), decrypt() 메소드를 작성했다.
public final class CaesarEncryption {
private final int distance;
CaesarEncryption(int distance) {
this.distance = distance;
}
public String encrypt(String plain) {
StringBuilder cipher = new StringBuilder();
for (Character c : plain.toCharArray()) {
cipher.append((char) ((int) c + distance));
}
return cipher.toString();
}
public String decrypt(String cipher) {
StringBuilder plain = new StringBuilder();
for (Character c : cipher.toCharArray()) {
plain.append((char) ((int) c - distance));
}
return plain.toString();
}
}
- 생성자로 이 CaesarEncryption를 이용해 암호화를 할 때, 알파벳 몇 칸을 미룰 것인지 설정할 수 있도록 했다. 해당 값은 "distance"라는 변수에 저장하도록 했는데, 필드와 클래스 자체를 final로 두어 외부에서 값의 접근이나 수정을 불가하게 만들었다.
- encrypt()와 decrypt()는 모두 StringBuilder을 이용했다.
- encrypt()에서는 암호화하고자 하는 문자열을 받아 아스키 코드 단위로 distance 거리만큼 "밀었다". decrypt()는 같은 과정을 정확히 반대로 진행했다.
- Character 클래스 타입을 int로 형변환하면 아스키 코드로 변환됨을 이용했다. 따라서 이 메소드는 알파벳 범위 안의 완전한 카이사르 암호화를 구현했다기보단, 아스키 코드 기준의 치환 암호화를 했다고 보는 것이 더 맞겠다.
2-2) 파일의 내용을 읽고 쓰는 기능
내부 구성으로 CaesarEncryption 클래스 객체를 두고 있다. IO를 위해 BufferedReader / BufferedWriter를 사용했다.
public class CaesarFile {
private CaesarEncryption caesarEncryption;
CaesarFile(CaesarEncryption caesarEncryption) {
this.caesarEncryption = caesarEncryption;
}
void encrypt(String in, String out) {
try (BufferedReader reader = new BufferedReader(new FileReader(in));
BufferedWriter writer = new BufferedWriter(new FileWriter(out))) {
String line = "";
while ((line = reader.readLine()) != null) {
writer.write(caesarEncryption.encrypt(line));
writer.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}
void decrypt(String in, String out) {
try (BufferedReader reader = new BufferedReader(new FileReader(in));
BufferedWriter writer = new BufferedWriter(new FileWriter(out))) {
String line = "";
while ((line = reader.readLine()) != null) {
writer.write(caesarEncryption.decrypt(line));
writer.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
- encrypt() : 암호화할 파일의 이름, 암호화해서 저장할 파일의 이름을 각각 인자로 받는다. readLine() 메소드를 통해 줄 단위로 파일 내용을 읽고, 해당 line 문자열을 그대로 CaesarEncryption.encrypt()에 보낸 결과를 저장했다.
- decrypt() : 암호화된 파일의 이름, 복호화해서 저장할 파일의 이름을 각각 인자로 받는다. encrypt()와 정확히 같은 과정이지만 호출하는 메소드가 CaesarEncryption.decrypt()라는 차이가 있다.
2-3) 실행해보기
클라이언트 main() 메소드를 작성했다.
public class Client {
public static void main(String[] args) {
CaesarEncryption caesarEncryption = new CaesarEncryption(3);
CaesarFile caesarFile = new CaesarFile(caesarEncryption);
caesarFile.encrypt("hello.txt","encrypt.txt");
caesarFile.decrypt("encrypt.txt","decrypt.txt");
}
}
- 카이사르 암호화에 사용할 distance는 3이다. 아스키 코드 기준으로 3 거리만큼 떨어진 문자로 치환 암호화를 할 것이다.
- 인풋 파일 이름은 "hello.txt"이다. 암호화 결과는 "encrypt.txt"에 저장된다.
- 암호화된 파일 "encrypt.txt"를 복호화해서 "decrypt.txt"에 다시 저장할 것이다.
그렇게 되면 "hello.txt"와 "decrypt.txt"에 저장된 파일 내용은 같아야 할 것이다! 실행해보자.
hello.txt :
안녕! 내 이름은 부추야.
나이는.. 비밀이야. 20대라는 것만 알려줄게.
지금 시저 ? 카이사르 ? 어떻게 읽어야할지 모르겠는데, 아무튼 그걸 이용해서 암호화하는 자바 코드를 작성했어.
그 실습을 위한 input 파일이야!
이 내용들은 암호화되어 저장될거야.
한 번 확인해보자! ^^
encrypt.txt :
앋녘$#낷#읷릇읃#붃춗앿1
낛읷늗11#빇밃읷앿1#53댃띿늗#겆맏#앏렧줇겏1
짃긋#싟젃#B#칷읷삯륷#B#얷떾겏#잀얷앿핣짃#몫륷겣늗덳/#앇묷튿#귻걻#읷욬핷섟#앗혻홗핛늗#잓밗#콗듟륿#잔섴햋얷1
귻#싧슸읇#윇핟#lqsxw#팏읿읷앿$
읷#낷욬듧읃#앗혻홗됛얷#젃잨됣걳앿1
핟#벋#환읻핷볷잓$#aa
decrypt.txt:
안녕! 내 이름은 부추야.
나이는.. 비밀이야. 20대라는 것만 알려줄게.
지금 시저 ? 카이사르 ? 어떻게 읽어야할지 모르겠는데, 아무튼 그걸 이용해서 암호화하는 자바 코드를 작성했어.
그 실습을 위한 input 파일이야!
이 내용들은 암호화되어 저장될거야.
한 번 확인해보자! ^^
실행은 잘 된 듯 하지만, distance 값이 3으로 짧은 탓 + 자모자 방식을 택하는 한글을 아스키코드로 할당했을 때 가까운 거리의 글자는 많이 닮아있다는 탓 덕분에 encrypt 파일을 봐도 원본 내용이 쉽게 노출되는듯 ^ㅆ^;;
REFERENCE
https://ko.wikipedia.org/wiki/%EC%B9%B4%EC%9D%B4%EC%82%AC%EB%A5%B4_%EC%95%94%ED%98%B8