공부 기록

[정보보안] Classic Encryption Techniques

by 너나나

Caesar Cipher

plaintext를 다른 charater와 1대1 mapping 시켜서 ciphertext를 만드는 방법이다!! (plaintext 같은 용어는 guiyum.tistory.com/56?category=846073 )

 

가장 대표적인 subsititution ciphers가 바로바로 Caesar cipher다!!

얘는 영어 문자에 0~25 번호를 할당하고(A면 0, B면 1 ... Z면 25) 여기에 secret key값(26보다 작은 값)을 더해서 modulo 연산을 한다. 영어 문자도 0~25고 secret key값도 0~25면 두개 더했을때 26 이상일 수도 있으니까 modulo연산을 해서 범위를 맞춰준다!!

K 를 secret key, P는 plaintext, C는 ciphertext라고 하자.

 

그럼 Encryption(암호화)은 C ≡ P + K mod 26

Decryption(복호화)은 P ≡ C - K mod 26

 

그러니까 단순하게 말하면 plaintext에 shift 연산을 하는 것이다. 만약 secret key K가 5라면 A 문자가 들어왔을때 F가 되는 그런 연산이다!!

 

character number character number character number character number
a 0 h 7 o 14 v 21
b 1 i 8 p 15 w 22
c 2 j 9 q 16 x 23
d 3 k 10 r 17 y 24
e 4 l 11 s 18 z 25
f 5 m 12 t 19    
g 6 n 13 u 20    

이렇게 문자와 숫자를 맵핑할 수 있다.

 

Plaintext : Alice loves Bob을 암호화 시켜보자.

Secret key : 3

C ≡ P + K mod 26이니까

각 알파벳을 3씩 shift 하면

Ciphertext : Dolfh oryhv Ere가 나온다.

복호화 할려면 Decryption Key : -3 해서 더해주면 원문인 Alice loves Bob이 나온다!!!

 

코드를 짜보자!!

#include<stdio.h>
#include<string.h>

int main() {
    int i = 0, key = 0, str_size = 0;
    char str[50] = {0, }; // Plaintext or Ciphertext
    
    printf("평문 또는 암호문을 입력하시오 : ");
    gets(str);
    
    printf("키 값을 입력하시오 : ");
    scanf("%d", &key);
    
    str_size = strlen(str);
    
    for(int i = 0; i < str_size; i++) {
    	if ((str[i] >= 'A') && (str[i] <= 'Z')) { // 대문자가 들어오면
        	str[i] -= 'A'; // 어떤 대문자에 아스키코드값 A만큼 빼주면 숫자가 됨! 만약 B가 들어오면 B는 아스키코드로 66이고 A는 65니까 'B' - 'A' 하면 우리가 저 표에 써놨던 1이 나옴!! 소문자에도 마찬가지로 적용
            if ((str[i] + key) < 0) {
            	str[i] += 26; // str[i] == 1이고 key == -3 같은 경우라면 범위를 맞춰줘야 한다.
            }
            str[i] = (str[i] + key) % 26;
            str[i] += 'A'; // 다시 아스키코드값 A만큼 더해줘 문자로 바꿈
        }
        else if ((str[i] >= 'a') && (str[i] <= 'z')) { // 소문자일 경우
        	str[i] -= 'a';
             if ((str[i] + key) < 0) {
            	str[i] += 26; // str[i] == 1이고 key == -3 같은 경우라면 범위를 맞춰줘야 한다.
            }
            str[i] = (str[i] + key) % 26;
            str[i] += 'a'; // 다시 아스키코드값 a만큼 더해줘 문자로 바꿈
        }
        else return -1; // 숫자가 문자가 아니니까 그냥 종료시키자
    }
    printf("\n암호화 또는 복호화된 결과 출력 : ");
    puts(str);
    
    return 0;
}

함수로도 작성할 수 있다.

#include<stdio.h>
#include<string.h>

char *CaesarCipher(char *c, int a, int b);

int main() {
	int i = 0, key = 0, str_size = 0;
	char str[50] = {0, };
	
	printf("평문 또는 암호문을 입력하시오 : ");
	gets(str);
	
	printf("키 값을 입력하시오 : ");
	scanf("%d", &key);
	
	str_size = strlen(str);
	
	CaesarCipher(str, str_size, key);
	
	printf("\n암호화 또는 복호화된 결과 출력 : ");
	puts(str);
	
	return 0;
}

char *CaesarCipher(char *str, int str_size, int key) {
	int i;
	for(int i = 0; i < str_size; i++) {
		if ((str[i] >= 'A') && (str[i] <= 'Z')) {
			str[i] -= 'A';
			
			if(str[i] + key < 0) {
				str[i] += 26;
			}
			
			str[i] = (str[i] + key) % 26;
			str[i] += 'A';
		}
		else if ((str[i] >= 'a') && (str[i] <= 'z')) {
			str[i] -= 'a';
			
			if(str[i] + key < 0) {
				str[i] += 26;
			}
			
			str[i] = (str[i] + key) % 26;
			str[i] += 'a';
		}
		else return NULL;
	}
}

Vigenere Cipher

한개의 plaintedt character가 multipble ciphertext characters로 바뀐다.

a가 q로 바뀔수도 있고 t로 바뀔수도 있고 z로 바뀔수도 있다!! 어떤 규칙에 따라 바뀌냐면!!

문자가 첫번째인지 두번째 문자인지 이런 position에 따라 결과가 달라진다. 그러니까 위에서 말한 caesar cipher랑 비슷한데 얘는 key stream으로 바뀐다!!

 

이 key stream은 k1, k2, ..., kd로 이루어져있는데 이러면 주기는 d이다. 키 스트림이 무한대일 수는 없으니까 이 길이 만큼 주기가 반복된다. 그러면 message는 m1 m2 m3 ... md md+1 md+2 ... 이렇게 있으면 d주기 만큼 나눠서 저 key stream에 따라 적용하면 된다.

 

Encryption(암호화) :

C(p1, p2, ... , p_d) = P(p1, p2, ..., p_d) + K(k1, k2, ..., k_d) mod 26

C(p_d+1, p_d+2, ... , p_2d) = P(p_d+1, p_d+2, ..., p_2d) + K(k1, k2, ..., k_d) mod 26

.

.

.

 

Decryption(복호화) : 

P(c1, c2, ... , c_d) = C(c1, c2, ..., c_d) +-K(k1, k2, ..., k_d) mod 26

P(c_d+1, c_d+2, ... , c_2d) = C(c_d+1, c_d+2, ..., c_2d) + K(k1, k2, ..., k_d) mod 26

.

.

.

 

사실 이해가 잘 안되니까 예를 보자!!

 

Secret key (K) 를 security 라는 key stream이라고 하자. 그러면 이 문자열의 길이가 8이니까 주기(d) 는 8이다.

Plaintext (P) : thiscryptosystemisnotsecure 이라고 하면

일단 먼저 이 Plaitext 문자열을 8개씩 자른다. 그리고 이 secret key를 숫자로 바꿔서 각 자리의 수를 그 수만큼 shift하면 된다.

P t h i s c r y p
K 18 (=s) 4 (=e) 2 (=c) 20 (=u) 2 (=r) 17 (=i) 24 (=t) 15 (=y)
C l l k m t z r n
P t o s y s t e m
K 18 (=s) 4 (=e) 2 (=c) 20 (=u) 2 (=r) 17 (=i) 24 (=t) 15 (=y)
C l s u s j b x k
P i s n o t s e c
K 18 (=s) 4 (=e) 2 (=c) 20 (=u) 2 (=r) 17 (=i) 24 (=t) 15 (=y)
C a w p i k a x a

이런식으로 암호화가 되는것이다. 그러면 첫번째 주기에 첫번째 문자인 t는 l로, 두번째 주기의 첫번째 문자인 t도 l로 암호화 되지만 두번째 주기의 6번째 문자 t는 l이 아니라 b로 암호화가 된다. 이런식으로 주어진 키 stream에 따라 암호화를 하는것이다!!

 

이제 코드를 짜보자!!

#include<stdio.h>
#include<string.h>

int main() {
	int i = 0, j = 0, key_size = 0, str_size = 0, select = 1;
	char str[50] = {0, }, key[50] = {0,} ;
	
	printf("암호문 또는 평문을 입력 : ");
	gets(str);
	printf("암호는 1번, 복호는 2번 선택 : ");
	scanf("%d", &select);
	fflush(stdin);
	printf("키 값 입력 :");
	gets(key);
	
	str_size = strlen(str);
	key_size = strlen(key);
	
	for (i = 0; i < str_size; i++){
		j = i % key_size; // 주기 
		
		if (select == 1) {
			if ((str[i] >= 'a') && (str[i] <= 'z')) {
				str[i] -= 'a';
				key[j] -= 'a';
				if(str[i] + key[j] < 0) {
					str[i] += 26;
				}
				str[i] = (str[i] + key[j]) % 26;
				str[i] += 'a';
				key[i] += 'a';
			}
			else if ((str[i] >= 'A') && (str[i] <= 'Z')) {
				str[i] -= 'A';
				key[j] -= 'A';
				if(str[i] + key[j] < 0) {
					str[i] += 26;
				}
				str[i] = (str[i] + key[j]) % 26;
				str[i] += 'A';
				key[i] += 'A';
			}
		}
		if (select == 2) {
			/* 복호화 구현 */ 
		} 
	}
	
	printf("\n암호화 또는 복호화된 결과 출력 : ");
	puts(str);
	
	return 0;
}

 

블로그의 정보

공부 기록

너나나

활동하기