博客首页 注册 建议与交流 排行榜 加入友情链接
推荐 投诉 搜索: 帮助

黑与白的世界

如果人们按照程序员编程的方式修建房屋,那么一只啄木鸟就能毁灭整个文明
dongj.cublog.cn


一个自己写的RSA
   好久没上了,贴一个自己以前用C++写的程序,感觉不是特别的优雅。是一个64位的RSA。
 
   首先,来介绍一个RSA算法的加密和解密原理。选择两个不同的大素数pqn是二者的乘积,即np*q,使fn=(p-1)*(q-1),随机选取正整数e,使其满足(e,fn)=1,即互素。则将(ne)作为公钥。求出正数d,使其满足e*d=1(mod fn),则将(nd)作为私钥。加密算法:对于明文m,密文c=m的e次幂模n。解密算法:对于密文c,明文m=c的d次幂模n。

   编写RSA,首先要解决的位数问题,一般语言所提供整型最高为64位,在RSA中,这种数实在太小,更何况要求幂。故要写一个高精度运算,要有加、减、乘、除、求模以及输入、输出、比较、整数转化为高精度等。高精度的算法一般网上可以找到。我进行了修改,具体的如下:
 

# include<iostream.h>
# include <string>
# include <math.h>

using namespace std;

# define maxsize 100

struct hp
{
    int len;
    int s[maxsize+1];
};


hp input(string str)
//输入字符串形成高精度数

{
    hp a;
    int i;
    while(str[0]=='0' && str.size()!=1)
        str.erase(0,1);
    a.len=(int)str.size();
    for(i=1;i<=a.len;++i)
        a.s[i]=str[a.len-i]-48;
    for (i=a.len+1;i<=maxsize;++i)
        a.s[i]=0;
    return a;
}

void output(hp &y)
//输出高精度数

{
    int i;
    for(i=y.len;i>=1;i--)
        cout<<y.s[i];
}

hp add(hp &a,hp &b)
//高精度加法c=a+b,返回c

{
    hp c;
    int i,len;
    for(i=1;i<=maxsize;i++) c.s[i]=0;
    if(a.len>b.len) len=a.len;
    else len=b.len;
    for(i=1;i<=len;i++)
    {
        c.s[i]+=a.s[i]+b.s[i];
        if(c.s[i]>=10)
        {
            c.s[i]-=10;
            c.s[i+1]++;
        }
    }
    if(c.s[len+1]>0) len++;
    c.len=len;
    return c;
}

hp sub(hp &a,hp &b)
//高精度减法c=a-b,返回c

{
    hp c;
    int i,len;
    for(i=1;i<=maxsize;i++) c.s[i]=0;
    if(a.len>b.len) len=a.len;
    else len=b.len;
    for(i=1;i<=len;i++)
    {
        c.s[i]+=a.s[i]-b.s[i];
        if(c.s[i]<0)
        {
            c.s[i]+=10;
            c.s[i+1]--;
        }
    }
    while(len>1&&c.s[len]==0) len--;
    c.len=len;
    return c;
}

int com(hp &a,hp &b)
//对a,b进行比较,若a>b,返回正数,相等时返回0,否则返回负数

{
    int len;
    if(a.len>b.len)
        len=a.len;
    else
        len=b.len;
    while(len>0 && a.s[len]==b.s[len])
        len--;
    if(len==0)
        return 0;
    else
        return a.s[len]-b.s[len];
}



hp mul(hp &a,hp &b)
//高精度乘法c = a * b,返回c

{
    hp c;
    int i,j,len;
    for(i=1;i<=maxsize;i++) c.s[i]=0;
    for(i=1;i<=a.len;i++)
        for(j=1;j<=b.len;j++)
        {
            c.s[i+j-1]+=a.s[i]*b.s[j];
            c.s[i+j]+=c.s[i+j-1]/10;
            c.s[i+j-1]%=10;
        }
    len=a.len+b.len+1;
    while(len>1&&c.s[len]==0) len--;
    c.len=len;
    return c;
}



void multiply10(hp &a)
//高精度*10

{
    int i;
    for(i=a.len;i>=1;i--)
        a.s[i+1]=a.s[i];
    a.s[1]=0;
    a.len++;
    while(a.len>1&&a.s[a.len]==0) a.len--;
}

hp div(hp &a,hp &b)
//高精度/高精度{d为余数}

{
    hp c, d, e;
    int i,len;
    for(i=1;i<=maxsize;i++)
    {
        c.s[i]=0;
        d.s[i]=0;
    }
    len=a.len;
    d.len=1;
    for(i=len;i>=1;i--)
    {
        multiply10(d);
        d.s[1]=a.s[i];
        while(com(d,b)>=0)
        {
            e = sub(d,b);
            d=e;
            c.s[i]++;
        }
    }
    while(len>1&&c.s[len]==0) len--;
    c.len=len;
    return c;
}

hp mod(hp &a,hp &b)
//高精度/高精度{d为余数}

{
    hp c, d, e;
    int i,len;
    for(i=1;i<=maxsize;i++)
    {
        c.s[i]=0;
        d.s[i]=0;
    }
    len=a.len;
    d.len=1;
    for(i=len;i>=1;i--)
    {
        multiply10(d);
        d.s[1]=a.s[i];
        while(com(d,b)>=0)
        {
            e = sub(d,b);
            d=e;
            c.s[i]++;
        }
    }
    while(len>1&&c.s[len]==0) len--;
    c.len=len;
    return d;
}

hp cstr(int k)
//整数k转化为高精度

{
    char a[100];
    hp x;
    string str;
    int len,i,t;
    len=log10(k)+1;
    for (i=len;i > 0; i--)
    {
        t=k%10;
        k-=t;
        k/=10;
        a[i-1]='0'+t;
    }
    a[len]='\0';
    for (i = 0; i < len; i++)
        str+=a[i];
    x=input( str);
    return x;
}

hp app(hp temp, int k)
//在高精度前面增加一位k

{
    int len = temp.len + 1;
    temp.s[len] = k;
    temp.len = len;
    return temp;
}

  
 
 
接着是素数的生成,用到的是Miller_Rabin算法。这一算法首先要产生一个随机数,判断是否为素数。在判断的过程中最重要的是求a的p次幂模n,如果这个算法没写好,就很容易溢出,或速度慢(可以说是没法运行)。
 

/* 定义0、1、2高精度数 */
hp zero = input("0");
hp one = input("1");
hp two = input("2");

/* 求a的p次幂模n */
hp exp_mod(hp a, hp p, hp n)
{
    hp temp = one, y = a;
    while (com(p, zero) != 0)
    {
        if (com(mod(p, two), one) == 0)
            temp = mod(mul(temp, y), n);
        y = mod(mul(y, y),n);
        p = div(p, two);
    }
    return temp;
}

 

素数的判断如下:

/* 用来生成64比特的数,并转化为十进制的高精度数 */
hp make_64bit()
{
    hp temp = zero;
    hp exp_two = one;
    for (int i = 0; i < 64; i++)
    {
        unsigned random = rand() % 2;
        if (random == 1)
            temp = add(temp, exp_two);
        exp_two = mul(exp_two, two);
    }
    return temp;
}

/* Miller_Rabin算法来判断是否为素数 */
bool Miller_Rabin(hp n)
//为素数返回false,为合数返回true

{
    hp x = make_64bit();
    hp m = sub(n, one);
//m = n -1

    hp i, y, k;

    /* 将n-1分解成2的k次幂乘以m */
    /* for (k = 1; m % 2 == 0; k++)*/
    for(k=one;com(mod(m, two), zero) == 0;k = add(k, one))     
        m = div(m, two);
    y=exp_mod(x,m,n);
//y等于x的m次幂模n

    if(com(y, one) == 0)
        return false;
    for(i=one; com(k, i) > 0; i = add(i, one))
    {
        if (com(mod(y, n), sub(n, one)) == 0 )
            return false;
        y = mod(mul(y,y), n);
    }
    return true;
}

之后,随便写个主函数,就可以产生64位的素数了(当然也能产生其他位数的)。

 

用产生的素数(比如p,q)就可以构造加密和解密算法了,这里除了要用到上面提到的函数外,还要用到的是求与fn=(p-1)*(q-1)互素的e,之后还要求得e的模逆,即e*d=1(mod fn),具体如下:

 

/* 求a与b的最大公约数 */
hp GCD(hp a, hp b)
{
    if (com(b, zero) == 0)
        return a;
    else
        return GCD(b, mod(a, b));
}

/* 求u*x=1(mod m)中的x的值 */
hp moni(hp u, hp m)
{
    hp r1 = m, r2 = u;
    hp b1 = zero, b2 = one;
    hp r3 = two, b3 = zero, q = zero;
    while (com(r3, one) > 0)
    {
        r3 = mod(r1, r2);
        q = div(r1, r2);
        b3 = sub(add(b1, mul(q, m)), mul(q, b2));
        b3 = mod(b3, m);
        if (com(r3, one) > 0)
        {
            r1 = r2; r2 = r3;
            b1 = b2; b2 = b3;
        }
        else
        {
            if (com(r3, one) == 0)
                return mod((add(b3, m)), m);
            else
            {
                cout<<"无解!"<<endl;
                cout<<"(u, m) = ";
                output(r2);
                cout<<endl;
                return zero;
            }
        }
    }
    return zero;
}

其他就不是什么问题了。

PS:本人菜鸟一个,可能会有很多问题,望指正。

发表于: 2008-03-23 ,修改于: 2008-03-24 18:56,已浏览436次,有评论0条 推荐 投诉


网友评论

发表评论