시저 암호는 암호학에서 가장 오래되고 간단한 암호 중 하나로, 로마 황제 카이사르가 사용한 암호화 기법입니다. 시저 암호는 알파벳 문자를 일정한 거리만큼 밀어서 다른 문자로 바꾸는 치환 암호(substitution cipher)의 가장 기본적인 형태입니다.
예를 들어, 시프트(shift) 값이 3인 경우, A는 D로, B는 E로, C는 F로 암호화됩니다. 시저 암호는 이러한 원리를 사용해 평문을 암호문으로 바꾸고 복호화하는 과정을 거칩니다.
C 언어로 시저 암호 구현하기
다음은 C 언어를 사용하여 시저 암호를 구현한 코드입니다. 이 코드는 사용자로부터 문자열을 입력 받고, 시저 암호로 암호화한 후 다시 복호화하는 기능을 수행합니다.
코드를 나눠서 설명해드리겠습니다.
함수 원형 선언
#include <stdio.h>
#include <ctype.h>
// 시저 암호화 함수 원형 선언
void caesar_cipher(char str[], int shift);
// 시저 복호화 함수 원형 선언
void caesar_decipher(char str[], int shift);
헤더파일을 상단에 추가해줍니다. ctype.h는 대소문자를 구분하기위한 isalpha 함수를 사용하기위해 선언해줍니다.
일단 암호화와 복호화에서 사용될 함수인 caesar_cipher(암호화)함수와 caesear_decipher(복호화)함수 원형을 main()함수위에 선언해줍니다. 함수원형을 먼저 선언하는 이유는 해당글을 참고해주세요.
변수 생성
int main() {
char input[100]; //평문을 입력받을 변수
int shift; //알파벳 이동할 횟수
}
main()함수에 input[100], shift 변수를 선언해줍니다. input[100] 에는 문자열을 입력받을 변수, shift에는 알파벳을 이동하여 치환할 횟수를 입력받게 됩니다.
평문 입력받기
int main() {
char input[100]; //평문을 입력받을 변수
int shift; //알파벳 이동할 횟수
// 사용자로부터 문자열 입력 받음
printf("문자열을 입력해주세요: ");
fgets(input, sizeof(input), stdin);
}
fgets() 함수를 사용하여 사용자로부터 암호활 문자열을 입력받습니다. 이때 sizeof(input)으로 최대 100글자를 받아올 수 있습니다. 이후 문자열은 stdin에 남아있게 됩니다.
이동횟수 입력받기
int main() {
char input[100]; //평문을 입력받을 변수
int shift; //알파벳 이동할 횟수
// 사용자로부터 문자열 입력 받음
printf("문자열을 입력해주세요: ");
fgets(input, sizeof(input), stdin);
// 사용자로부터 시프트 값 입력 받음
printf("시저 암호의 이동 횟수를 입력해주세요: ");
scanf_s("%d", &shift);
}
scanf_s 함수는 입력 스트림에서 지정된 서식에 맞게 값을 읽어오는 함수입니다. 서식문자(%d)를 사용하면, 사용자로부터 정수형 데이터를 입력 받아 변수 shift에 저장합니다.
암호화,복호화 함수 호출
#include <stdio.h>
#include <ctype.h>
// 시저 암호화 함수 원형 선언
void caesar_cipher(char str[], int shift);
// 시저 복호화 함수 원형 선언
void caesar_decipher(char str[], int shift);
int main() {
char input[100]; //평문을 입력받을 변수
int shift; //알파벳 이동할 횟수
// 사용자로부터 문자열 입력 받음
printf("문자열을 입력해주세요: ");
fgets(input, sizeof(input), stdin);
// 사용자로부터 시프트 값 입력 받음
printf("시저 암호의 이동 횟수를 입력해주세요: ");
scanf_s("%d", &shift);
// 시저 암호화 진행
caesar_cipher(input, shift);
printf("암호화된 문자열: %s", input);
// 시저 복호화 진행
caesar_decipher(input, shift);
printf("복호화된 문자열: %s", input);
return 0;
}
이후에 암호화와 복호화함수에 input, shift값을 넘겨주어 호출한뒤 반환되는 결과를 출력해줍니다.
암호화 함수
// 시저 암호화 함수 정의
void caesar_cipher(char str[], int shift) {
int i;
for (i = 0; str[i] != '\0'; i++) {
// 소문자인 경우
if ('a' <= str[i] && str[i] <= 'z') {
str[i] = 'a' + ((str[i] - 'a' + shift) % 26);
}
// 대문자인 경우
else if ('A' <= str[i] && str[i] <= 'Z') {
str[i] = 'A' + ((str[i] - 'A' + shift) % 26);
}
}
}
아까 caser_cipher의 함수원형을 작성했었는데 이번에는 함수를 정의해줍니다. 이때 함수호출이 star[]와 shift로 인자값을 넘겨받습니다.
반복문을 사용하기위해 int i 를 생성한뒤 입력받은 문자열(i)가 '\0' 널문자가 아니면 하나씩 반복하고 str[i]가 입력받은 문자열의 끝부분 '\0' Null문자를 만나게되면 반복문이 종료됩니다.
이때 if문과 else if문을 사용하여 소문자와 대문자일때의 경우를 나누어 처리해줍니다.
소문자일경우 str[i]변수에 새로운 값을 담아주게 되는데, 예를 들어, str[i] = 'c' 이고, shift = 3이라고 가정해보면 현재 문자 str[i]에서 기준 문자 'a'를 빼줍니다
즉 c라고 가정하였을때 'c' - 'a' = 2. 이렇게 하면 문자의 인덱스를 얻을 수 있습니다 ('a'=0, 'b'=1, 'c'=2, ...)
다음으로 shift 값을 더해줍니다: 2 + 3 = 5. 여기서 shift 값은 각 문자가 이동해야 하는 알파벳의 개수입니다.
마지막으로 이동한 문자의 인덱스에 대응되는 문자를 순환시키려면, % 26을 해줍니다. 여기서 26은 소문자 알파벳의 개수입니다 5 % 26 = 5
5는 암호화된 문자의 인덱스를 나타냅니다. 이 경우, 인덱스 5에 대응되는 알파벳 소문자는 'f'입니다. 처음 문자 'c'가 shift 값 3만큼 이동한 결과는 'f'임을 알 수 있습니다.
복호화 함수
void caesar_decipher(char str[], int shift) {
int i;
for (i = 0; str[i] != '\0'; i++) {
// 소문자인 경우
if ('a' <= str[i] && str[i] <= 'z') {
str[i] = 'a' + ((str[i] - 'a' - shift + 26) % 26);
}
// 대문자인 경우
else if ('A' <= str[i] && str[i] <= 'Z') {
str[i] = 'A' + ((str[i] - 'A' - shift + 26) % 26);
}
}
}
암호화할때랑 거의 유사합니다.
if와 else if 문을 사용하여 소문자와 대문자를 각각 처리합니다. 암호화에서는 shift 값을 더했으나, 복호화에서는 shift 값을 빼는 것을 확인할 수 있습니다. 복호화 과정에서 이동한 문자를 원래의 문자로 되돌리기 위해, 암호화에서 이동시킨 방향과 반대로 shift 값을 이동시키기 때문입니다.
또한, 복호화 과정에서는 나머지 연산 결과가 음수가 될 수 있기 때문에 + 26을 추가한 후 다시 % 26 해줍니다. 이렇게 하면 모듈로 연산 결과가 항상 양수가 되어 의도한 대로 복호화 처리가 가능해집니다.
전체 코드
#include <stdio.h>
#include <ctype.h>
// 시저 암호화 함수 원형 선언
void caesar_cipher(char str[], int shift);
// 시저 복호화 함수 원형 선언
void caesar_decipher(char str[], int shift);
int main() {
char input[100];
int shift;
// 사용자로부터 문자열 입력 받음
printf("문자열을 입력해주세요: ");
fgets(input, sizeof(input), stdin);
// 사용자로부터 시프트 값 입력 받음
printf("시저 암호의 이동 횟수를 입력해주세요: ");
scanf("%d", &shift);
// 시저 암호화 진행
caesar_cipher(input, shift);
printf("암호화된 문자열: %s", input);
// 시저 복호화 진행
caesar_decipher(input, shift);
printf("복호화된 문자열: %s", input);
return 0;
}
// 시저 암호화 함수 정의
void caesar_cipher(char str[], int shift) {
int i;
// 문자열의 각 문자에 대해
for (i = 0; str[i] != '\0'; i++) {
// 알파벳 문자만 암호화 진행
if (isalpha(str[i])) {
char base = islower(str[i]) ? 'a' : 'A';
// 시프트 값을 더한 후 알파벳 범위 내로 Wrapping하여 적용
str[i] = (str[i] - base + shift) % 26 + base;
}
}
}
// 시저 복호화 함수 정의
void caesar_decipher(char str[], int shift) {
int i;
// 문자열의 각 문자에 대해
for (i = 0; str[i] != '\0'; i++) {
// 알파벳 문자만 복호화 진행
if (isalpha(str[i])) {
char base = islower(str[i]) ? 'a' : 'A';
// 시프트 값을 뺀 후 알파벳 범위 내로 Wrapping하여 적용
str[i] = (str[i] - base - shift + 26) % 26 + base;
}
}
}