凱撒加密
在密碼學中,愷撒密碼是一種最簡單且最廣為人知的加密技術。它是一種替換加密的技術,明文中的所有字母都在字母表上向后(或向前)按照一個固定數目進行偏移后被替換成密文。例,當偏移量是3的時候,所有的字母A將被替換成D,B變成E,以此類推。這個加密方法是以愷撒的名字命名的,當年愷撒曾用此方法與其將軍們進行聯系。愷撒密碼通常被作為其他更復雜的加密方法中的一個步驟。愷撒密碼還在現代的ROT13系統中被應用。但是和所有的利用字母表進行替換的加密技術一樣,凱撒密碼的密度是很低的,只需簡單地統計字頻就可以破譯。
凱撒加密C++算法
(這里的代碼只是為了演示使用,不保證代碼具有工業強度)
// 凱撒密碼實現
// 將明文字母變為它后面的三個字母,后面的循環到前面
// 公式 f(a) = (f(a) + 3) % 26
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void caesar_encode_single(char* p, char* c, char key) {
if (*p >= 'a' && *p <= 'z') { /// 小寫字母
*c = (*p - 'a'+ key) % 26 + 'a';
}
else if (*p >= 'A' && *p <= 'Z') { /// 大寫字母
*c = (*p - 'A'+ key) % 26 + 'A';
}
else { /// 其它轉換成空格
*c = ' ';
}
}
void caesar_decode_single(char* c, char* p, char key) {
char offset = (*c) - key;
if (*c >= 'a' && *c <= 'z') { /// 小寫字母
offset = (offset >= 'a') ? offset : offset + 26;
*p = offset;
}
else if (*c >= 'A' && *c <= 'Z') { /// 大寫字母
offset = (offset >= 'A') ? offset : offset + 26;
*p = offset;
}
else { /// 其它轉換成空格
*p = ' ';
}
}
void caesar_encode(char* plain, char* cipher, char key) {
for (int i = 0; plain[i] != '\0'; ++i) { /// 逐個加密
caesar_encode_single(&plain[i], &cipher[i], key);
}
}
void caesar_decode(char* cipher, char* plain, char key) {
for (int i = 0; cipher[i] != '\0'; ++i) { /// 逐個解密
caesar_decode_single(&cipher[i], &plain[i], key);
}
}
int main(int argc, char** argv) {
if (argc < 3) {
printf("usage: %s plain key\n", argv[0]);
return -1;
}
char P[128];
char P2[128];
char C[128];
memset(P, 0, sizeof(P));
memset(P2, 0, sizeof(P2));
memset(C, 0, sizeof(C));
strncpy(P, argv[1], sizeof(P));
int K = atoi(argv[2]);
caesar_encode(P, C, K);
printf("the ciphertext is \n%s\n", C); /// 輸出密文
caesar_decode(C, P2, K);
printf("decode ciphertext is\n%s\n", P2);/// 輸出解碼明文
return 0;
}
下面是位移為3時的明密對照表,根據位移的不同還會產生不同的明密對照表:
明: |
A |
B |
C |
D |
E |
F |
G |
H |
I |
J |
K |
L |
M |
N |
O |
P |
Q |
R |
S |
T |
U |
V |
W |
X |
Y |
Z |
密: |
D |
E |
F |
G |
H |
I |
J |
K |
L |
M |
N |
O |
P |
Q |
R |
S |
T |
U |
V |
W |
X |
Y |
Z |
A |
B |
C |
運行結果
# g++ -g -o caesar caesar.cpp
維吉尼亞密碼
在單一愷撒密碼的基礎上,法國外交家布萊斯·德·維吉尼亞(Blaise de Vigenère)發明了一種方法來對同一條信息中的不同字母用不同的密碼進行加密。這樣,同樣的E在一個位置可能被M所取代,而在另一個位置的E則有可能以K的面目出現。這樣,就可以防止任何人利用頻率分析法解密該條信息。
維吉尼亞密碼引入了“密鑰”的概念,即根據密鑰來決定用哪一行的密表來進行替換,以此來對抗字頻統計。假如以上面第一行代表明文字母,左面第一列代表密鑰字母,對如下明文加密:
TO BE OR NOT TO BE THAT IS THE QUESTION
當選定RELATIONS作為密鑰時,加密過程是:明文一個字母為T,第一個密鑰字母為R,因此可以找到在R行中代替T的為K,依此類推,得出對應關系如下:
密鑰:RELAT IONSR ELATI ONSRE LATIO NSREL
明文:TOBEO RNOTT OBETH ATIST HEQUE STION
密文:KSMEH ZBBLK SMEMP OGAJX SEJCS FLZSY
歷史上以維吉尼亞密表為基礎又演變出很多種加密方法,其基本元素無非是密表與密鑰,並一直沿用到二戰以后的初級電子密碼機上。
維吉尼亞密表
維吉尼亞加密C++算法
(維吉尼亞算法的基礎是凱撒密碼,因此算法也是基於凱撒加密來實現)
// 維吉尼亞加密實現,基於凱撒加密
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define ALPHABETA_MIN 'A'
#define ALPHABETA_NUM 26
char table[ALPHABETA_NUM][ALPHABETA_NUM];
void caesar_encode_single(char* p, char* c, char key) {
if (*p >= 'a' && *p <= 'z') { /// 小寫字母
*c = (*p - 'a'+ key) % 26 + 'a';
}
else if (*p >= 'A' && *p <= 'Z') { /// 大寫字母
*c = (*p - 'A'+ key) % 26 + 'A';
}
else { /// 其它轉換成空格
*c = ' ';
}
}
void caesar_decode_single(char* c, char* p, char key) {
char offset = (*c) - key;
if (*c >= 'a' && *c <= 'z') { /// 小寫字母
offset = (offset >= 'a') ? offset : offset + 26;
*p = offset;
}
else if (*c >= 'A' && *c <= 'Z') { /// 大寫字母
offset = (offset >= 'A') ? offset : offset + 26;
*p = offset;
}
else { /// 其它轉換成空格
*p = ' ';
}
}
int getkey(char key) {
if (key >= 'a' && key <= 'z') { /// 小寫字母
return key - 'a';
}
else {
return key - 'A';
}
}
void init_vigenere() {
for (int i = 0;i < ALPHABETA_NUM; ++i) {
for (int j = 0; j < ALPHABETA_NUM; ++j) {
table[i][j] = ALPHABETA_MIN + (i + j) % ALPHABETA_NUM;
}
}
}
void print_vigenere() {
for (int i = 0;i < ALPHABETA_NUM; ++i) {
for (int j = 0; j < ALPHABETA_NUM; ++j) {
printf("%c ", table[i][j]);
}
printf("\n");
}
}
bool vigenere_encode(char* key, char* source, char* dest) {
char* tempSource = source;
char* tempKey = key;
char* tempDest = dest;
for (char* c = source; (*c) != '\0'; c++) {
caesar_encode_single(c, tempDest, getkey(*tempKey));
tempDest++;
if (*c == ' ') {
continue;
}
if(!(*(++tempKey))) {
tempKey = key;
}
}
dest[strlen(source)] = '\0';
return true;
}
bool vigenere_decode(char* key, char* source, char* dest) {
char* tempSource = source;
char* tempKey = key;
char* tempDest = dest;
for (char* c = source; (*c) != '\0'; c++) {
caesar_decode_single(c, tempDest, getkey(*tempKey));
tempDest++;
if (*c == ' ') {
continue;
}
if(!(*(++tempKey))) {
tempKey = key;
}
}
dest[strlen(source)] = '\0';
return true;
}
int main(int argc, char** argv) {
if (argc < 3) {
printf("usage: %s plain key\n", argv[0]);
return -1;
}
init_vigenere();
print_vigenere();
char key[256];
char plain[256];
char plain2[256];
char cipher[256];
memset(key, 0, sizeof(key));
memset(plain, 0, sizeof(plain));
memset(plain2, 0, sizeof(plain2));
memset(cipher, 0, sizeof(cipher));
strncpy(plain, argv[1], sizeof(plain));
strncpy(key, argv[2], sizeof(key));
printf("the plaintext is \n%s\n", plain);
vigenere_encode(key, plain, cipher);
printf("the ciphertext is \n%s\n", cipher); /// 輸出密文
vigenere_decode(key, cipher, plain2);
printf("decode ciphertext is\n%s\n", plain2);/// 輸出解碼明文
return 0;
}
運行結果
# g++ -g -o vigenere vigenere.cpp
我的博客即將搬運同步至騰訊雲+社區,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan