1. 程式人生 > 實用技巧 >c語言實現多表代換密碼演算法及求逆元

c語言實現多表代換密碼演算法及求逆元

密文及明文預設長度為4的倍數
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int ex_gcd(int a,int b,int &x,int &y)       //擴充套件歐幾里得 
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    int r=ex_gcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-a/b*y;
    return r;
}

int re_yuan(int a,int b)                    //求a的逆元x 
{
    int d,x,y;
    d=ex_gcd(a,b,x,y);
    return (x%b+b)%b;
}

void IuputAre_A(int A[][4])                 //A與A^-1的輸入
{
    for (int i = 0; i < 4;i++)
        for (int j = 0; j < 4; j++)
            scanf("%d", &A[i][j]);
}

void InputB(int B[])                        //B輸入
{
    for (int i = 0; i < 4;i++)
        scanf("%d", &B[i]);
}

bool checkA(int A[][4],int re_A[][4])                               //驗證金鑰的正確性(即A*A^-1=E)
{
    for (int i = 0; i < 4;i++)
    {
        for (int j = 0; j < 4;j++)
        {
            int sum = A[i][0]*re_A[0][j]+A[i][1]*re_A[1][j]+A[i][2]*re_A[2][j]+A[i][3]*re_A[3][j];
            //printf("\n%f %f %f %f %f %f %f %f \n",A[i][0],re_A[0][j],A[i][1],re_A[1][j],A[i][2],re_A[2][j],A[i][3],re_A[3][j]);
            //printf("sum is %f\n", sum);
            //printf("sum is %d\n", sum%26);
            if(i==j)
            {
                if(sum%26!=1)
                    return 0;
            }else
            {
                if(sum%26!=0)
                    return 0;
            }
        }
    }
    return 1;
}

void Encrypt(int A[][4],char Enstring[],int StrLen,int B[])         //加密函式,引數為 A,要加密的明文,明文長度,B
{
    char M[StrLen/4][4];
    for (int i = 0; i < StrLen;i++)
    {
        Enstring[i] -= 65;
    }
    for (int i = 0; i < StrLen / 4; i++)           //求Ci
    {
        for (int j = 0; j < 4; j++)
        {
            M[i][j] = (Enstring[i * 4] * A[j][0] + Enstring[i * 4 + 1] * A[j][1] + Enstring[i * 4 + 2] * A[j][2] + Enstring[i * 4 + 3] * A[j][3] + B[j]) % 26;
        }
    }
    for (int i = 0; i < StrLen/4;i++)                                //數字對應字母
    {
        for(int j=0;j<4;j++)
        {
            if(M[i][j]<0)
				M[i][j] += 26;
            Enstring[i*4+j] = M[i][j]+65;
        }
    }

}

void Decrypt(int re_A[][4],char Destring[],int StrLen,int B[])      //解密函式,引數為 A^-1,要解密的密文,密文長度,B
{
    char M[StrLen/4][4];
    for (int i = 0; i < StrLen;i++)
    {
        Destring[i] -= 65;
    }
    for (int i = 0; i < StrLen / 4;i++)                            //英文字母和十進位制數對應
    {
        for (int j = 0; j < 4;j++)
        {
             Destring[i * 4 + j] -= B[j];
        }
    }
    for (int i = 0; i < StrLen / 4;i++)                            //求Mi
    {
        for (int j = 0; j < 4;j++)
        {
            M[i][j] = (Destring[i * 4] * re_A[j][0] + Destring[i * 4 + 1] * re_A[j][1] + Destring[i * 4 + 2] * re_A[j][2] + Destring[i * 4 + 3] * re_A[j][3] ) % 26;
        }
    }
    for (int i = 0; i < StrLen/4;i++)                                //數字對應字母
    {
        for(int j=0;j<4;j++)
        {
            if(M[i][j]<0)
				M[i][j] += 26;
            Destring[i*4+j] = M[i][j]+65;
        }
    }

}

int main(){
    int A[4][4], B[4],re_A[4][4];
{                                                      //A、B、A^-1的輸入
    printf("請輸入加密金鑰金鑰(A,B)和解密金鑰A^-1 (分組為4):\nA:");
    IuputAre_A(A);                  //A的輸入
    printf("\nB:");
    InputB(B);                      //B的輸入
    printf("\nA^-1:");
    IuputAre_A(re_A);               //A^-1的輸入
}
    while(1){                                         //驗證金鑰的正確性(即A*A^-1=E),若不正確則提示再次輸入
        if(!checkA(A,re_A)){
            system("cls");
            printf("請輸入正確的A和A^-1!\nA:");
            IuputAre_A(A);
            printf("A^-1:");
            IuputAre_A(re_A);
            continue;
        }
        break;
    }
    while(1){
    printf("\n請輸入功能序號:\n0.加密\n1.解密\n2.求逆元\n3.退出程式\n");
    int FunType;
    scanf("%d", &FunType);
    if(FunType==3)
    {
        return 0;
    }
    else if(FunType==0)                               //功能0.加密
    {                             
        char EnString[1000];
        printf("請輸入待加密明文(長度為四的倍數):");
        scanf("%s", EnString);
        int StrLen = strlen(EnString);
        Encrypt(A, EnString,  StrLen,  B);
        printf("加密後的密文是:%s\n", EnString);
    }
    else if(FunType==1)                               //功能1.解密
    {
        char DeString[1000];
        printf("請輸入待解密密文(長度為四的倍數):");
        scanf("%s", DeString);
        int StrLen = strlen(DeString);
        if(StrLen%4!=0)                              //對長度不是4的倍數的明文的處理,
        {
            for (int i = 0; i < (StrLen % 4); i++)
            {
                DeString[StrLen + i] = ' ';
            }
            StrLen += 4 - StrLen % 4;
            DeString[StrLen] = 0;                     //字串以0結尾
        }
        Decrypt(re_A, DeString,  StrLen,  B);
        printf("解密後的明文是:%s\n", DeString);
    }
    else if(FunType==2)                               //功能2.求逆元
    {
        int a, m;
        printf("a:");
        scanf("%d", &a);
        printf("m:");
        scanf("%d", &m);
        printf("\n%d模%d 的逆元為:%d\n", a, m, re_yuan(a, m));
    }
    else
    {
        printf("請輸入正確的功能編號!");
    }
    } 
}