在密碼學中,愷撒密碼是一種最簡單且最廣爲人知的加密技術。它是一種替換加密的技術,明文中的全部字母都在字母表上向後(或向前)按照一個固定數目進行偏移後被替換成密文。例,當偏移量是3的時候,全部的字母A將被替換成D,B變成E,以此類推。這個加密方法是以愷撒的名字命名的,當年愷撒曾用此方法與其將軍們進行聯繫。愷撒密碼一般被做爲其餘更復雜的加密方法中的一個步驟。愷撒密碼還在現代的ROT13系統中被應用。可是和全部的利用字母表進行替換的加密技術同樣,凱撒密碼的密度是很低的,只需簡單地統計字頻就能夠破譯。c++
(這裏的代碼只是爲了演示使用,不保證代碼具備工業強度)算法
// 凱撒密碼實現ide
// 將明文字母變爲它後面的三個字母,後面的循環到前面加密
// 公式 f(a) = (f(a) + 3) % 26 spa
#include <stdio.h>code
#include <unistd.h>orm
#include <stdlib.h>blog
#include <string.h>ip
void caesar_encode_single(char* p, char* c, char key) {ci
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
歷史上以維吉尼亞密表爲基礎又演變出不少種加密方法,其基本元素無非是密表與密鑰,並一直沿用到二戰之後的初級電子密碼機上。
(維吉尼亞算法的基礎是凱撒密碼,所以算法也是基於凱撒加密來實現)
// 維吉尼亞加密實現,基於凱撒加密
#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