OverTheWire Bandit Level 11 → Level 12 풀이
문제
다음 단계의 암호는 모든 소문자(a-z)와 대문자(A-Z)가 13개 위치만큼 회전된 data.txt 파일에 저장됩니다.
풀이
data.txt의 내용을 확인해보니 문자열들이 나온것을 볼 수 있다. 근데 문제에서는 data.txt파일에 저장된 문자열이 암호의 문자열을 13번째 다음의 알파벳으로 바뀌어 저장한 것임을 알 수 있다.
이러한 암호화 방식을 카이사르암호라고 한다.
(카이사르 암호는 특정 키 값을 각 문자에 더한 값만큼의 문자로 만드는 것이다.)
리눅스의 tr명령어는 문자를 지우거나 바꿔주는 명령어이다. 이 명령어를 이용하여 data.txt의 문자열의 각각의 문자들을 13번째 옆의 문자로 바꾸면 암호가 나올것이다.
옵션이 없는 경우 set1의 문자열을 set2로 바꿔주며 abcdef의 경우 a-f로 지정이 가능하다!
tr [OPTION]... SET1 [SET2]
따라서 A-Za-z의 문자순서를 13번째 다음의 문자인 N-ZA-Mn-za-m로 지정하여 각각 set1 ser2로 tr 명령어를 사용하면
되므로 cat data.txt | tr 'A-Za-z' 'N-ZA-Mn-za-m' 를 입력하면 암호가 5Te8Y4drgCRfCx8ugdwuEX8KFC6k2EUu 임을 알 수 있다.
카이사르 암호 구현
#include <stdio.h>
#include <string.h>
#define ASCII_a 97 //아스키값
#define ASCII_A 65
#define ASCII_z 122
#define ASCII_Z 90
char* encrypCaesar(int count, char str[]) { // 받은 문자열을 카이사르 암호화하여 반환
count = count % 26;
if (count < 0) {
count = 26 + count;
}
for (int i = 0; i < strlen(str); i++) {
if (str[i] == 32) // str[i](문자열 i번째 값)이 ' '(공백) 이면 다음문자로 넘어간다
continue;
if (ASCII_a <= str[i] && str[i] <= ASCII_z) { // 문자가 a-z인 경우
if (str[i] + count > ASCII_z) // 치환한 문자가 문자 아스키 값을 넘어가는 경우
str[i] = (str[i] + count) - (ASCII_z + 1) + ASCII_a; // z를 넘어가면 a로 시작하게 한다
else
str[i] = str[i] + count; // 그외의 경우는 치환한 후 저장
}
else if (ASCII_A <= str[i] && str[i] <= ASCII_Z) { // 문자가 A-Z인 경우
if (str[i] + count > ASCII_Z) // 치환한 문자가 문자 아스키 값을 넘어가는 경우
str[i] = (str[i] + count) - (ASCII_Z + 1) + ASCII_A; //Z를 넘어가면 A로 시작하게 한다
else
str[i] = str[i] + count; // 그외의 경우는 치환한 후 저장
}
else
str[i] = str[i]; // a-zA-Z의 문자가 아닐경우 본래 값 저장
}
return str; //암호화된 문자열 반환
}
void main() {
int count;
char str[100];
char* cryptoStr;
printf("치환할 횟수을 입력하시오. : ");
scanf_s("%d", &count);
getchar();
printf("\n암호화를 수행할 문자열을 입력하시오. : ");
scanf_s("%[^\n]s",&str, sizeof(str));
cryptoStr = encrypCaesar(count, str);
printf("\n암호화: %s", str);
}
카이사르 암호를 c언어로 구현해봤다.
data.txt의 문자열인 Gur cnffjbeq vf 5Gr8L4qetPEsPk8htqjhRK8XSp6x2RHh 을 입력값으로 줘보면
The password is 5Te8Y4drgCRfCx8ugdwuEX8KFc6k2EUu 가 출력된다.