数论及其应用——密码学中的数论

  密码学,是一门古老而又年轻的学科,在《模仿游戏》中Benedict Cumberbatch饰演的图灵,就是二战时期颇有造诣的密码学大师。虽然涉猎不深,但是笔者还是认为密码学同数论、组合数学一样,都是非常好的数学游戏,那么这篇文章,我们就来介绍一下一些简单的和数论有一定关联的加密方式。

 

 

  最为古老的一种加密方式——凯撒密码,其实就是字符密码的一种方式。

  在密码学中,有两个最基本的名词——明文、密文。明文即包含了加密者真正想表达的东西,而密文则是通过某种加密方式,由明文生成。而这种加密方式,就是明文中的基本字母(或者其他符号),与密文中的字母(或者其他符号)一一对应关系。

  基于对上面概念的简单理解,我们就可以来看凯撒密码了。

  明文:A B C D ……

  密文:D E F G ……

  即明文中的大写字母对应该字母在字母表位置中+3的那个大写字母。

  凯撒密码就是一种利用移位变换来加密的密码,那么推广起来,它遵循这样的公式:C = P + k(mod 26) , 其中C为密文字符,P为明文字符。

  基于对这个很简单的加密方式的理解,我们通过一个题目尝试来用代码来实现它。(Problem source : pku 3749)

 在编程实现上,简单地对字母进行ASCII值的运算即可,这里基于C++中输入输出流的特点,我们可以仅仅通过一个字符变量来实现一条凯撒消息的翻译。

  参考代码如下。

 

#include<stdlib.h>
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
    char a[15],c;
    while(1)
    {
        while(cin >> a && strcmp(a,"START"))
        {if(strcmp(a,"ENDOFINPUT") == 0)  break;}


        if(strcmp(a,"ENDOFINPUT") == 0)  break;
        getchar();
        while((c = getchar()) != '\n')
        {
             if(c >= 'A' && c <= 'Z')
                { c -= 5 ; if(c < 'A')  c += 26;}
             cout << c;
        }cout << endl;
        while(cin >> a && strcmp(a,"END"));
    }
    return 0;
}

   今天介绍一种强大的加密方式——RSA,关于这种加密方式,我们直接通过一个具体的题目来了解一下。(Problem source:hdu 1211)
  

Problem Description
RSA is one of the most powerful methods to encrypt data. The RSA algorithm is described as follow:
> choose two large prime integer p, q > calculate n = p × q, calculate F(n) = (p - 1) × (q - 1) > choose an integer e(1 < e < F(n)), making gcd(e, F(n)) = 1, e will be the public key > calculate d, making d × e mod F(n) = 1 mod F(n), and d will be the private key
You can encrypt data with this method :
C = E(m) = me mod n
When you want to decrypt data, use this method :
M = D(c) = cd mod n
Here, c is an integer ASCII value of a letter of cryptograph and m is an integer ASCII value of a letter of plain text.
Now given p, q, e and some cryptograph, your task is to "translate" the cryptograph into plain text.
 
Input
Each case will begin with four integers p, q, e, l followed by a line of cryptograph. The integers p, q, e, l will be in the range of 32-bit integer. The cryptograph consists of l integers separated by blanks.
 
Output
For each case, output the plain text in a single line. You may assume that the correct result of plain text are visual ASCII letters, you should output them as visualable letters with no blank between them.


  题目大意:首先给出了RSA加密和解密的方法。给出了两个大素数p、q,计算n = p * q , F(n) = (p - 1)(q - 1)。选择一个整数e,是的gcd(e,F(n) ) = 1。计算d,使其满足d x e = 1 (mod F(n))。
  设c是密文中字符的ASCII值,m是明文中字符的ASCII值,那么生成密文的方式为:
   c = m^e(mod n).
   则解密的方式为:
  m = c^d mod n.
  现在给出参数p、q、e、和一段密文,请你输出解密后的信息。
 数理分析: 值得注意的是,既然题目中已经给出了解密公式,其实题目的难度就大大降低了。我们需要知道的是,一种加密方式是对应着一种解密方式的。人们可以自定义加密信息的方式,而解密公式则需要根据加密公式以及参数之间的关系式进行推导。
  而在这个问题中,我们运用解密公式的时候需要求得d的数值,这里就需要用到RSA机制中 d x e = 1(mod F(n))这一条件来求解d了。即e关于模F(n)的逆元,自然而然我们想到了先前学过的拓展欧几里得算法。
  编程实现:基于对算法流程的分析,剩下的部分则需要处理一些模拟过程中的小细节了,值得注意的是,这里并没有给出密文的长度的限制,因此我们需要处理字符串的技巧。
  参考代码如下。
 

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int extgcd(int a , int b , int &x , int &y)
{
     if(b == 0) {x = 1;y = 0;return a;}
     int d = extgcd(b , a%b,x,y);
     int t = x;
     x = y;
     y = t - a/b*y;
     return d;
}
int pon(int x , int y,int mo)
{
     int m = 1;
     while(y)
     {
           if(y&1)  m = (long long )m*x%mo;
           x = (long long )x*x%mo;
           y >>= 1;
     }
     return m;
}

int main()
{
    int n , p , q , e , d , m , c , l;
    while(cin >> p >> q >> e >> l)
    {
         n = p * q;
         p = (p - 1)*(q - 1);
         int y;
         extgcd(e , p , d , y);
         d = (d%p + p)%p;
         while(l--)
         {
             cin >> c;
             m = pon(c , d , n);
             printf("%c",m%128);
         }
         printf("\n");
    }
    return 0;
}

 

  我们在这里再介绍一种加密方法——流密码。我们通过一个题目来引入这种加密技术的简单模型。(Problem source : pku 1026)

 

Description

Bob and Alice started to use a brand-new encoding scheme. Surprisingly it is not a Public Key Cryptosystem, but their encoding and decoding is based on secret keys. They chose the secret key at their last meeting in Philadelphia on February 16th, 1996. They chose as a secret key a sequence of n distinct integers, a1 ; . . .; an, greater than zero and less or equal to n. The encoding is based on the following principle. The message is written down below the key, so that characters in the message and numbers in the key are correspondingly aligned. Character in the message at the position i is written in the encoded message at the position ai, where ai is the corresponding number in the key. And then the encoded message is encoded in the same way. This process is repeated k times. After kth encoding they exchange their message.
The length of the message is always less or equal than n. If the message is shorter than n, then spaces are added to the end of the message to get the message with the length n.
Help Alice and Bob and write program which reads the key and then a sequence of pairs consisting of k and message to be encoded k times and produces a list of encoded messages. 

Input

The input file consists of several blocks. Each block has a number 0 < n <= 200 in the first line. The next line contains a sequence of n numbers pairwise distinct and each greater than zero and less or equal than n. Next lines contain integer number k and one message of ascii characters separated by one space. The lines are ended with eol, this eol does not belong to the message. The block ends with the separate line with the number 0. After the last block there is in separate line the number 0.

Output

Output is divided into blocks corresponding to the input blocks. Each block contains the encoded input messages in the same order as in input file. Each encoded message in the output file has the lenght n. After each block there is one empty line.
 
  题目大意:通过读题我们不难发现,所谓流密码,就是给出一个整数n,然后给出长度为n的数列a[],要求任意a[i]小于n,并且任意a[i]!=a[j],随后给出明文字符串s,该字符串的长度小于等于n,当小于n的时候,末尾以空格填充。
  这样使得数列a[]和字符串s[]呈现出一一对应的关系,那么现在开始遍历明文数组中的每一元素s[i],该字符对应的a[i]是该字符加密一次后在密文的位置,现在给出密匙、加密次数、明文,请生成密文。
  数理分析:基于对流密码流程的理解,我们发现其实实现加密的算法就是简单的处理字符串的模拟,可以说与数论没有太大的关系。
  参考代码如下。
 
#include<cstdlib>
#include<string.h>
#include<stdio.h>
#include<iostream>
using namespace std;
int main()
{
      int k , n , len , cir[210],dec[210];
      char c , s[210],en[210];
      bool flag[210];
      while(scanf("%d",&n) && n)
      {
            for(int i = 1;i <= n;i++)
                 scanf("%d",&dec[i]);
            memset(flag , 0 , sizeof(flag));
            for(int i = 1;i <= n;i++)
                 if(!flag[i])
            {
                  int q = 0 , j = i;
                  while(!flag[j])
                  {
                       q++;
                       flag[j] = 1;
                       j = dec[j];
                  }
                  cir[i] = q;
                  for(j = dec[i];j != i;j=dec[j])
                     cir[j] = q;
            }
            memset(s,' ',sizeof(s));
            while(scanf("%d",&k) && k)
        {
            getchar();
            len = 1;
            while(scanf("%c",&c) && c!='\n')
            {
                  s[len] = c;
                  len++;
            }
            memset(en,' ',sizeof(en));
            for(int i = 1;i < len;i++)
            {
                  int j = k%cir[i];
                  int po = i;
                  while(j--)
                    po = dec[po];
                  en[po] = s[i];
            }
            en[n+1] = '\0';
            printf("%s\n",en + 1);
      }
      printf("\n");
      }
}

  另外放个小彩蛋,按照按照上文给出密匙,按照次数为930的加密,结果显示明文和密文是一样的!是笔者一次试出来的彩蛋!密码学是不是好神奇。

posted on 2016-03-02 15:05  在苏州的城边  阅读(1966)  评论(0编辑  收藏  举报

导航