-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDoublePlayfair.java
143 lines (117 loc) · 4.71 KB
/
DoublePlayfair.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import java.io.*;
public class DoublePlayfair extends ClassicalCipher
{
// Conducts DoublePlayfair encryption and decryption.
// Not subclass of Playfair as they aren't that similar - closer to
// HorizontalTwoSquare, but has seriation, a different rule for
// letters on same row, and does the encryption twice
// (although Wikipedia has DoublePlayfair=TwoSquare)
// This method from http://www.pbs.org/wgbh/nova/decoding/doubplayfair.html
// "Jim Gillogly has noted that declassified NSA documents refer to
// another cipher of this type, in which the digraphs were enciphered
// twice by means of the two-square cipher. Since each letter enciphered
// the first time was then found in the square on the other side for
// the second encipherment, the relation between plain and cipher
// digraphs was much more complicated than in regular Playfair"
/*
Copyright (C) 2019 S Combes
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
protected String keyL;
protected String keyR;
protected int rank;
// ----------------------------------------------------------------------
DoublePlayfair(String wordL,String wordR,int rank)
{ this(new Codespace(Codespace.StockAlphabet.MERGED_IJ),wordL,wordR,rank); }
// ----------------------------------------------------------------------
DoublePlayfair(Codespace cs,String wordL,String wordR,int rank)
{
super(cs);
if (cs.PTspace.length() != 25)
throw new IllegalArgumentException("DoublePlayfair needs a 25 letter alphabet");
keyL=new Keyword().new Simple(cs,wordL).getKey();
keyR=new Keyword().new Simple(cs,wordR).getKey();
this.rank=rank;
}
// ----------------------------------------------------------------------
public String toString()
{ return ("Double Playfair Cipher : L Key "+keyL+" R Key "+keyR+
"Seriation = "+rank+nL+
super.toString());}
// ----------------------------------------------------------------------
@Override
public String encode(String PT)
{
String flat=(PT.length()%2==0)?cs.flattenToPT(PT):cs.flattenToPT(PT)+"X";
flat=seriateOn(flat,rank);
StringBuilder sb=new StringBuilder(PT.length());
for (int i=0;i<flat.length();i+=2)
sb.append(singleEncode(singleEncode(flat.substring(i,i+2))));
return sb.toString();
}
// ----------------------------------------------------------------------
protected String singleEncode(String text)
{
StringBuilder sb=new StringBuilder(2);
int l1=keyL.indexOf(text.charAt(0));
int l2=keyR.indexOf(text.charAt(1));
int x1=l1%5;
int y1=l1/5;
int x2=l2%5;
int y2=l2/5;
if (y1==y2) { // Same row - letters to left
sb.append(keyR.charAt(y1*5+(x2+4)%5));
sb.append(keyL.charAt(y1*5+(x1+4)%5));
} else {
sb.append(keyR.charAt(y1*5+x2));
sb.append(keyL.charAt(y2*5+x1));
}
return sb.toString();
}
// ----------------------------------------------------------------------
@Override
public String decode(String CT)
{
String flat=cs.flattenToCT(CT);
StringBuilder sb=new StringBuilder(CT.length());
for (int i=0;i<flat.length()-1;i+=2)
sb.append(singleDecode(singleDecode(flat.substring(i,i+2))));
return seriateOff(sb.toString(),rank);
}
// ----------------------------------------------------------------------
protected String singleDecode(String text)
{
StringBuilder sb=new StringBuilder(2);
int l1=keyR.indexOf(text.charAt(0));
int l2=keyL.indexOf(text.charAt(1));
int x1=l1%5;
int y1=l1/5;
int x2=l2%5;
int y2=l2/5;
if (y1==y2) { // Same row - letters to right
sb.append(keyL.charAt(y1*5+(x2+1)%5));
sb.append(keyR.charAt(y1*5+(x1+1)%5));
} else {
sb.append(keyL.charAt(y1*5+x2));
sb.append(keyR.charAt(y2*5+x1));
}
return sb.toString();
}
// ----------------------------------------------------------
public static void main(String [] args) {
// From http://www.pbs.org/wgbh/nova/decoding/doubplayfair.html
DoublePlayfair dp=new DoublePlayfair("HAMBURG","NLIHGEMXVFWPZUDYQSTCORKAB",7);
String target="MPSRHRMXNWAKBWMYWEBICWSP";
String PT="MYHOVERCRAFTISFULLOFEELS";
if (dp.knownTest(PT,target)) System.out.println("PASS");
else System.out.println("***** FAIL *******");
}
}