playfair密码和凯撒密码加密算法的Java实现

一、实现广义的凯撒密码加密算法

//实现广义的凯撒密码
    //凯撒密码的加密
    String plaintext="";
    String ciphertext="";
    public String enk(){
        System.out.println("请输入明文");
        Scanner sc = new Scanner(System.in);
        plaintext = sc.next();
        char[] chars = plaintext.toCharArray();
        for(int i=0; i<chars.length; i++){
            int j = chars[i];
            chars[i] = (char)(j+3);
            ciphertext += chars[i];
        }
        return ciphertext;
    }

二、实现广义的playfair密码的加密算法

package Bender;
import java.util.Scanner;
public class Test {
    String plaintext="";
    String ciphertext="";
    /*
    实现playfair密码加密
     */
    public char[][] playk() {//将给出的密码字符串加入到密码表中
        System.out.println("请输入编制密码表的单词");
        Scanner sc = new Scanner(System.in);
        plaintext = sc.next();
        char[] chars1 = plaintext.toCharArray();//转换为字符数组
        char[][] chars2 = new char[5][5];//空的密码表
        //编制密码表
        chars2[0][0] = chars1[0];//直接将第一个字符加入密码表
        int num = 1;//记录密码表中的已有元素个数
        for(int i=1; i<chars1.length; i++){//对明文字符数组(一维数组)进行遍历
            if('i'==chars1[i]||'j'==chars1[i]) {//插入的是i||j
                for(int j=0; j<=(num/5); j++) { //对密码表(二维数组)进行遍历
                    boolean jud = false;
                    for (int k = 0; k < 5; k++) {//插入密码表的操作只有两种情况
                        if (chars2[j][k]=='\0') {//遍历到空,说明密码表中的密码遍历完了没有找到相同的,那么就应该执行插入操作,并且跳出对密码表(二维数组)的遍历
                            chars2[j][k] = 'i';
                            jud = true;
                            num++;
                            break;
                        } else if ("i".equals(chars2[j][k]) || "j".equals(chars2[j][k])) {//遍历到密码表中存在相同的字符时就不必插入密码表了,应该直接跳出对密码表(二维数组)的遍历
                            jud = true;
                            break;
                        }
                    }
                    if (jud) {
                        break;
                    }
                }
            }else {//正常插入
                for(int j=0; j<=(num/5); j++){
                    boolean jud = false;
                    for(int k=0; k<5; k++){//注意空字符的判断 ch=='\0';
                        if (chars2[j][k]=='\0') {//遍历到空,说明密码表中的密码遍历完了没有找到相同的,那么就应该执行插入操作,并且跳出对密码表(二维数组)的遍历
                            chars2[j][k] = chars1[i];
                            jud = true;
                            num++;
                            break;
                        } else if(chars1[i]==chars2[j][k])
                        {//遍历到密码表中存在相同的字符时就不必插入密码表了,应该直接跳出对密码表(二维数组)的遍历
                            jud = true;
                            break;
                        }
                    }
                    if(jud){
                        break;
                    }
                }
            }
        }
        return chars2;
    }
    //将上面没完成的密码表填满,最后返回编制好的密码表
    public char[][] playk2(char[][] ch){
        char[] chgoal = {'a','b','c','d','e','f','g','h','i','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
        for(int i=0; i<chgoal.length; i++){//字母表遍历
            for(int j=0; j<5; j++){//密码表遍历
                boolean jud = false;
                for(int k=0; k<5; k++){
                    if(chgoal[i]==ch[j][k]){//字母已存在密码表中,,直接跳出对密码表的遍历
                        jud = true;
                        break;
                    }else if(ch[j][k]=='\0'){//如果该字母不在密码表中
                        ch[j][k] = chgoal[i];
                        jud = true;
                        break;
                    }
                }
                if(jud){
                    break;
                }
            }
        }
        return ch;
    }
    public void show(char[][] chars){//展示最终编制的密码表
        for(char[] ele: chars){
            for(char ch: ele){
                System.out.print(ch);
            }
            System.out.println();
        }
    }
    //整理明文,返回字符数组
    public char[] splitstr(String str) {
        String strgoal = str.replaceAll(" ","").replaceAll("j","i");//去除字符串中的空格
        char[] ch = new char[strgoal.length()*2];//以字符串两倍的长度创建字符数组
        for(int i=0; i<strgoal.length(); i++){//将字符串中的单个字母添加到字符数组中
            ch[i] = strgoal.charAt(i);
        }
        int index = strgoal.length();//index标识第一个空字符
        for(int i=0; i<ch.length;i=i+2){//整理明文,相同则插入X,如果最后只剩一个字母则加X,注意循环条件i<ch.length而不是i<strgoal.length()
            if(ch[i]!='\0'&&ch[i+1]!='\0'){//如果是正常情况:俩个位置都有值
                if(ch[i]==ch[i+1]){//判断是否字母相同,如果相等的话(不相等则不用执行操作)
                    for(int j=index; j>=i+2; j--){//执行插入X的操纵,从后往前覆盖
                        ch[j] = ch[j-1];
                    }
                    index++;
                    ch[i+1] = 'x';
                }
            }else if(ch[i]!='\0'&&ch[i+1]=='\0'){//第二种情况:前面一个有值,后一个未赋值,将X赋给后一个,此时也意味着ch中的有效字母已经遍历完了,跳出循环即可
                ch[i+1] = 'x';
                break;
            }else{//第三种情况,前后都为空,不执行操作,直接跳出循环即可
                break;
            }
        }
        //此时的字符数组就是整理好的明文
        return ch;
    }
    //最后一步(此时的密码表和整理后的明文已经编制好了,最后一步根据密码表将整理好的明文编译成密文,然后输出)
    public String encryp(char[][] cht, char[] chb){
        //char[] ch = new char[chb.length];//和chb等长的字符数组,用来装密文
        String str = "密文:";
        for(int i=0; i<chb.length; i+=2){//对chb进行遍历,一次遍历相邻的两个
            if(chb[i]!='\0'){
                //用于存放下标
                int x1 = 0;
                int x2 = 0;
                int y1 = 0;
                int y2 = 0;
                for(int j=0; j<5; j++){//对密码表进行遍历,确定明文字母在密码表中的坐标
                    for(int k=0; k<5; k++){
                        if(chb[i]==cht[j][k]){
                            x1 = j;
                            y1 = k;
                        }
                        if(chb[i+1]==cht[j][k]){
                            x2 = j;
                            y2 = k;
                        }
                    }
                }
                System.out.println(cht[x1][y1]+"(" + x1 + "," + y1 + ")" + cht[x2][y2]+"(" + x2 + "," + y2 + ")");
                //获取到两个下标后进行判断,一共有三种情况
                if(x1==x2){//两个字母在同一行
                    if(y1>y2){//第一个字母在第二个字母右边
                        str += ""+cht[x1][y1]+cht[x1][(y1+1)%5];
                    }else{//第一个字母在第二个字母在左边(不可能相等,在整理明文的时候已经处理了)
                        str += ""+cht[x1][y2]+cht[x1][(y2+1)%5];
                    }

                }else if(y1==y2) {//两个字母在同一列
                    if(x1<x2){//第一个字母b在第二个a上面
                        str += ""+cht[x2][y2]+cht[(x2+1)%5][y2];
                    }else{
                        str += ""+cht[(x1+1)%5][y1]+cht[x1][y1];
                    }
                }else{//对角,横着取值
                    str += ""+cht[x1][y2]+cht[x2][y1];
                }
            }
        }
        return str;
    }
    public static void main(String[] args) {
        Test t = new Test();
        System.out.println(t.enk());
        //playk()将给出的密码字符串加入到密码表中,返回二维字符数组
        //playk2(char[][] ch)将上面没完成的密码表填满,最后返回编制好的密码表的二维字符数组
        //show(char[][] ch)展示最终编制好的密码表
        //spliterstr(String str)整理明文,返回字符数组
        //encryp(char[][] cht, char[] chb)加密操作,返回密文字符串
//        char[][] ch1 = t.playk2(t.playk());
//        char[] ch2 = t.splitstr("i have a balloon");
//        System.out.println(ch2);
//
//        System.out.println(t.encryp(ch1,ch2));

    }
}


总结

凯撒密码数据古典密码学的经典案例,而playfair密码则属于替代密码的一种。
它依据一个5*5的正方形组成的密码表来编写,密码表里排列有25个字母。如果一种语言字母超过25个,可以去掉使用频率最少的一个。如,法语一般去掉w或k,德语则是把i和j合起来当成一个字母看待。英语中z使用最少,可以去掉它。


加密原理:


编制密码表
第一步是编制密码表。在这个5*5的密码表中,共有5行5列字母。第一列(或第一行)是密钥,其余按照字母顺序。密钥是一个单词或词组,若有重复字母,可将后面重复的字母去掉。当然也要把使用频率最少的字母去掉。如:密钥是Live and learn,去掉后则为liveandr。如果密钥过长可占用第二列或行。
同时字母I和J会被当成一个字母。
如密钥crazy dog,可编制成
CDFMT
ROHNU
AGI PV
ZBKQW
YELSX
整理明文
第二步整理明文。将明文每两个字母组成一对。如果成对后有两个相同字母紧挨或最后一个字母是单个的,就插入一个字母X(或者Q)。
如,communist,应成为co,mx,mu,ni,st。
编写密文
最后编写密文。对明文加密规则如下:
1 :若p1 p2在同一行,对应密文c1 c2分别是紧靠p1 p2 右端的字母。其中第一列被看做是最后一列的右方。如,按照前表,ct对应dc
2 :若p1 p2在同一列,对应密文c1 c2分别是紧靠p1 p2 下方的字母。其中第一行被看做是最后一行的下方。
3 :若p1 p2不在同一行,不在同一列,则c1 c2是由p1 p2确定的矩形的其他两角的字母(至于横向替换还是纵向替换要事先约好,或自行尝试)。如,按照前表,wh对应ku或uk。
如,依照上表,明文where there is life,there is hope.
可先整理为:WH ER ET HE RE IS LI FE TH ER EI SH OP EX
然后密文为:KU YO XD OL OY PL FK DL FU YO LG LN NG LY
将密文变成大写,然后几个字母一组排列。
如5个一组就是KUYOX DOLOY PLFKD LFUYO LGLNN GLY

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Playfair密码是一种古老的替换密码,使用一个5x5的矩阵来加密和解密文本。下面是Java语言实现Playfair密码加密解密示例代码: ```java public class PlayfairCipher { private char[][] keyMatrix; public PlayfairCipher(String key) { // 构造密钥矩阵 keyMatrix = new char[5][5]; String keyStr = key + "abcdefghiklmnopqrstuvwxyz"; keyStr = keyStr.replaceAll("j", "i"); int index = 0; for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { keyMatrix[i][j] = keyStr.charAt(index); index++; } } } public String encrypt(String plaintext) { // 对明文进行处理,去掉空格和非字母字符,并将j替换为i plaintext = plaintext.toLowerCase().replaceAll("[^a-z]", ""); plaintext = plaintext.replaceAll("j", "i"); StringBuilder ciphertext = new StringBuilder(plaintext); // 对明文进行分组,如果两个字母相同,在它们之间插入一个x for (int i = 0; i < ciphertext.length(); i += 2) { if (i == ciphertext.length() - 1) { ciphertext.append('x'); } else if (ciphertext.charAt(i) == ciphertext.charAt(i + 1)) { ciphertext.insert(i + 1, 'x'); } } // 处理分组后的明文,加密每一组 for (int i = 0; i < ciphertext.length(); i += 2) { char c1 = ciphertext.charAt(i); char c2 = ciphertext.charAt(i + 1); int[] pos1 = findPosition(c1); int[] pos2 = findPosition(c2); if (pos1[0] == pos2[0]) { // 在同一行 ciphertext.setCharAt(i, keyMatrix[pos1[0]][(pos1[1] + 1) % 5]); ciphertext.setCharAt(i + 1, keyMatrix[pos2[0]][(pos2[1] + 1) % 5]); } else if (pos1[1] == pos2[1]) { // 在同一列 ciphertext.setCharAt(i, keyMatrix[(pos1[0] + 1) % 5][pos1[1]]); ciphertext.setCharAt(i + 1, keyMatrix[(pos2[0] + 1) % 5][pos2[1]]); } else { // 不在同一行也不在同一列 ciphertext.setCharAt(i, keyMatrix[pos1[0]][pos2[1]]); ciphertext.setCharAt(i + 1, keyMatrix[pos2[0]][pos1[1]]); } } return ciphertext.toString(); } public String decrypt(String ciphertext) { // 对密文进行处理,去掉空格和非字母字符,并将j替换为i ciphertext = ciphertext.toLowerCase().replaceAll("[^a-z]", ""); ciphertext = ciphertext.replaceAll("j", "i"); StringBuilder plaintext = new StringBuilder(ciphertext); // 处理密文,解密每一组 for (int i = 0; i < plaintext.length(); i += 2) { char c1 = plaintext.charAt(i); char c2 = plaintext.charAt(i + 1); int[] pos1 = findPosition(c1); int[] pos2 = findPosition(c2); if (pos1[0] == pos2[0]) { // 在同一行 plaintext.setCharAt(i, keyMatrix[pos1[0]][(pos1[1] + 4) % 5]); plaintext.setCharAt(i + 1, keyMatrix[pos2[0]][(pos2[1] + 4) % 5]); } else if (pos1[1] == pos2[1]) { // 在同一列 plaintext.setCharAt(i, keyMatrix[(pos1[0] + 4) % 5][pos1[1]]); plaintext.setCharAt(i + 1, keyMatrix[(pos2[0] + 4) % 5][pos2[1]]); } else { // 不在同一行也不在同一列 plaintext.setCharAt(i, keyMatrix[pos1[0]][pos2[1]]); plaintext.setCharAt(i + 1, keyMatrix[pos2[0]][pos1[1]]); } } return plaintext.toString(); } private int[] findPosition(char c) { // 查找字符在密钥矩阵中的位置 int[] pos = new int[2]; for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { if (keyMatrix[i][j] == c) { pos[0] = i; pos[1] = j; return pos; } } } return pos; } } ``` 使用示例: ```java PlayfairCipher cipher = new PlayfairCipher("playfair example"); String plaintext = "hello world"; String ciphertext = cipher.encrypt(plaintext); String decryptedText = cipher.decrypt(ciphertext); System.out.println("Plaintext: " + plaintext); System.out.println("Ciphertext: " + ciphertext); System.out.println("Decrypted text: " + decryptedText); ``` 输出: ``` Plaintext: hello world Ciphertext: axeevythvtah Decrypted text: helloworldx ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值