RSA 소개 및 개인키 로직 포스트: https://shacoding.com/2019/07/28/rsa-find-d-using-ne-c/
암호화 인식 & 복호화 구현 문자
영어 소문자, 대문자, 숫자, 띄어쓰기, 특수문자(콤마, 점, 콜론, 세미콜론,소괄호, 느낌표, 물음표, 퍼센트, 대시, 큰 따옴표, 작은 따옴표) 구현
– 미구현 문자는 띄어쓰기 처리, 줄 바꿈 구현 불가
구현된 기능
1. 암호화 시 (영문 소문자, 대문자, 숫자, 특수문자) 인식 가능
2. 복호화 시 (영문 소문자, 대문자, 숫자, 특수문자) 구현 가능
3. 원 문자열 ->원 숫자 집합으로 분할 가능
4. 원 숫자 집합 -> 암호 숫자 집합으로 변경 가능 (암호화)
5. 암호 숫자 집합 -> 원 숫자 집합으로 변경 가능 (복호화)
6. 원 숫자 집합 -> 원 문자열로 통합 가능
7. 위 (1~6)의 코드 -> 프로시저화 완료
스크린샷으로 살펴보기

1.5. 원 문자열 -> 분할 -> 원 숫자 집합 생성





C언어 소스
#include <stdio.h>
#define MAX 2000
#define n 16637 // 공개 키 < (0 <= M <=n-1)에 주의해서 설정, 현재 M의 최대값은 7575 >
#define e 14453 // 공개 키
#define d 17 // 개인 키
/*
- 리스트 포인터 소개 -
* code = RSA 전처리 코드 집합 저장 (ex) a는 1로, b는 2로)
* bundle = 원 숫자 집합 저장 (ex) 102,203,1020,...)
* encode = 암호 숫자 집합 저장 (ex) 2120,3366, ...)
* decode = 복호화 숫자(원 숫자) 집합 저장 (ex) 102,203,1020,...)
*/
typedef struct list { // 리스트 구조체
int size;
int* array;
}list;
list* code, * bundle, * encode, * decode; // 여기서 선언하지 않으면 '댕글링 포인터'가 되어 버림
/*
- 함수 소개 (작업 실행 순서대로) -
* init() = RSA 작업에 필요한 리스트 생성 (code,bundle,encode,decode 리스트)
* get_symbol(char* tmp) = string의 문자열을 조각으로 나눠서 리턴 (ex) ab-> 'a','b')
* make_Code(char* string,list* code) = 문자 조각으로 전처리 코드 집합 생성 <code> (ex) a->1, b->2)
* get_integer(list* code) = 전처리 코드 2개로 원 숫자 만들기 (ex) 1,2 -> 102)
* make_Bundle(list * code,list* bundle) = 원 숫자 집합 생성 <bundle> (ex) 102,1021,1200,..)
* make_C(int M) = RSA 암호화 <원 숫자 -> 암호 숫자로 변경> (ex) 102 -> 3366)
* make_Encode(list *bundle,list *encode) = 암호 숫자 집합 생성 <encode> (ex) 3366,3450,9800,..)
* make_M(int C) = RSA 복호화 <암호 숫자 -> 원 숫자로 변경> (ex) 3366 -> 102)
* make_Decode(list* encode, list* decode) = 복호 숫자(원 숫자) 집합 생성 <decode> (ex) 102,1021,1200,..)
* get_Code(list* decode) = 복호 숫자(원 숫자) 분할해서 전처리 코드 반환 (ex) 102 -> 1과 2 반환)
* decode_Effect(list* decode) = RSA 전처리 코드를 아스키코드로 변환 후 문자 출력
↑(전처리 코드를 다 쓸때까지 반복) (ex) 1->97->'a'출력, 2->98->'b'출력, ...)
*/
void init();
char get_symbol(char* tmp);
void make_Code(char* string, list* code);
int get_integer(list* code);
void make_Bundle(list* code, list* bundle);
int make_C(int M);
void make_Encode(list* bundle, list* encode);
int make_M(int C);
void make_Decode(list* encode, list* decode);
int* get_Code(list* decode);
void decode_Effect(int* decode);
/* 아래는 (문자열 처리)에 필요함 */
/* ------------------------------------------------------------------------ */
// 원문자열 저장
char string[MAX] = "";
// 특수문자 배열
char sign[14] = { ' ',',','.',';',':','(',')','!','?','%','"',39,'-' }; // 39 = `
// 특수문자와의 거리
int sign_distance[14] = { 63 - 32,64 - 44,65 - 46,66 - 59,67 - 58,68 - 40,69 - 41,70 - 33,71 - 63,72 - 37,73 - 34,74 - 39,75 - 45 };
/* ------------------------------------------------------------------------ */
// 메인 함수
int main() {
init(); // RSA 작업에 필요한 리스트 생성
printf("■ 암호화할 문장을 적어 주세요:\n\n");
gets(string);// 원 문자열 입력해서 문자형 배열(string)에 저장(ex)string배열에 'abdcdi' 저장)
/* 암호화 과정 */
make_Code(string, code); // 전처리 코드 집합 생성
make_Bundle(code, bundle); // 원 숫자 집합 생성
make_Encode(bundle, encode); // 암호 숫자 집합 생성
/* 복호화 과정 */
make_Decode(encode, decode); // 복호 숫자(원 숫자) 집합 생성
printf("\n■ 다음과 같이 복호화되었습니다:\n\n");
decode_Effect(decode); // 복호 숫자 이용 -> 문자 출력까지
}
// RSA 작업에 필요한 리스트 생성
void init() {
// RSA 전처리 코드 저장 리스트
code = (list*)malloc(sizeof(list));
code->size = 0;
code->array = (int*)malloc(sizeof(int) * MAX);
// 원 숫자 집합(숫자 묶음) 저장 리스트
bundle = (list*)malloc(sizeof(list));
bundle->size = 0;
bundle->array = (int*)malloc(sizeof(int) * MAX);
// 암호화 코드 저장 리스트
encode = (list*)malloc(sizeof(list));
encode->size = 0;
encode->array = (int*)malloc(sizeof(int) * MAX);
// 복호화 코드 저장 리스트
decode = (list*)malloc(sizeof(list));
decode->size = 0;
decode->array = (int*)malloc(sizeof(int) * MAX);
}
// string의 문자열을 조각으로 나눠서 리턴 (ex) ab-> 'a','b')
char get_symbol(char* tmp) {
static int j = 0;
return tmp[j++];
}
// 문자 조각으로 RSA 전처리 코드 저장 (ex) a->1, b->2)
void make_Code(char* string, list* code) {
char piece; // 문자 조각
// RSA 전처리 코드 저장
while ((piece = get_symbol(string)) != 0) {
// 영어 소문자 (a~z)
// RSA 전처리 시 -> 1~26으로 지정
if (piece >= 97 && piece <= 122) {
code->array[code->size] = piece - 96;
code->size++;
}
// 영어 대문자(A~Z)
// RSA 전처리 시 -> 27~52으로 지정
else if (piece >= 65 && piece <= 90) {
code->array[code->size] = piece - 38;
code->size++;
}
// 숫자 (0~9)
// RSA 전처리 시 -> 53~62으로 지정
else if (piece >= 48 && piece <= 57) {
code->array[code->size] = piece + 5;
code->size++;
}
// 특수 문자
// RSA 전처리 시 -> 63~73로 지정
else {
for (int i = 0; i < 13; i++) {
if (piece == sign[i]) {
code->array[code->size] = i + 63;
break;
}
else if (i == 12)
code->array[code->size] = 63; // 없으면 공백 문자
}
code->size++;
}
}
}
// 전처리 코드 2개로 원 숫자 만들기
// ex) ab(12)가 오면 (a*100+b)를 반환, c(3)만 오면 c*100을 반환
int get_integer(list* code) {
static int i = 0;
// i가 리스트의 최고 idx보다 높을 때
if (i >= code->size) {
return -1;
}
// 마지막 원소를 다룰 때 (문자 개수는 홀수)
// ex) size=17, i=16
else if (i == code->size - 1)
return code->array[i++] * 100;
// 일반적인 것을 다룰 때
// ex) size=17, i=5; size=17; i=15;
else {
int first = code->array[i] * 100;
int second = code->array[i + 1];
i += 2;
return first + second;
}
}
// 원 숫자 집합(bundle) 생성 (ex) 102,1021,1200,..)
void make_Bundle(list* code, list* bundle) {
int receive;
while ((receive = get_integer(code)) != -1) {
bundle->array[bundle->size++] = receive;
}
}
// RSA 암호화 C = M^e mod n
int make_C(int M) {
unsigned long long C = 1; // 곱하기 하면서 오버플로우 될 수 있으므로 크게 설정
for (int i = 0; i < e; i++) {
C *= M;
C %= n;
}
return C; // 최종 나머지 값은 int형으로 해결 가능
}
// 암호 숫자 집합 생성 (ex) 3366,3450,9800,..)
void make_Encode(list* bundle, list* encode) {
printf("\ne:%d, n:%d\n", e, n);
for (int i = 0; i < bundle->size; i++) {
int M = bundle->array[i];
encode->array[encode->size] = make_C(M); // C = M^e mod n
printf("원 숫자 %d => 암호 숫자 %d\n", M, encode->array[encode->size]);
encode->size++;
}
}
// RSA 복호화 M = C^d mod n
int make_M(int C) {
unsigned long long M = 1; // 곱하기 하면서 오버플로우 될 수 있으므로 크게 설정
for (int i = 0; i < d; i++) {
M *= C;
M %= n;
}
return M; // 최종 나머지 값은 int형으로 해결 가능
}
// 복호 숫자(원 숫자) 집합 생성(ex) 102, 1021, 1200, ..)
void make_Decode(list* encode, list* decode) {
printf("\n\nd:%d, n:%d\n", d, n);
for (int i = 0; i < encode->size; i++) {
int C = encode->array[i];
decode->array[decode->size] = make_M(C); // M = C^d mod n
printf("암호 숫자 %d => 원 숫자 %d\n", C, decode->array[decode->size]);
decode->size++;
}
}
// 복호 숫자(원 숫자) 분할해서 전처리 코드 반환 (ex) 102-> 1과 2)
int* get_Code(list* decode) {
static int z = 0; // idx역할
static int tmp[2]; // 정적 처리 -> 리턴해도 스택에서 안 사라지게
tmp[0] = tmp[1] = 0; // 값 매번 0으로 초기화
// z가 리스트의 최고 idx보다 높을 때
if (z >= decode->size) {
return -1;
}
// 마지막 원소를 다룰 때
// ex) 1819 1920 2100따위일 때 2100
else if (decode->array[z] % 100 == 0) {
tmp[0] = decode->array[z++] / 100;
}
// 일반적인 원소를 다룰 때
else {
tmp[0] = decode->array[z] / 100;
tmp[1] = decode->array[z] % 100;
z++;
}
return tmp;
}
/* RSA 전처리 코드를 아스키코드로 변환 후 문자 출력
↑(전처리 코드를 다 쓸때까지 반복) (ex) 1->97->'a'출력, 2->98->'b'출력, ...) */
void decode_Effect(int* decode) {
int* receive; // 전처리 코드의 주소를 저장
int get = 0; // receive[0]과 receive[1]이 저장됨
// get_Code 이용해서 전처리 코드 반환, 전처리 코드 모두 받을 때까지 문자 출력
while ((receive = get_Code(decode)) != -1) {
for (int i = 0; i < 2; i++) {
get = receive[i];
if (get != 0) {
// 영어 소문자
if (get >= 1 && get <= 26)
printf("%c", get + 96);
// 영어 대문자
else if (get >= 27 && get <= 52)
printf("%c", get + 38);
// 숫자
else if (get >= 53 && get <= 62)
printf("%c", get - 5);
// 특수문자
else {
for (int i = 0; i < 13; i++) {
// 넘어온 문자-특수문자와의 거리=특수문자일 때
// ex) 63-29=32(' ')
if (get - sign_distance[i] == sign[i]) {
printf("%c", sign[i]);
break;
}
}
}
}
}
}
printf("\n");
}
프로그램 그림 설명



참고 자료: Discrete Mathematics and Its Applications (케네스 H. 로젠의 책)