MATLAB实现的playfair加解密

程序下载链接:https://download.csdn.net/download/m0_56241309/87457063

一、实验目的

实验环境: Windows 11操作系统;Matlab2019b

实现目标:

  1. 实现playfair加解密;

  1. 重复的明文字符中间使用明文字符的下一个字符进行填充;

  1. 字符串中出现的J与I全部使用I进行代替;

  1. 实现加密解密交互界面;

  1. 实现加密解密关键步骤信息输出。

二、方案设计

1. 加密过程

  1. 首先获取密钥字符串,进行预处理,将密钥字符串中的所有空格删除,并将所有字母J全部使用I进行代替,最后进行大写处理。

  1. 随后将密钥字符串依次填充进矩阵中,遇到重复的字符则跳过。

  1. 密钥填充结束后,将字母表中的余下字符依次填入矩阵中,遇到此前已经填入的字符则跳过,继续填入下一字符。其中如果此前没有填入I,则须注意J不填入,使用I进行替换。

  1. 填充完成矩阵后,获取明文字符串。首先进行预处理,将明文字符串中的所有空格删除,并将所有的字母J使用I进行替换。此外,重复的明文字符中间插入该字符的下一位字符。如果填充完毕后,明文字符串的长度为奇数,则在最后一个字符的后面填充该字符的下一位字符,最后对其进行大写处理。

  1. 明文字符串预处理结束后,开始加密。如果待加密的两个字符在同一行,则每个字符分别用其下一位字符进行替换,尾字符用该行的首字符进行替换;如果待加密的两个字符在同一列,则每个字符分别用其下一位字符进行替换,尾字符用该列的首字符进行替换;如果待加密的字符不在同一行也不在同一列,则每个字符用两字符组成的矩阵的对角字符分别进行替换。

  1. 对明文字符串中每一对字符进行加密处理后,便得到最终的密文字符串

2. 解密过程

  1. 首先获取密文字符串,由于密文字符串已经经过了预处理,因此无需对其进行多余的操作

  1. 获取密钥字符串,对其进行预处理。将所有的空格进行删除,并将所有J使用I替换,然后大写化。处理完毕后,将其填充到矩阵中,出现过的字符跳过,继续填充下一位字符。

  1. 密钥填充结束后,将字母表中的余下字符依次填入矩阵中,遇到此前已经填入的字符则跳过,继续填入下一字符。其中如果此前没有填入I,则须注意J不填入,使用I进行替换。

  1. 矩阵填充完毕后,可以开始解密。如果待解密的两个字符处在同一行,则每个字符使用其前一位字符进行替换,首字符使用该行的尾字符进行替换;如果待解密的两个字符处在同一列,则每个字符使用其前一位字符进行替换,首字符使用该列的尾字符进行替换;如果待解密的两个字符既不在同一行也不在同一列,则每个字符使用两字符组成的矩阵的对角字符分别进行替换

  1. 对密文字符串中的每一对字符进行解密处理后,便得到最终的明文字符串

3. 信息输出

  1. 设置两个信息输出函数,分别实现加密界面和解密界面的信息输出

4. 交互界面

  1. 基于Matlab2019b中的mlapp编程实现

三、方案实现

1. 加密过程

介绍:加密按钮EnButtom回调函数

function EnButtonPushed(app, event)
            if strcmp(app.Plaintext_En.Value,'')
                logRefresh_func_En(app,'请输入明文');
                return
            end
            if strcmp(app.KeyWord.Value,'')
                logRefresh_func_En(app,'请输入密钥');
                return
            end
            %创建矩阵    
            %    %将J替换成I
            alphabet='ABCDEFGHIKLMNOPQRSTUVWXYZ';
            plain_origion='';
            Key=app.KeyWord.Value;
            Key=upper(Key);
            fbar=waitbar(0,'密钥字符串预处理中');
            pause(0.3)
            %将所有J换成I
            for i=1:length(Key)
                if strcmp(Key(i),'J')
                    Key(i)='I';
                end
            end
            %字符串填入矩阵,跳过重复的字符以及空格
            waitbar(0.25,fbar,'矩阵化密钥字符')
            pause(0.3)
            for i=1:length(Key)
                %如果字符已经填入或者遇到了空格
                if ismember(Key(i),plain_origion)||Key(i)==' '
                    continue
                else
                    plain_origion(i)=Key(i);
                end
            end
            logRefresh_func_En(app,'矩阵化密钥字符完成');
            
            %转换,明文信息填入一维矩阵
            waitbar(0.5,fbar,'密钥信息填入矩阵')
            pause(0.3)
            str='';
            for i=1:length(plain_origion)
                if ismember(plain_origion(i),alphabet)
                       str=strcat(str,plain_origion(i));
                else
                    continue
                end
            end
            logRefresh_func_En(app,'密钥信息填入矩阵成功');
            
            %将剩余字母依次填入一维矩阵(1*25)
            waitbar(0.5,fbar,'填充矩阵信息中,请稍后')
            pause(0.3)
            for i=1:length(alphabet)
                if ismember(alphabet(i),str)
                    continue
                else
                       str=strcat(str,alphabet(i));
                end
            end
            logRefresh_func_En(app,'矩阵填充完成');
            
            %将矩阵转换成5*5的明文矩阵
            waitbar(0.75,fbar,'转置')
            app.PlaintextMat=reshape(str,5,5)';
            waitbar(1,fbar,'矩阵初始化完成')
            pause(0.3)
            logRefresh_func_En(app,'矩阵初始化完成');
            close(fbar)
 
 
%处理明文字符串
%1.当字符串为奇数个时,再最后一个明文字母后面补充其下一位字母
%2.对字符串两两分组,出现一组中字符相同时,在相同的字符中间插入其下一位字符
               Pre_plaintext=app.Plaintext_En.Value;
               Pre_plaintext=upper(Pre_plaintext);
            %将所有J换成I
            for i=1:length(Pre_plaintext)
                if strcmp(Pre_plaintext(i),'J')
                    Pre_plaintext(i)='I';
                end
            end
 
            %首先去除明文中的空格
            fbar=waitbar(0,'正在去除空格,请稍后');
            pause(0.3)
            Bridge='';
            for i=1:length(Pre_plaintext)
                waitbar(i/length(Pre_plaintext),fbar,'删除空格中,请稍后');
                pause(0.01);
                if Pre_plaintext(i)==' '
                    continue
                else
                       Bridge=strcat(Bridge,Pre_plaintext(i));
                end
            end
            logRefresh_func_En(app,'空格删除完毕');
            Pre_plaintext=Bridge;
            %如果字符串长度为奇数,则填充下一位字符
            if mod(length(Pre_plaintext),2)~=0
                location=find(alphabet==Pre_plaintext(length(Pre_plaintext)));
                if location==25
                       Pre_plaintext=strcat(Pre_plaintext,'A');
                else
                    Pre_plaintext=strcat(Pre_plaintext,alphabet(location+1));
                end
            end
            waitbar(1,fbar,'奇偶检查完毕');
            logRefresh_func_En(app,'奇偶检查完毕');
            pause(0.3);
            %如果出现了重复的字母则再重复字母中间插入重复字母的下一位字母
            %先查找字符串中重复的组别个数
            Num=0;
            for i=1:length(Pre_plaintext)-1
                if Pre_plaintext(i)==Pre_plaintext(i+1)
                    Num=Num+1;
                end
                i=i+1;
            end
            %插入新字符
            for i=1:length(Pre_plaintext)+Num-1
                waitbar(i/length(Pre_plaintext)+Num-1,fbar,'字符插入中');
                pause(0.01);
                if Pre_plaintext(i)==Pre_plaintext(i+1)
                    Pre_plaintext(i+2:end+1)=Pre_plaintext(i+1:end);
                    address=find(alphabet==Pre_plaintext(i));
                    if address==25
                        Pre_plaintext(i+1)='A';
                    else
                        Pre_plaintext(i+1)=alphabet(address+1);
                    end
                end
                i=i+1;
            end
            logRefresh_func_En(app,'字符插入完成');
            %字符串处理完毕开始加密信息
            app.Ciphertext='';
            for i=1:2:length(Pre_plaintext)-1
                waitbar(i/length(Pre_plaintext)-1,fbar,'加密中,请稍后');
                pause(0.01);
                %获取相邻两个字符的在 PlaintextMat 中的位置
                [M,N]=find(app.PlaintextMat==Pre_plaintext(i));
                [m,n]=find(app.PlaintextMat==Pre_plaintext(i+1));
                %如果在同一行
                if M==m
                    %处理第一个字符,检查mod(N,5)是否为零
                    if mod(N,5)==0
                        %如果为零则需将此处置换为本行第一个字符
                           app.Ciphertext=strcat(app.Ciphertext,app.PlaintextMat(M,1));
                    else
                        %否则置换为矩阵中同行的下一位字符
                           app.Ciphertext=strcat(app.Ciphertext,app.PlaintextMat(M,N+1));
                    end
                    
                    %处理第二个字符,检查mod(n,5)是否为零
                    if mod(n,5)==0
                        %如果为零则需将此处置换为本行第一个字符
                           app.Ciphertext=strcat(app.Ciphertext,app.PlaintextMat(m,1));
                    else
                        %否则置换为矩阵中同行的下一位字符
                           app.Ciphertext=strcat(app.Ciphertext,app.PlaintextMat(m,n+1));
                    end
                    
                %如果在同一列     
                elseif N==n
                    %处理第一个字符,检查mod(M,5)是否为零
                    if mod(M,5)==0
                        %如果为零,则需要将此处置换为本列的第一个字符
                           app.Ciphertext=strcat(app.Ciphertext,app.PlaintextMat(1,N));
                    else
                        %否则置换为矩阵中同列的下一位字符
                           app.Ciphertext=strcat(app.Ciphertext,app.PlaintextMat(M+1,N));
                    end
                    
                    %处理第二个字符,检查mod(m,5)是否为零
                    if mod(m,5)==0
                        %如果为零,则需要将此处置换为本列的第一个字符
                           app.Ciphertext=strcat(app.Ciphertext,app.PlaintextMat(1,n));
                    else
                        %否则置换为矩阵中同列的下一位字符
                           app.Ciphertext=strcat(app.Ciphertext,app.PlaintextMat(m+1,n));
                    end
                    
                %如果位置行列相互错开
                else
                    %处理第一个字符
                       app.Ciphertext=strcat(app.Ciphertext,app.PlaintextMat(M,n));
                    %处理第二个字符
                       app.Ciphertext=strcat(app.Ciphertext,app.PlaintextMat(m,N));
                end
            end
            waitbar(1,fbar,'加密完成');
            pause(0.3);
            logRefresh_func_En(app,'加密完成')
            close(fbar);
               app.Crypt_En.Value=app.Ciphertext;
               app.Crypt_De.Value=app.Ciphertext;
end

2. 解密过程

介绍:解密按钮DeButtom回调函数

function DeButtonPushed(app, event)
            ifstrcmp(app.Crypt_De.Value,'')
                logRefresh_func_De(app,'请输入密文');
                return
            end
            ifstrcmp(app.KeyWord_De.Value,'')
                logRefresh_func_De(app,'请输入密钥');
                return
            end
            %创建矩阵    
            % %将J替换成I
            alphabet='ABCDEFGHIKLMNOPQRSTUVWXYZ';
            plain_origion='';
            Key=app.KeyWord_De.Value;
            Key=upper(Key);
            fbar=waitbar(0,'密钥字符串预处理中');
            pause(0.3)
            %将所有J换成I
            for i=1:length(Key)
                ifstrcmp(Key(i),'J')
                    Key(i)='I';
                end
            end
            %字符串填入矩阵,跳过重复的字符以及空格
            waitbar(0.25,fbar,'矩阵化密钥字符')
            pause(0.3)
            for i=1:length(Key)
                %如果字符已经填入或者遇到了空格
                ifismember(Key(i),plain_origion)||Key(i)==' '
                    continue
                else
                    plain_origion(i)=Key(i);
                end
            end
            logRefresh_func_De(app,'矩阵化密钥字符完成');
            
            %转换,明文信息填入一维矩阵
            waitbar(0.5,fbar,'密钥信息填入矩阵')
            pause(0.3)
            str='';
            for i=1:length(plain_origion)
                ifismember(plain_origion(i),alphabet)
                    str=strcat(str,plain_origion(i));
                else
                    continue
                end
            end
            logRefresh_func_De(app,'密钥信息填入矩阵成功');
            
            %将剩余字母依次填入一维矩阵(1*25)
            waitbar(0.5,fbar,'填充矩阵信息中,请稍后')
            pause(0.3)
            for i=1:length(alphabet)
                ifismember(alphabet(i),str)
                    continue
                else
                    str=strcat(str,alphabet(i));
                end
            end
            logRefresh_func_De(app,'矩阵填充完成');
            
            %将矩阵转换成5*5的明文矩阵
            waitbar(0.75,fbar,'转置')
            app.PlaintextMatDe=reshape(str,5,5)';
            waitbar(1,fbar,'矩阵初始化完成')
            pause(0.3)
            logRefresh_func_De(app,'矩阵初始化完成');
            close(fbar)
            
            %获取密文
            fbar=waitbar(0,'获取密文中');
            Ciphertext_De=app.Ciphertext;
            app.Plaintext='';
            logRefresh_func_De(app,'解密中,请稍后')
            for i=1:2:length(Ciphertext_De)-1
                waitbar(i/length(Ciphertext_De)-1,fbar,'解密中,请稍后');
                pause(0.01);
                %获取相邻两个字符的在PlaintextMat 中的位置
                [M,N]=find(app.PlaintextMatDe==Ciphertext_De(i));
                [m,n]=find(app.PlaintextMatDe==Ciphertext_De(i+1));
                %如果在同一行
                ifM==m
                    %处理第一个字符,检查mod(N,5)是否为零
                    ifN==1
                        %如果为零则需将此处置换为本行尾字符
                        app.Plaintext=strcat(app.Plaintext,app.PlaintextMatDe(M,5));
                    else
                        %否则置换为矩阵中同行的上一位字符
                        app.Plaintext=strcat(app.Plaintext,app.PlaintextMatDe(M,N-1));
                    end
                    
                    %处理第二个字符,检查mod(n,5)是否为零
                    ifn==1
                        %如果为零则需将此处置换为本行尾字符
                        app.Plaintext=strcat(app.Plaintext,app.PlaintextMatDe(m,5));
                    else
                        %否则置换为矩阵中同行的上一位字符
                        app.Plaintext=strcat(app.Plaintext,app.PlaintextMatDe(m,n-1));
                    end
                    
                %如果在同一列     
                elseifN==n
                    %处理第一个字符,检查mod(M,5)是否为零
                    ifM==1
                        %如果为零,则需要将此处置换为本列的尾巴字符
                        app.Plaintext=strcat(app.Plaintext,app.PlaintextMatDe(5,N));
                    else
                        %否则置换为矩阵中同列的上一位字符
                        app.Plaintext=strcat(app.Plaintext,app.PlaintextMatDe(M-1,N));
                    end
                    
                    %处理第二个字符,检查mod(m,5)是否为零
                    ifm==1
                        %如果为零,则需要将此处置换为本列的尾巴字符
                        app.Plaintext=strcat(app.Plaintext,app.PlaintextMatDe(5,n));
                    else
                        %否则置换为矩阵中同列的上一位字符
                        app.Plaintext=strcat(app.Plaintext,app.PlaintextMatDe(m-1,n));
                    end
                    
                %如果位置行列相互错开
                else
                    %处理第一个字符
                    app.Plaintext=strcat(app.Plaintext,app.PlaintextMatDe(M,n));
                    %处理第二个字符
                    app.Plaintext=strcat(app.Plaintext,app.PlaintextMatDe(m,N));
                end
            end
            waitbar(1,fbar,'解密完成');
            pause(0.3);
            logRefresh_func_De(app,'解密完成')
            close(fbar);
            app.Plaintext_De.Value=app.Plaintext;
end

3. 信息输出

介绍:加密界面信息输出函数logRefresh_func_En

function logRefresh_func_En(app,StrArrayNew)
            app.Ptime=datestr(now);
            app.LOG=strcat('[',app.Ptime(end-7:end),']');
            StrArrayNew=strcat(app.LOG,StrArrayNew);
            app.StrArray_En=[app.StrArray_En,StrArrayNew,newline];
            app.Process_En.Value=app.StrArray_En;
end

介绍:解密界面信息输出函数logRefresh_func_De

function logRefresh_func_De(app,StrArrayNew)
            app.Ptime=datestr(now);
            app.LOG=strcat('[',app.Ptime(end-7:end),']');
            StrArrayNew=strcat(app.LOG,StrArrayNew);
            app.StrArray_De=[app.StrArray_De,StrArrayNew,newline];
            app.Process_De.Value=app.StrArray_De;
end

4. 交互界面

Matlab2019b的mlapp开发环境

四、数据测试与分析

1. 数据测试

  1. 加密过程

  1. 解密过程

  1. 加解密演示

2. 分析

在playfair加解密中,加密方与解密方需要实现确定一个密钥词,使用该密钥生成“密钥矩阵”。加密方首先使用密钥词,将其中的J替换成I,并依次进行填充,遇到重复的字符就接着处理下一位字符。密钥填充完毕后,需要对余下的其余字母表字符进行填充,同样的需要避免填入重复的字符。填充结束后,便可以使用该表进行字符的代换。在开始加密之前,首先对明文字符串进行处理,将所有的空格删除,所有的J替换成I,并在重复的字符中间插入该字符的下一位字符。随后检查字符串是否长度为奇数,否则需要进行末端的字符填充,在其后补充下一位字符。处理结束后开始加密,如果待加密的两个字符在同一行,则每个字符分别用其下一位字符进行替换,尾字符用该行的首字符进行替换;如果待加密的两个字符在同一列,则每个字符分别用其下一位字符进行替换,尾字符用该列的首字符进行替换;如果待加密的字符不在同一行也不在同一列,则每个字符用两字符组成的矩阵的对角字符分别进行替换。

解密方在使用同样的方式输入密钥词后,创建同样的代换表。随后将密文字符串中的每一对字符进行解密,也就是按照代换表依次进行代换。如果待解密的两个字符处在同一行,则每个字符使用其前一位字符进行替换,首字符使用该行的尾字符进行替换;如果待解密的两个字符处在同一列,则每个字符使用其前一位字符进行替换,首字符使用该列的尾字符进行替换;如果待解密的两个字符既不在同一行也不在同一列,则每个字符使用两字符组成的矩阵的对角字符分别进行替换,最终得到明文。

五、总结

  1. 在playfair加解密中,对字符串的处理比较复杂。需要对密钥以及明文进行预处理,如约定将J替换成I,以及约定在重复的字符中间插入下一位字符,以及在奇数长度的字符串后填充尾字符的下一位字符,确保明文字符串可以拆分为一对一对的字符对进行代换

  1. 在加密过程中,同样涉及了比较复杂的代换操作,需要区别对待每一对明文字符,根据其位置的不同分别使用不同的代换方式,最终才能得到密文

  1. 解密过程同样,需要注意对字符串的预处理。此外,在解密过程中,同样需要区别对待每一对密文字符,根据其位置分别采用不同的相反的代换方式,最终得到明文

  1. 在实现playfair加解密的过程中涉及了大量的字符串处理操作,matlab中对字符串的处理需要格外注意其索引从1开始

  1. 此外,matlab处理字符串时存在许多函数可以方便编程过程,如判断是否已经填充过某一字符时可以使用ismember()函数来判断

  1. 由于playfair加解密是比较复杂的代换密码,因此在实现过程中需要反复地确定过程是否正确,为此需要将代码放入脚本文件中执行,确认无误后才写入mlapp文件中

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BumbleStone

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值