【密码学1】分组密码(DES)

(一)实验要求

1、编写程序实现分组密码(DES)加、解密:
(1)编程实现基于自己的名字来构造一分组密码的密钥;
(2)应用(1)获得的密钥将一段英文(或文件)进行加、解密;
2、用分组密码实现口令的安全:
如:登陆计算机(或连接服务器)时,用户的口令作为分组密码密钥,加密某个固定的明文,生成的密文存储在计算机中。下次登陆时,把生成的密文和已存储的密文进行比较,若一致则登陆成功。也可用其它方法,只要实现口令登陆即可。

(二)实验原理:

1.所需参数

key:8个字节共64位的工作密钥
data:8个字节共64位的需要被加密或被解密的数据  
mode:DES工作方式,加密或者解密

2.初始置换

DES算法使用64位的密钥key将64位的明文输入块变为64位的密文输出块,并把输出块分为L0、R0两部分,每部分均为32位。初始置换规则为:将输入的64位明文的第1位置换到第40位,第2位置换到第8位,第3位置换到第48位。以此类推,最后一位是原来的第7位。

3.加密处理–迭代过程

经过初始置换后,进行16轮完全相同的运算,在运算过程中数据与密钥结合、函数f的输出经过一个异或运算,和左半部分结合形成新的右半部分,原来的右半部分成为新的左半部分。每轮迭代的过程可以表示如下:Ln = R(n - 1);Rn = L(n - 1)⊕f(Rn-1,kn-1)
函数f由四步运算构成:密钥置换(子密钥Kn的生成,n=0~16);扩展置换;S-盒代替;P-盒置换。

4.逆置换

将初始置换进行16次的迭代,即进行16层的加密变换,这个运算过程我们暂时称为函数f。得到L16和R16,将此作为输入块,进行逆置换得到最终的密文输出块。

5.DES解密

加密和解密可以使用相同的算法。加密和解密唯一不同的是密钥的次序是相反的。就是说如果每一轮的加密密钥分别是K1、K2、K3…K16,那么解密密钥就是K16、K15、K14…K1。为每一轮产生密钥的算法也是循环的。加密是密钥循环左移,解密是密钥循环右移。

(三)主要代码:

1. 类型转换功能:完成字符和二进制之间的相互转换

(1)转换为二进制(用于明文、密钥)

void change(char s[],int flag)///转换为二进制
{
    int l=0;
    for(int i=0; i<8; i++)
    {
        int n=s[i],time=0;
        memset(zhongbit,0,sizeof(zhongbit));
        while(n!=0)
        {
            zhongbit[time++]=n%2;
            n/=2;
        }
        if(flag==1)
        {
            for(int j=7; j>=0; j--)
                smbit[l++]=zhongbit[j];
        }
        else if(flag==2)
        {
            for(int j=7; j>=0; j--)
                miyaobit[l++]=zhongbit[j];
        }
    }
}

(2)将二进制转换成16进制密文

void zhuan()///将二进制转换成16进制密文
{
    int ans=0,l=0;
    for(int i=0; i<64; i++)
    {
        if((i+1)%4==0)
        {
            ans=smbit[i-3]*8+smbit[i-2]*4+smbit[i-1]*2+smbit[i];
            if(ans>9)
                miwen[l++]='A'+ans-10;
            else
                miwen[l++]=ans+'0';
            ans=0;
        }
    }
}

2.IP初始置换

void ipzhihuan()///第一次循环使用的ip置换
{
    for(int i=0; i<64; i++)
        mip[i]=smbit[IP[i]-1];///下标从0开始
    fen();
    memset(smbit,0,sizeof(smbit));
}

3. E盒扩展

void EK()///E盒扩展
{
    memset(rr,0,sizeof(rr));
    for(int i=0; i<48; i++)
        rr[i]=Right[E[i]-1];///下标从0开始
}

4. 异或及S盒压缩

void SY(int k)///异或及S盒压缩
{
    for(int i=0; i<48; i++)
        rr[i]^=zimi[k][i];
    int c=0;
    for(int i=0; i<48; i++)
    {
        if((i+1)%6==0)///进入下个s盒
        {
            int w=(i+1)/6,h,l;///哪个盒,哪一行那一列
            h=rr[i-5]*2+rr[i]*1;
            l=rr[i-4]*8+rr[i-3]*4+rr[i-2]*2+rr[i-1]*1;
            int ans=S[w-1][h][l];
            int tt=0;
            memset(er,0,sizeof(er));
            while(ans)
            {
                er[tt++]=ans%2;
                ans/=2;
            }
            for(int j=3; j>=0; j--)
                SYa[c++]=er[j];
        }
    }
}

5. P盒置换

void PHe()///P盒置换
{
    for(int i=0; i<32; i++)
        Right[i]=Left[i]^SYa[P[i]-1];
    for(int i=0; i<32; i++)
        Left[i]=mip[32+i];
    for(int i=0; i<32; i++)
    {
        mip[i]=Left[i];
        mip[32+i]=Right[i];
    }
    fen();///分为左右两部分
}

6.逆置换

void nizhihuan()///逆初始置换表
{
    for(int i=0; i<64; i++)
        smbit[i]=mip[IP_1[i]-1];
}
void PC_1zhi()///置换选择pc1盒及循环移位
{
    if(times==0)///只有当是第一次的时候才会进行PC置换盒1
    {
        for(int i=0; i<56; i++)
            miyaopc1[i]=miyaobit[PC_1[i]-1];///下标从0开始
    }
    for(int i=0; i<28; i++) ///分为两部分,循环移位
    {
        int ans=i+xz[times];
        if(ans>27)
            ans-=28;
        c[i]=miyaopc1[ans];///得到前半部分
        d[i]=miyaopc1[28+ans];///得到后半部分
    }
    for(int i=0; i<28; i++)
    {
        miyaopc1[i]=c[i];
        miyaopc1[28+i]=d[i];
    }
    times++;
}

7.轮置换,子密钥生成

void PC_2zhi()///16轮置换,pc2盒得到子密钥
{
    for(int k=0; k<16; k++)
    {
        PC_1zhi();
        for(int i=0; i<48; i++)
            zimi[k][i]=miyaopc1[PC_2[i]-1];///将每一次产生的子密钥存下来
    }
}

8.DES加密

void jiami()  ///加密算法
{
    PC_2zhi();  ///子密钥产生
    ipzhihuan();  ///ip置换
    for(int i=0; i<16; i++)  ///一样的方式一共循环15次
    {
        EK();  ///E盒扩展
        SY(i);  ///S盒压缩
        PHe();  ///p盒置换
    }
    for(int i=0; i<32; i++)
    {
        mip[32+i]=LL[16][i];
        mip[i]=RR[16][i];
    }
    nizhihuan();  ///逆初始置换表
    zhuan();  ///将二进制转换成16进制密文
}

9.DES解密

void jiemi()  ///解密算法
{
    cnt=0;
    memset(LL,0,sizeof(LL));
    memset(RR,0,sizeof(RR));
    ipzhihuan();  ///ip置换
    for(int i=0; i<16; i++)  ///一样的方式一共循环15次
    {
        EK();  ///E盒扩展
        SY(15-i);  ///S盒压缩
        PHe();  ///p盒置换
    }
    for(int i=0; i<32; i++)
    {
        mip[32+i]=LL[16][i];
        mip[i]=RR[16][i];
    }
    nizhihuan();  ///逆初始置换表
}

10.主函数

int main()
{
    init();
    printf("请输入8位明文:");
    scanf("%s",mingwen);  //输入明文 
    change(mingwen,1);  ///明文转换为二进制
    printf("\n请输入8位密钥:");
    scanf("%s",miyao);  //输入密文 
    change(miyao,2);  ///密钥转换为二进制
    jiami();  ///加密算法
    printf("加密完成,得到十六进制密文:\n");
    printf("%s\n",miwen);
    jiemi();  ///解密算法
    printf("\n解密完成,得到明文:\n\n");
    for(int i=0;i<64;i++)
    {
        if((i+1)%8==0)
        {
            int ans=smbit[i-7]*128+smbit[i-6]*64+smbit[i-5]*32+smbit[i-4]*16
+smbit[i-3]*8+smbit[i-2]*4+smbit[i-1]*2+smbit[i];
            printf("%c",ans);
        }
    }
    printf("\n");
    return 0;
}

11. 口令安全(从网络上查找到了以下代码,但未能完成操作)

11. 口令安全(从网络上查找到了以下代码,但未能完成操作)
void koulinganquan()//口令安全验证
{
char key[17];
char fileName1[64];
char fileName2[64];
char fileP[Max];
char c[Max];
strcpy(fileName1,"m.txt");
strcpy(fileName2,"c.txt");
int plen;
int klen;
readStrFromFile(fileName2,c);
if(strlen(c) == 0)//无密码
{
printf("无密码,请输入密码\n");
printf("输入密码\n");
scanf("%s",key);
klen=strlen(key);//输入密码
while(1)
{
if(klen != 0&&klen%16 == 0)
{break;}
else
{ 
klen++;
strcat(key,"0");
}
}
readStrFromFile(fileName1,fileP);//读取密文文件
readPlainText(fileP, &plen);//读取明文文件
aes(fileP, plen, key);//开始加密
writeStrToFile(fileP,plen,fileName2);//写入密文文件
printf("输入成功!\n");
}
else
{
printf("输入密码\n");
scanf("%s",key);
klen=strlen(key);
while(1)//密钥填充
{
if(klen != 0&&klen%16 == 0)
{break;}
else
{
klen++;
strcat(key,"0");
}
}
readStrFromFile(fileName1,fileP);//读取密文文件
readPlainText(fileP, &plen);//读取明文文件
aes(fileP, plen, key);//开始加密
if(strcmp(fileP,c) == 0)//比较
{
printf("密码正确\n");
printf("若要修改密码请输入'1',否则输入'0'\n");
int i;
scanf("%d",&i);
if(i == 1)
{
printf("输入密码\n");
scanf("%s",key);
klen=strlen(key);
while(1)
{
if(klen != 0&&klen%16 == 0)
{break;}
else
{
klen++;
strcat(key,"0");
}
}
readStrFromFile(fileName1,fileP);
readPlainText(fileP, &plen);
aes(fileP, plen, key);//开始加密
writeStrToFile(fileP,plen,fileName2);
printf("修改成功!\n");
}
}
else
printf("密码错误\n");
}
}

实验结果

1.(1)DES加密:根据提示输入密钥和需要加密的明文,随后得到加密后的密文。
在这里插入图片描述

图1-1 DES加密

(2)DES解密:解密(1)中密文得到解密后的明文,发现与(1)中的明文相同,证明DES加解密的正确性。
在这里插入图片描述

图1-2 DES解密
2.分组密码实现口令的安全
登陆计算机(或连接服务器)时,用户的口令作为分组密码密钥,加密某个固定的明文,生成的密文存储在计算机中。下次登陆时,把生成的密文和已存储的密文进行比较,若一致则登陆成功。从网络上查找到了口令安全代码(见(二)中代码部分),多次实践,但因能力不足,最终未能完成页面的实现。

总结

1.进一步熟悉掌握了DES加密解密的原理

2.DES算法的特点:

(1)分组加密算法:以64位为分组。64位明文输入,64位密文输出。
(2)对称算法:加密和解密使用同一密钥
(3)有效密钥长度:为56位密钥通常表示为64位数,但每个第8位用作奇偶校验,可以忽略。
(4)代替和置换:DES算法是两种加密技术的组合:混乱和扩散。先替代后置换。
(5)易于实现:DES算法只是使用了标准的算术和逻辑运算,其作用的数最多也只有64 位

3.了解到DES要求密钥长度为8字节,那对于不是8字节的密钥的一些解决方法,例如:

若用户输入字符数小于8,可以在密钥最后随机填充足够的字符以补足8字节长度;
若用户输入字符数大于8,可以在这个字符串中随机选择8个字符作为密钥。

4.

对于分组密码实现口令的安全这部分实验内容,虽然最终未能实现其功能,但在做尝试的过程中也学习到了很多:上个学期曾做过一个数据库的登录实验(预先注册账号及密码,登录时直接输入用户密码登录),当时以为登录时只是比较输入的用户名、密码是否在已注册的数据库中即可,通过这次试验了解到,登陆计算机或连接服务器时,用户的口令是作为分组密码密钥,加密某个固定的明文,生成的密文存储在计算机中。下次登陆时,把生成的密文和已存储的密文进行比较,若一致才能够登陆成功。

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值