维吉尼亚密码及程序实现
凯撒加密
在密码学中,恺撒密码是一种最简单且最广为人知的加密技术。它是一种替换加密的技术,明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。例,当偏移量是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