4. eulerPhi 보다 작고 eulerPhi와 서로소인 정수 e를 찾아 선택합니다. (e가 공개키가 됩니다.)
5. d * e % eulerPhi == 1 인 d를 찾습니다. (d가 개인키가 됩니다.)
6. 최종적으로 키가 생성됩니다.
<e, n> 공개키, <d, n> 개인키
암호화 방법
메시지를 e번 제곱해주고 n으로 나눈 나머지를 얻습니다.
복호화 방법
메시지를 d번 제곱해주고 n으로 나눈 나머지를 얻습니다.
주의사항) n은 우리가 사용하는 문자 값보다 커야됩니다.
n이 'A' (65) 보다 작다면 A라는 의미를 잃어버리기 때문입니다.
프로그램에선 숫자가 너무 커지므로 제곱할 때마다 n으로 나눠주고 있습니다.
코드가 좀 길어서 제가 다시 볼지 모르겠습니다 ㅋㅋ;
코드 흐름
1. InitPrime() : 에라토스테네스의 체를 통해 notPrime배열에 소수를 구해두기
2. 소수 p, q를 입력받기
3. 오일러피 값을 구합니다. eulerPhi = (p - 1) * (q - 1)
4. GetRelativePrime() : eulerPhi 에 서로수인 숫자를 구합니다. (최대공약수를 찾기 위해 GCD 가 쓰입니다)
5. 공개키 e 입력 받기
6. FindPrivateDKey() : 개인키 후보를 찾습니다.
7. 개인키 d 입력 받기
8. 문자열 입력
9. Encryption() : 암호화 및 출력
(여기서 char 배열에서 int 배열로 바꿔서 저장합니다.
char는 1byte (=8bit) 최대 255까지밖에 표현되지 않아 값을 잃어버리기 때문입니다.)
10. Decryption() : 암호를 복호화하여 출력
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int MaxSize = 10000;
const int Size = 100;
const int LineLength = 14;
bool notPrime[MaxSize];
bool relativePrime[MaxSize]; //서로소
char input[100];
int encryptToInt[100];
vector<long long> dList;
void InitPrime()
{
notPrime[0] = notPrime[1] = true;
for (int i = 2; i * i <= MaxSize; ++i)
{
if (notPrime[i])
{
continue;
}
for (int j = i * i; j <= MaxSize; j += i)
{
notPrime[j] = true;
}
}
}
void PrintPrime(int enterLine, int size)
{
printf("====소수 목록====\n");
int line = 0;
for (int i = 2; i < Size; ++i)
{
if (notPrime[i])
{
continue;
}
printf("%3d ", i);
line++;
if (line >= enterLine)
{
line = 0;
printf("\n");
}
}
}
int GCD(int a, int b) //Greatest Common Divisor 최대 공약수 찾기
{
while (b != 0)
{
int c = a % b;
a = b;
b = c;
}
return a;
}
void GetRelativePrime(int enterLine, int phi)
{
int line = 0;
for (int i = 1; i < phi; ++i)
{
if (GCD(i, phi) == 1)
{
line++;
printf("%3d ", i);
relativePrime[i] = true;
if (line >= enterLine)
{
line = 0;
printf("\n");
}
}
}
}
void FindPrivateDKey(int e, int eulerPhi, int many)
{
for (long long d = 1; dList.size() < many; ++d)
{
if (d * e % eulerPhi == 1)
{
dList.push_back(d);
printf("[%d]번째 가능한 개인키 d = %lld [ %lld * %d %% %d = 1 ]\n", dList.size(), d, d, e, eulerPhi);
}
}
}
int Pow(int value, int e, int n)
{
int v = value;
for (int i = 1; i < e; ++i)
{
v = v * value % n;
}
return v;
}
void Encryption(int e, int n)
{
char encryptForPrint[100] = { 0 };
int length = strlen(input);
for (int i = 0; i < length; ++i)
{
int value = Pow(input[i], e, n);
//char는 1바이트로 8bit, 최대 2^8 (256) 까지밖에 표현이 불가능하여
//값이 256을 넘으면 오버플로우 발생
encryptToInt[i] = value;
encryptForPrint[i] = value;
}
printf("%s\n", encryptForPrint);
}
void Decryption(int d, int n)
{
char decryptForPrint[100] = { 0 };
int length = strlen(input);
for (int i = 0; i < length; ++i)
{
decryptForPrint[i] = Pow(encryptToInt[i], d, n);
}
printf("%s\n", decryptForPrint);
}
int main()
{
int p, q, n, e;
long long d;
InitPrime();
PrintPrime(LineLength, Size);
printf("\n\n두 개의 소수를 입력하세요.\n");
while (true)
{
scanf("%d %d", &p, &q);
if (notPrime[p] || notPrime[q])
{
printf("\n소수를 다시 입력하세요.\n");
continue;
}
break;
}
n = p * q; //[중요] n보다 작은 값들에 대해서만 암호화가 가능하다!!! % n 으로 나누어주기 때문이다.
int eulerPhi = (p - 1) * (q - 1);
printf("\n오일러 피 함수 값 %d * %d = %d\n", (p - 1), (q - 1), eulerPhi);
printf("====%d와 서로수인 수====\n", eulerPhi);
GetRelativePrime(LineLength, eulerPhi);
printf("\n\n");
while (true)
{
scanf("%d", &e);
if (relativePrime[e])
{
break;
}
else
{
printf("\n서로수인 수를 입력해야됩니다.\n");
}
}
FindPrivateDKey(e, eulerPhi, 5); //5개를 구해보자
printf("\n개인키를 입력하세요.\n");
while (true)
{
scanf("%lld", &d);
bool isContain = false;
for (int i = 0; i < dList.size(); ++i)
{
if (dList[i] == d)
{
isContain = true;
break;
}
}
if (isContain)
{
break;
}
else
{
printf("\n올바른 개인키를 입력해야 됩니다.\n");
}
}
printf("\n\n 공개키 [e = %d, n = %d], 개인키 [d = %lld, n = %d]\n\n", e, n, d, n);
printf("100문자 이내로 평문을 작성해보세요.\n");
printf("(단 n의 크기가 해당 문자를 나타내는 숫자보다 작다면 변환값을 잃게 됩니다.)\n");
printf("ex) 'A' = 65, n = 42라면 65값을 잃게 됩니다.\n\n");
getchar(); //버퍼에 엔터키 제거용
gets_s(input);
printf("\n평문을 암호화 합니다.\n");
Encryption(e, n);
printf("\n==============================================\n");
printf("\n평문을 복호화 합니다.\n\n");
Decryption(d, n);
return 0;
}
#include <iostream>
using namespace std;
int GCD(int a, int b)
{
while (b != 0)
{
int c = a % b;
a = b;
b = c;
}
return a;
}
int main()
{
cout << GCD(21, 12);
}
#include <iostream>
#include <ctime>
using namespace std;
int main()
{
clock_t start = clock(); //ms 단위를 반환 합니다. 1s == 1000ms
int i = 0;
int second = 0;
while (second < 5)
{
clock_t end = clock();
i++;
if (end - start >= 1000)
{
second++;
start = end;
cout << second << "초 경과 i 값은 " << i << endl;
}
}
}
부모 클래스 또는 인터페이스를 이용하여 하위 요소를 생성 및 사용할 때 이용되는 패턴입니다.
using System;
namespace ConsoleApp
{
class Program
{
public static void Main(string[] args)
{
int size = 3;
int player = 0;
Unit[] unit = new Unit[size];
while (player < size)
{
Console.WriteLine("{0}p 종족을 입력하세요: (Zerg, Protoss, Terran)", player + 1);
string race = Console.ReadLine();
switch (race)
{
case "Zerg":
unit[player] = new Zerg();
player++;
break;
case "Protoss":
unit[player] = new Protoss();
player++;
break;
case "Terran":
unit[player] = new Terran();
player++;
break;
default:
break;
}
}
Console.WriteLine();
foreach (Unit u in unit)
{
u.ShowType();
}
}
}
abstract class Unit
{
public abstract void ShowType();
}
class Zerg : Unit
{
public override void ShowType()
{
Console.WriteLine("Zerg");
}
}
class Protoss : Unit
{
public override void ShowType()
{
Console.WriteLine("Protoss");
}
}
class Terran : Unit
{
public override void ShowType()
{
Console.WriteLine("Terran");
}
}
}
using System;
using System.Net; //IPAddress, Dns
using System.Net.Sockets; //AddressFamily
namespace ConsoleServerTest
{
class Program
{
public static void Main (string[] args)
{
PrintMyAddress();
}
private static void PrintMyAddress()
{
IPAddress[] host = Dns.GetHostAddresses(Dns.GetHostName());
for (int i = 0; i < host.Length; ++i)
{
if (host[i].AddressFamily == AddressFamily.InterNetworkV6) //IPv6
{
Console.WriteLine("IPv6 주소 [{0}]", host[i]);
}
if (host[i].AddressFamily == AddressFamily.InterNetwork) //IPv4
{
Console.WriteLine("IPv4 주소 [{0}]", host[i]);
}
}
}
}
}