치환 암호는 26자리의 알파벳 배열을 암호키로 사용한다. A부터 Z까지 알파벳 문자를 순서대로 암호키에 대응시키고 평문의 각 문자를 그에 상응하는 것으로 치환하여 암호화하는 방식이다. 예를 들어 NQXPOMAFTRHLZGECYJIUWSKDVB
라는 문자열을 암호키로 사용한다면, 평문의 A
를 암호화 하면 N
이 된다.
명령행 인자를 통해 사용자에게 26자리 알파벳 배열을 암호키로 입력받고, 프롬프트로 평문을 입력받아 암호키를 사용해 암호화하여 출력하는 프로그램을 만든다.
$ ./substitution JTREKYAVOGDXPSNCUIZLFBMWHQ
plaintext: HELLO
ciphertext: VKXXN
콤마나 공백 등의 문자는 변환하지 않는다. 알파벳 문자만 변환하여야 하며, 소문자는 소문자로, 대문자는 대문자로 변환한다.
$ ./substitution VCHPRZGJNTLSKFBDQWAXEUYMOI
plaintext: hello, world
ciphertext: jrssb, ybwsp
main
함수가 즉시 1
을 반환하도록 한다.main
함수가 즉시 1
을 반환하도록 한다. 암호키는 26개의 알파벳 문자로 이루어진 문자열이며, 알파벳 문자는 각각 한번씩 사용되어야 한다.plaintext:
를 줄바꿈 없이 출력하고, 유저에게 string
타입의 인풋을 받는 프롬프트를 출력한다. (get_string
사용)ciphertext:
를 줄바꿈 없이 출력하고, 평문의 각 알파벳 문자를 그에 상응하는 암호키의 문자로 치환한 암호문을 출력한다. 알파벳이 아닌 문자는 변환하지 않고 출력한다.과제 안내문의 Specifications에는 없지만 Walkthorugh에 상황별 에러메세지를 출력하라는 안내가 있었기 때문에 명령행인자의 오입력 케이스를 여러 개로 구분했다.
bool checkArg(int argc, char **argv)
{
if (argc != 2)
{
printf("usage: ./caesar key\n");
return false;
}
if (strlen(argv[1]) != ALPHABET_LEN)
{
printf("Key must contain 26 characters.\n");
return false;
}
char temp[ALPHABET_LEN];
for (int i = 0; i < ALPHABET_LEN; i++)
{
temp[i] = toupper(argv[1][i]);
}
if (strspn(temp, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") != ALPHABET_LEN)
{
printf("Key must only contain alphabetic characters.\n");
return false;
}
if (strspn("ABCDEFGHIJKLMNOPQRSTUVWXYZ", temp) != ALPHABET_LEN)
{
printf("Key must not contain repeated characters.\n");
return false;
}
return true;
}
toupper()
는 소문자 알파벳인 경우 대문자로 변환해 반환하고, 나머지는 그대로 반환.char *getCiphertext(char *key, char *plaintext)
{
size_t len = strlen(plaintext);
char *result = malloc(len);
for (int i = 0; i < (int)len; i++)
{
char character = plaintext[i];
int index;
if (isupper(character))
{
index = character - 'A';
result[i] = toupper(key[index]);
}
else if (islower(character))
{
index = character - 'a';
result[i] = tolower(key[index]);
}
else
{
result[i] = character;
}
}
return result;
}
#define ALPHABET_LEN 26
bool checkArg(int argc, char **argv);
char *getCiphertext(char *key, char *plaintext);
int main(int argc, char **argv)
{
if (!checkArg(argc, argv))
{
return 1;
}
char *plaintext = get_string("plaintext: ");
char *ciphertext = getCiphertext(argv[1], plaintext);
printf("ciphertext: %s", ciphertext);
printf("\n");
free(ciphertext);
return 0;
}
strlen()
의 리턴 타입.unsigned int
를 사용할 경우 오버플로우 될 수 있다.%zu
형식 지정자 사용. %lu
도 가능.