zoukankan      html  css  js  c++  java
  • RSA加密算法

    周五在上c语言课的时候,有幸接触了著名的rsa加密算法。rsa算法作为目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。回寝室后我感觉这种算法很有趣并且以我们目前的学习进度可以进行编写,便进行了尝试。在开始前我也找到了一些资料,下面和大家分享一下。

    RSA

    rsa算法的由来

    1976年以前,所有的加密方法都是同一种模式:

    1. 甲方选择某一种加密规则,对信息进行加密;
    2. 乙方使用同一种规则,对信息进行解密。

    由于加密和解密使用同样规则(简称”密钥”),这被称为”对称加密算法”(Symmetric-key algorithm)。
    这种加密模式有一个最大弱点:甲方必须把加密规则告诉乙方,否则无法解密。保存和传递密钥,就成了最头疼的问题。

    1976年,两位美国计算机学家Whitfield Diffie 和 Martin Hellman,提出了一种崭新构思,可以在不直接传递密钥的情况下,完成解密。这被称为”Diffie-Hellman密钥交换算法”。这个算法启发了其他科学家。人们认识到,加密和解密可以使用不同的规则,只要这两种规则之间存在某种对应关系即可,这样就避免了直接传递密钥。
    这种新的加密模式被称为非对称加密算法

    1. 乙方生成两把密钥(公钥和私钥)。公钥是公开的,任何人都可以获得,私钥则是保密的。
    2. 甲方获取乙方的公钥,然后用它对信息加密。
    3. 乙方得到加密后的信息,用私钥解密。

    如果公钥加密的信息只有私钥解得开,那么只要私钥不泄漏,通信就是安全的。
    1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。从那时直到现在,RSA算法一直是最广为使用的”非对称加密算法”。毫不夸张地说,只要有计算机网络的地方,就有RSA算法。

    rsa算法的步骤

    1. 随机选择两个不相等的质数p和q。(实际应用中,这两个质数越大,就越难破解。)
    2. 计算p和q的乘积n。n的长度就是密钥长度。3233写成二进制是110010100001,一共有12位,所以这个密钥就是12 位。实际应用中,RSA密钥一般是1024位,重要场合则为2048位。
    3. 计算n的欧拉函数φ(n)。根据公式:φ(n) = (p-1)(q-1)
    4. 随机选择一个整数e,条件是1< e < φ(n),且e与φ(n) 互质。
    5. 计算e对于φ(n)的模反元素d。
    6. 将n和e封装成公钥,n和d封装成私钥。
      实际应用中,公钥和私钥的数据都采用ASN.1格式表达(实例)。

    加密和解密

    有了公钥和密钥,就能进行加密和解密了。

    1. 加密要用公钥 (n,e) 所谓”加密”,就是算出下式的c:m^e ≡ c (mod n)。c就是密文
    2. 解密要用私钥(n,d) 可以证明,下面的等式一定成立:c^d ≡ m (mod n) 也就是说,c的d次方除以n的余数为m。m就是明文

    至此,”加密–解密”的整个过程全部完成。

    后续

    这种算法非常可靠,密钥越长,它就越难破解。根据已经披露的文献,目前被破解的最长RSA密钥是768个二进制位。也就是说,长度超过768位的密钥,还无法破解(至少没人公开宣布)。因此可以认为,1024位的RSA密钥基本安全,2048位的密钥极其安全。 由于rsa的公钥(n,e) 只能加密小于n的整数m,那么如果要加密大于n的整数,就要采用这么两种解决方法:一种是把长信息分割成若干段短消息,每段分别加密;另一种是先选择一种”对称性加密算法”(比如DES),用这种算法的密钥加密信息,再用RSA公钥加密DES密钥。

    代码

    由于时间与水平有限,目前编写的rsa还比较简陋,而且素数也不够大,只编写了的一个加密解密和在一起的程序,和单独加密的程序,还有单独随机公钥的程序,后续将会在时间充裕的时候补上有关明文字母分开的代码,以便于编写单独解密的程序。下面是我写的代码,欢迎大家的讨论。

    RSA集合

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    #include <math.h>
    int (int e,int fn);
    int fun_2(int e,int fn);
    int zhuan_huan(int b,int a[],int k);
    int js_mod(int a,int b,int n);
    * 主函数 *
    *************/
    void main()
    {
    int p,q,e,d,n,fn;
    long m[10000],c[100000];//c[10000]存放加密后的数字密文,m[1000]存放解密后的数字明文,即英文明文在zimu_biao[69]中的下标。
    int i,j; //i,j用于循环遍历数组
    int mi_yue; //用户输入的密钥
    int count=1; //统计输入密钥的次数,count>3时将不允许用户再输入。
    char min_wen[大专栏  RSA加密算法ass="number">10000],re_min_wen[10000];//分别为用户输入的明文、密文,解密后的明文。
    //密钥生成
    char zimu_biao[69]="abcdefghijklmnopqrstuvwxyz,ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789'.?!";
    printf("请输入您要发送的明文文件(小写英文表示):n");
    printf("******************************************************n");
    gets(min_wen);
    printf("******************************************************n");
    srand((unsigned) time(NULL));
    printf("n加密开始nn");
    do
    {
    p=rand()%201+101;
    for(i=2;i<=sqrt(p);i++)
    {
    if(p%i==0)
    break;
    }
    }while(i<=sqrt(p));
    do
    {
    q=rand()%201+101;
    for(i=2;i<=sqrt(q);i++)
    {
    if(q%i==0)
    break;
    }
    }while(i<=sqrt(q)||q==p);
    n=p*q;
    fn=(p-1)*(q-1);
    do
    {
    e=rand()%(fn)+1;
    }while(fun_1(e,fn));
    d=fun_2(e,fn); //求解密指数d
    printf("******************************************************n");
    printf("n明文长度:%dn",strlen(min_wen));
    printf("n您的两个大素数分别为p=%d(保密),q=%d(保密)n模数n=%d(公开),欧拉函数fn=%d(保密)n",p,q,n,fn);
    printf("Public Key:%10d %10d(公钥,公开)n",n,e);
    printf("Private Key:%10d %10d(私钥,保密)nn",n,d);
    //明文转换过程
    for(i=0;i<strlen(min_wen);i++)
    for(j=0;j<68;j++)
    if(min_wen[i]==zimu_biao[j])
    m[i]=j;//将字符串明文换成数字,并存到整型数组m里面,即明文的另一种表示方法
    //加密过程
    for(i=0;i<strlen(min_wen);i++)
    c[i]=js_mod(m[i],e,n);
    printf("输出密文:n");
    printf("******************************************************n");
    for(i=0;i<strlen(min_wen);i++)
    printf("%d",c[i]);
    printf("n******************************************************n");
    //提示用户解密
    printf("nn您有3次输入密钥(只需要输入私钥的d)的机会,3次输入错误将无法解密nn");
    while(1)
    {
    scanf("%d",&mi_yue);
    if(mi_yue==d)
    {
    printf("密钥输入正确,您得到的明文为:nn");
    for(i=0;i<strlen(min_wen);i++)
    m[i]=js_mod(c[i],d,n);
    for(i=0;i<strlen(min_wen);i++)
    re_min_wen[i]=zimu_biao[m[i]];
    for(i=0;i<strlen(min_wen);i++)
    printf("%c",re_min_wen[i]);
    printf("nn");
    break;
    }
    else
    {
    printf("您第%d次输入的密钥错误,请重新输入。。。n",count);
    count++;
    if(count>3)
    {
    printf("n您已%d次输入的密钥错误,将不允许继续输入n",count-1);
    break;
    }
    }
    }
    }
    //判断fn和e是否互素
    int (int e,int fn)
    {
    int i,null=0;
    for(i=2;i<=fn;i++)
    {
    if(e%i==0&&fn%i==0)
    null=1;
    }
    return null;
    }
    //扩展欧几里得算法求乘法逆元,即求解密指数d
    int fun_2(int e,int fn)
    {
    int d=1;
    while((e*d)%fn!=1)
    {
    d++;
    }
    return d;
    }
    //将十进制数转换成二进制
    int zhuan_huan(int b,int a[],int k)
    {
    int t,temp=-1;
    while(b>0){
    t=b%2;
    temp++;
    a[temp]=t;
    b=b/2;
    }
    return temp;
    }
    //快速计算模指数
    int js_mod(int a,int b,int n)
    {
    int x=0,y=1,k,i,s[1000];
    k=zhuan_huan(b,s,1000);
    for(i=k;i>=0;i--){
    x=2*x;
    y=(y*y)%n;
    if(s[i]==1){
    x++;
    y=(y*a)%n;
    }
    }
    return y;
    }
  • 相关阅读:
    字符串匹配算法 【微软面试100题 第三十三题】
    交换元素,使两数组之和的差最小 【微软面试100题 第三十二题】
    在从1到n的正数中1出现的次数 【微软面试100题 第三十题】
    栈的push、pop序列 【微软面试100题 第二十九题】
    整数的二进制表示中1的个数 【微软面试100题 第二十八题】
    跳台阶问题 【微软面试100题 第二十七题】
    左旋转字符串 【微软面试100题 第二十六题】
    字符串中找出最长的数字串 【微软面试100题 第二十五题】
    合并链表 【微软面试100题 第二十四题】
    计算圆形是否和正方形相交 【微软面试100题 第二十三题】
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12239990.html
Copyright © 2011-2022 走看看