📜  Playfair密码范例

📅  最后修改于: 2021-04-30 02:46:03             🧑  作者: Mango

Playfair密码是第一个实用的有向图替换密码。该方案由查尔斯·惠斯通(Charles Wheatstone)于1854年发明,但以促进密码使用的普勒费尔勋爵(Lord Playfair)命名。在与传统密码不同的游戏公平密码中,我们对一对字母(图)进行加密,而不是对单个字母进行加密。

它在第二次布尔战争和第一次世界大战中被英国军队用于战术目的,在第二次世界大战期间被澳大利亚人用于相同目的。这是因为Playfair的使用速度相当快,并且不需要任何特殊设备。

加密技术

对于加密过程,让我们考虑以下示例:

Playfair密码加密算法:
该算法包括2个步骤:

  1. 生成密钥Square(5×5):
    • 密钥方块是一个5×5的字母网格,用作加密明文的密钥。 25个字母中的每个字母必须唯一,并且表中省略了一个字母(通常为J)(因为表只能容纳25个字母)。如果明文包含J,则将其替换为I。
    • 按键方块中的初始字母是按键的唯一字母,按照它们出现的顺序排列,然后依次排列其余字母。

    例如:

    The key is "monarchy" 
    Thus the initial entires are 
    'm', 'o', 'n', 'a', 'r', 'c', 'h', 'y'
    followed by remaining characters of 
    a-z(except 'j') in that order.
    

  2. 加密纯文本的算法:将纯文本分为两个字母(图)组成的对。如果字母的数量为奇数,则将Z添加到最后一个字母。

    例如:

    PlainText: "instruments" 
    After Split: 'in' 'st' 'ru' 'me' 'nt' 'sz'
    

    加密规则:

    • 如果两个字母都在同一列中:取每个字母下方的字母(如果位于底部,则返回顶部)。

      例如:

      Diagraph: "me"
      Encrypted Text: cl
      Encryption: 
        m -> c
        e -> l
      

    • 如果两个字母都在同一行中:取每个字母右边的字母(如果位于最右边,则返回最左边)。

      例如:

      Diagraph: "st"
      Encrypted Text: tl
      Encryption: 
        s -> t
        t -> l
      

    • 如果以上规则都不成立:用两个字母组成一个矩形,并在矩形的水平相对角上取字母。

      例如:

      Diagraph: "nt"
      Encrypted Text: rq
      Encryption: 
        n -> r
        t -> q
      

例如:

Plain Text: "instrumentsz"
Encrypted Text: gatlmzclrqtx
Encryption: 
  i -> g
  n -> a
  s -> t
  t -> l
  r -> m
  u -> z
  m -> c
  e -> l
  n -> r
  t -> q
  s -> t
  z -> x

以下是Playfair Cipher在C语言中的实现:

// C program to implement Playfair Cipher
  
#include 
#include 
#include 
  
#define SIZE 30
  
// Function to convert the string to lowercase
void toLowerCase(char plain[], int ps)
{
    int i;
    for (i = 0; i < ps; i++) {
        if (plain[i] > 64 && plain[i] < 91)
            plain[i] += 32;
    }
}
  
// Function to remove all spaces in a string
int removeSpaces(char* plain, int ps)
{
    int i, count = 0;
    for (i = 0; i < ps; i++)
        if (plain[i] != ' ')
            plain[count++] = plain[i];
    plain[count] = '\0';
    return count;
}
  
// Function to generate the 5x5 key square
void generateKeyTable(char key[], int ks, char keyT[5][5])
{
    int i, j, k, flag = 0, *dicty;
  
    // a 26 character hashmap
    // to store count of the alphabet
    dicty = (int*)calloc(26, sizeof(int));
    for (i = 0; i < ks; i++) {
        if (key[i] != 'j')
            dicty[key[i] - 97] = 2;
    }
  
    dicty['j' - 97] = 1;
  
    i = 0;
    j = 0;
  
    for (k = 0; k < ks; k++) {
        if (dicty[key[k] - 97] == 2) {
            dicty[key[k] - 97] -= 1;
            keyT[i][j] = key[k];
            j++;
            if (j == 5) {
                i++;
                j = 0;
            }
        }
    }
  
    for (k = 0; k < 26; k++) {
        if (dicty[k] == 0) {
            keyT[i][j] = (char)(k + 97);
            j++;
            if (j == 5) {
                i++;
                j = 0;
            }
        }
    }
}
  
// Function to search for the characters of a digraph
// in the key square and return their position
void search(char keyT[5][5], char a, char b, int arr[])
{
    int i, j;
  
    if (a == 'j')
        a = 'i';
    else if (b == 'j')
        b = 'i';
  
    for (i = 0; i < 5; i++) {
  
        for (j = 0; j < 5; j++) {
  
            if (keyT[i][j] == a) {
                arr[0] = i;
                arr[1] = j;
            }
            else if (keyT[i][j] == b) {
                arr[2] = i;
                arr[3] = j;
            }
        }
    }
}
  
// Function to find the modulus with 5
int mod5(int a)
{
    return (a % 5);
}
  
// Function to make the plain text length to be even
int prepare(char str[], int ptrs)
{
    if (ptrs % 2 != 0) {
        str[ptrs++] = 'z';
        str[ptrs] = '\0';
    }
    return ptrs;
}
  
// Function for performing the encryption
void encrypt(char str[], char keyT[5][5], int ps)
{
    int i, a[4];
  
    for (i = 0; i < ps; i += 2) {
  
        search(keyT, str[i], str[i + 1], a);
  
        if (a[0] == a[2]) {
            str[i] = keyT[a[0]][mod5(a[1] + 1)];
            str[i + 1] = keyT[a[0]][mod5(a[3] + 1)];
        }
        else if (a[1] == a[3]) {
            str[i] = keyT[mod5(a[0] + 1)][a[1]];
            str[i + 1] = keyT[mod5(a[2] + 1)][a[1]];
        }
        else {
            str[i] = keyT[a[0]][a[3]];
            str[i + 1] = keyT[a[2]][a[1]];
        }
    }
}
  
// Function to encrypt using Playfair Cipher
void encryptByPlayfairCipher(char str[], char key[])
{
    char ps, ks, keyT[5][5];
  
    // Key
    ks = strlen(key);
    ks = removeSpaces(key, ks);
    toLowerCase(key, ks);
  
    // Plaintext
    ps = strlen(str);
    toLowerCase(str, ps);
    ps = removeSpaces(str, ps);
  
    ps = prepare(str, ps);
  
    generateKeyTable(key, ks, keyT);
  
    encrypt(str, keyT, ps);
}
  
// Driver code
int main()
{
    char str[SIZE], key[SIZE];
  
    // Key to be encrypted
    strcpy(key, "Monarchy");
    printf("Key text: %s\n", key);
  
    // Plaintext to be encrypted
    strcpy(str, "instruments");
    printf("Plain text: %s\n", str);
  
    // encrypt using Playfair Cipher
    encryptByPlayfairCipher(str, key);
  
    printf("Cipher text: %s\n", str);
  
    return 0;
}
  
// This code is contributed by AbhayBhat
输出:
Key text: Monarchy
Plain text: instruments
Cipher text: gatlmzclrqtx

解密技术

解密Playfair密码与执行相反的过程一样简单。接收者具有相同的密钥,可以创建相同的密钥表,然后解密使用该密钥发出的任何消息。

Playfair密码解密算法:
该算法包括2个步骤:

  1. 在接收方的末端生成密钥Square(5×5):
    • 密钥方块是一个5×5的字母网格,用作加密明文的密钥。 25个字母中的每个字母必须唯一,并且表中省略了一个字母(通常为J)(因为表只能容纳25个字母)。如果明文包含J,则将其替换为I。
    • 按键方块中的初始字母是按键的唯一字母,按照它们出现的顺序排列,然后依次排列其余字母。

    例如:

    The key is "monarchy" 
    Thus the initial entires are 
    'm', 'o', 'n', 'a', 'r', 'c', 'h', 'y'
    followed by remaining characters of 
    a-z(except 'j') in that order.
    

  2. 解密密文的算法:密文分成两个字母(图)的对。

    例如:

    CipherText: "gatlmzclrqtx" 
    After Split: 'ga' 'tl' 'mz' 'cl' 'rq' 'tx'
    

    解密规则:

    • 如果两个字母都在同一列中:将每个字母上方(如果回到顶部,则返回底部)。

      例如:

      Diagraph: "cl" 
      Decrypted Text: me
      Decryption: 
        c -> m
        l -> e
      

    • 如果两个字母都在同一行中:将每个字母都放在左边(如果在最左边,则返回最右边)。

      例如:

      Diagraph: "tl" 
      Decrypted Text: st 
      Decryption: 
        t -> s
        l -> t
      

    • 如果以上规则都不成立:用两个字母组成一个矩形,并在矩形的水平相对角上取字母。

      例如:

      Diagraph: "rq" 
      Decrypted Text: nt 
      Decryption: 
        r -> n
        q -> t
      

例如:

Plain Text: "gatlmzclrqtx"
Decrypted Text: instrumentsz
Decryption: 
(red)-> (green)
  ga -> in
  tl -> st
  mz -> ru
  cl -> me
  rq -> nt
  tx -> sz

以下是C语言中Playfair密码解密的实现:

#include 
#include 
#include 
#define SIZE 30
  
// Convert all the characters
// of a string to lowercase
void toLowerCase(char plain[], int ps)
{
    int i;
    for (i = 0; i < ps; i++) {
        if (plain[i] > 64 && plain[i] < 91)
            plain[i] += 32;
    }
}
  
// Remove all spaces in a string
// can be extended to remove punctuation
int removeSpaces(char* plain, int ps)
{
    int i, count = 0;
    for (i = 0; i < ps; i++)
        if (plain[i] != ' ')
            plain[count++] = plain[i];
    plain[count] = '\0';
    return count;
}
  
// generates the 5x5 key square
void generateKeyTable(char key[], int ks,
                      char keyT[5][5])
{
    int i, j, k, flag = 0, *dicty;
  
    // a 26 character hashmap
    // to store count of the alphabet
    dicty = (int*)calloc(26, sizeof(int));
  
    for (i = 0; i < ks; i++) {
        if (key[i] != 'j')
            dicty[key[i] - 97] = 2;
    }
    dicty['j' - 97] = 1;
  
    i = 0;
    j = 0;
    for (k = 0; k < ks; k++) {
        if (dicty[key[k] - 97] == 2) {
            dicty[key[k] - 97] -= 1;
            keyT[i][j] = key[k];
            j++;
            if (j == 5) {
                i++;
                j = 0;
            }
        }
    }
    for (k = 0; k < 26; k++) {
        if (dicty[k] == 0) {
            keyT[i][j] = (char)(k + 97);
            j++;
            if (j == 5) {
                i++;
                j = 0;
            }
        }
    }
}
  
// Search for the characters of a digraph
// in the key square and return their position
void search(char keyT[5][5], char a,
            char b, int arr[])
{
    int i, j;
  
    if (a == 'j')
        a = 'i';
    else if (b == 'j')
        b = 'i';
  
    for (i = 0; i < 5; i++) {
        for (j = 0; j < 5; j++) {
            if (keyT[i][j] == a) {
                arr[0] = i;
                arr[1] = j;
            }
            else if (keyT[i][j] == b) {
                arr[2] = i;
                arr[3] = j;
            }
        }
    }
}
  
// Function to find the modulus with 5
int mod5(int a)
{
    return (a % 5);
}
  
// Function to decrypt
void decrypt(char str[], char keyT[5][5], int ps)
{
    int i, a[4];
    for (i = 0; i < ps; i += 2) {
        search(keyT, str[i], str[i + 1], a);
        if (a[0] == a[2]) {
            str[i] = keyT[a[0]][mod5(a[1] - 1)];
            str[i + 1] = keyT[a[0]][mod5(a[3] - 1)];
        }
        else if (a[1] == a[3]) {
            str[i] = keyT[mod5(a[0] - 1)][a[1]];
            str[i + 1] = keyT[mod5(a[2] - 1)][a[1]];
        }
        else {
            str[i] = keyT[a[0]][a[3]];
            str[i + 1] = keyT[a[2]][a[1]];
        }
    }
}
  
// Function to call decrypt
void decryptByPlayfairCipher(char str[], char key[])
{
    char ps, ks, keyT[5][5];
  
    // Key
    ks = strlen(key);
    ks = removeSpaces(key, ks);
    toLowerCase(key, ks);
  
    // ciphertext
    ps = strlen(str);
    toLowerCase(str, ps);
    ps = removeSpaces(str, ps);
  
    generateKeyTable(key, ks, keyT);
  
    decrypt(str, keyT, ps);
}
  
// Driver code
int main()
{
    char str[SIZE], key[SIZE];
  
    // Key to be encrypted
    strcpy(key, "Monarchy");
    printf("Key text: %s\n", key);
  
    // Ciphertext to be decrypted
    strcpy(str, "gatlmzclrqtx");
    printf("Plain text: %s\n", str);
  
    // encrypt using Playfair Cipher
    decryptByPlayfairCipher(str, key);
  
    printf("Deciphered text: %s\n", str);
  
    return 0;
}
  
// This code is contributed by AbhayBhat
输出:
Key text: Monarchy
Plain text: gatlmzclrqtx
Deciphered text: inskrumentsz
的优点和缺点
  • 好处:
    1. 很难破解,因为用于破解简单替换密码的频率分析技术很困难,但仍可用于(25 * 25)= 625个有向图,而不是很难的25个专论。
    2. 因此,频率分析需要更多的密文才能破解加密。
  • 缺点:
    1. 一个有趣的弱点是,密文(AB)和反向文(BA)中的有向图将具有相应的明文,例如UR和RU(并且密文UR和RU将对应于明文AB和BA,即替换是自-逆)。如果知道明文的语言,则可以借助频率分析轻松地利用这一点。
    2. 另一个缺点是游戏公平密码是对称密码,因此相同的密钥用于加密和解密。