Playfair 加密算法

来源:互联网 发布:石油进口数据 编辑:程序博客网 时间:2024/06/16 15:31

Playfair 加密原理

Playfair 密码将明文中的双字母组合作为一个单元对待,并将这些单元转换为密文双字母组合。
Playfair 密码基于一个 5x5 字母矩阵,该矩阵使用密钥来构造,其构造方法是:
从左至右,从上至下依次填入关键词的字母(去除重复的字母),然后以字母表顺序依次填入其他的字母。(字母 I 和 J 被当做一个字母)
对每一对明文字母 p1、p2 的加密办法如下:

  • 若 p1=p2,则插入一个字母(例如X,需事先约定)于重复字母之间;
  • 若明文字母数为奇数时,则在明文的末端添加某个事先约定的字母作为填充;
  • 若 p1、p2 在同一行时,则对应密文 c1、c2 分别是紧靠 p1、p2 右端的字母。(最后一列的右方为第一列);
  • 若 p1、p2 在同一列时,则对应密文 c1、c2 分别是紧靠 p1、p2 下方的字母。(最后一行的下方为第一行);
  • 若 p1、p2 不在同一列、同一行时,则 c1、c2 是由 p1、p2 确定的矩形的剩余两个角的字母,c1 与 p1 同行,c2 与 p2 同行。

具体实现如下:

/* 约定:若明文字母数为奇数时, 明文末尾添加字母 p2 = p1 + 1  *      明文对中的两个字母相等时,中间插入‘X’ */#include <iostream>#include <cstring>using namespace std;char X = 'X';                   char K[] = "fivestars";char M[] = "Playfair cipher was actually invented by wheatstone";//字母是否已在矩阵中(已赋值的1是J的位置)int flag[26]={ 0,0,0,0,0, 0,0,0,0,1, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0 }; //判断字符是否存在于数组,若不存在则加入int duplicate(char a, char b[]){    int i, flag = 1;            //flag=1,字符第一次出现    for (i=0; i<strlen(b); i++) {        if(b[i]==a) {           //a[i]在目标串中存在,即重复             flag = 0;           }    }    return flag;    }//初始化密钥,a[]原始密钥,b[]目标密钥 void initKey(char a[], char b[], int flag[]){    int i, j, k=0, flag;    for (i=0; a[i]!='\0'; i++) {          if (a[i]==' ')           //跳过空格              continue;        if (a[i]>='a' && a[i]<='z')             a[i] = a[i]-32;     //密钥小写转大写         if(a[i]=='J')             a[i] = 'I';         //密钥 J 都变为 I        if (duplicate(a[i],b)) {      //赋值新字符,或跳过重复字符,             b[strlen(b)] = a[i];     //字符加入目标串结尾            flag[a[i]-'A'] = 1;     //标记在字母表中已存在         }     }    b[strlen(b)] = '\0';     cout << "Init K : " << b << endl << endl;}//创建字母表(这里用了一维数组来模拟,当然也可用二维)void createTable(char key[]){    int i;    for (i=0; i<26; i++)         if (flag[i]==0)             key[strlen(key)] = i+'A';   //剩余字母无重复地添加到 key (共25个)     key[strlen(key)] = '\0';        for (i=0; i<25; i++) {        cout << key[i];        if((i+1)%5==0) cout << endl;    //每隔5个换行    }    cout << endl;}//初始化明文void initPlain(char a[], char b[]){    int i, j=0, k=0, flag;    for (i=0; a[i]!='\0'; i++) {          if (a[i]==' ')           //跳过空格              continue;        if (a[i]>='a' && a[i]<='z')             a[i] = a[i]-32;    //小写转大写         if (a[i]=='J')             a[i] = 'I';        //J 都变为 I            b[j] = a[i];            j++;                   //j 为新数组的长度         if (j%2==0) {      //(1)判断明文对两字母是否重复,重复则用规定的 X 代替             if (b[j-1]==b[j-2]) {                   b[j] = b[j-1];                b[j-1] = X;                j++;                    }           }         if (strlen(b)%2)    //(2)若字母数为奇数,在明文末尾添加字母p2 = p1+1             b[strlen(b)] = b[strlen(b)-1] + 1;    }    b[strlen(b)] = '\0';     cout << "Init M : " << b << endl << endl;}//获取明文在字母表中的二维坐标void grid(char a[], char c, int &x, int &y){    int k = 0;    for (k=0; a[k]!='\0'; k++) {        if(a[k] == c) {            x = k/5;            y = k%5;        }       }} void encrypt(char key[], char plain[], char cipher[]){    int k, i,j, m,n;    for (k=0; plain[k]!='\0'; k+=2) {          grid(key, plain[k], i, j);        grid(key, plain[k+1], m, n);        if (i==m) {             // (3) 同一行             cipher[k] = key[i*5+(j+1)%5];                   cipher[k+1] = key[m*5+(n+1)%5];          }         else if (j==n) {        // (4) 同一列             cipher[k] = key[(i+1)%5*5+j];               cipher[k+1] = key[(m+1)%5*5+n];         }        else {                  // (5) 斜对             cipher[k] = key[i*5+n];                     cipher[k+1] = key[m*5+j];                 }    }    cout << "Encrypt: " << cipher << endl;}int main(){    int i,j,k;    int c = 0;    char key[100]={0}, plain[100]={0}, cipher[100]={0};    cout << "K: " << K << endl;    cout << "M: " << M << endl << endl;    initKey(K, key, flag);              //初始化密钥     createTable(key);                   //创建字母表     initPlain(M, plain);                //初始化明文     encrypt(key, plain, cipher);        //加密     return 0;}

测试

这里写图片描述


0 0