Chaocipher
Description
The Chaocipher was invented by J.F.Byrne in 1918 and, although simple by modern cryptographic standards, does not appear to have been broken until the algorithm was finally disclosed by his family in 2010.
The algorithm is described in this paper by M.Rubin in 2010 and there is a C# implementation here.
Task
The task is to code the algorithm in your language and to test that it works with the plaintext 'WELLDONEISBETTERTHANWELLSAID' used in the paper itself.
C
<lang c>#include <stdio.h>
- include <string.h>
- include <stdlib.h>
- define TRUE 1
- define FALSE 0
typedef int bool; typedef enum { ENCRYPT, DECRYPT } cmode;
const char *l_alphabet = "HXUCZVAMDSLKPEFJRIGTWOBNYQ"; const char *r_alphabet = "PTLNBQDEOYSFAVZKGJRIHWXUMC";
void chao(const char *in, char *out, cmode mode, bool show_steps) {
int i, j, index; char store; size_t len = strlen(in); char left[27], right[27], temp[27]; strcpy(left, l_alphabet); strcpy(right, r_alphabet); temp[26] = '\0';
for (i = 0; i < len; ++i ) { if (show_steps) printf("%s %s\n", left, right); if (mode == ENCRYPT) { index = strchr(right, in[i]) - right; out[i] = left[index]; } else { index = strchr(left, in[i]) - left; out[i] = right[index]; } if (i == len - 1) break;
/* permute left */
for (j = index; j < 26; ++j) temp[j - index] = left[j]; for (j = 0; j < index; ++j) temp[26 - index + j] = left[j]; store = temp[1]; for (j = 2; j < 14; ++j) temp[j - 1] = temp[j]; temp[13] = store; strcpy(left, temp);
/* permute right */
for (j = index; j < 26; ++j) temp[j - index] = right[j]; for (j = 0; j < index; ++j) temp[26 - index + j] = right[j]; store = temp[0]; for (j = 1; j < 26; ++j) temp[j - 1] = temp[j]; temp[25] = store; store = temp[2]; for (j = 3; j < 14; ++j) temp[j - 1] = temp[j]; temp[13] = store; strcpy(right, temp); }
}
int main() {
const char *plain_text = "WELLDONEISBETTERTHANWELLSAID"; char *cipher_text = malloc(strlen(plain_text) + 1); char *plain_text2 = malloc(strlen(plain_text) + 1); printf("The original plaintext is : %s\n", plain_text); printf("\nThe left and right alphabets after each permutation" " during encryption are :\n\n"); chao(plain_text, cipher_text, ENCRYPT, TRUE); printf("\nThe ciphertext is : %s\n", cipher_text); chao(cipher_text, plain_text2, DECRYPT, FALSE); printf("\nThe recovered plaintext is : %s\n", plain_text2); free(cipher_text); free(plain_text2); return 0;
}</lang>
- Output:
The original plaintext is : WELLDONEISBETTERTHANWELLSAID The left and right alphabets after each permutation during encryption are : HXUCZVAMDSLKPEFJRIGTWOBNYQ PTLNBQDEOYSFAVZKGJRIHWXUMC ONYQHXUCZVAMDBSLKPEFJRIGTW XUCPTLNBQDEOYMSFAVZKGJRIHW ADBSLKPEFJRIGMTWONYQHXUCZV OYSFAVZKGJRIHMWXUCPTLNBQDE HUCZVADBSLKPEXFJRIGMTWONYQ NBDEOYSFAVZKGQJRIHMWXUCPTL QUCZVADBSLKPEHXFJRIGMTWONY NBEOYSFAVZKGQDJRIHMWXUCPTL HFJRIGMTWONYQXUCZVADBSLKPE JRHMWXUCPTLNBIEOYSFAVZKGQD CVADBSLKPEHFJZRIGMTWONYQXU YSAVZKGQDJRHMFWXUCPTLNBIEO NQXUCVADBSLKPYEHFJZRIGMTWO BIOYSAVZKGQDJERHMFWXUCPTLN YHFJZRIGMTWONEQXUCVADBSLKP RHFWXUCPTLNBIMOYSAVZKGQDJE NQXUCVADBSLKPEYHFJZRIGMTWO MOSAVZKGQDJERYHFWXUCPTLNBI XCVADBSLKPEYHUFJZRIGMTWONQ AVKGQDJERYHFWZXUCPTLNBIMOS TONQXCVADBSLKWPEYHUFJZRIGM IMSAVKGQDJERYOHFWZXUCPTLNB SKWPEYHUFJZRILGMTONQXCVADB RYHFWZXUCPTLNOBIMSAVKGQDJE ZILGMTONQXCVARDBSKWPEYHUFJ LNBIMSAVKGQDJOERYHFWZXUCPT JILGMTONQXCVAZRDBSKWPEYHUF LNIMSAVKGQDJOBERYHFWZXUCPT RBSKWPEYHUFJIDLGMTONQXCVAZ RYFWZXUCPTLNIHMSAVKGQDJOBE RSKWPEYHUFJIDBLGMTONQXCVAZ YFZXUCPTLNIHMWSAVKGQDJOBER HFJIDBLGMTONQUXCVAZRSKWPEY LNHMWSAVKGQDJIOBERYFZXUCPT JDBLGMTONQUXCIVAZRSKWPEYHF MWAVKGQDJIOBESRYFZXUCPTLNH BGMTONQUXCIVALZRSKWPEYHFJD VKQDJIOBESRYFGZXUCPTLNHMWA YFJDBGMTONQUXHCIVALZRSKWPE HMAVKQDJIOBESWRYFGZXUCPTLN HIVALZRSKWPEYCFJDBGMTONQUX RYGZXUCPTLNHMFAVKQDJIOBESW QXHIVALZRSKWPUEYCFJDBGMTON SWYGZXUCPTLNHRMFAVKQDJIOBE KPUEYCFJDBGMTWONQXHIVALZRS NHMFAVKQDJIOBRESWYGZXUCPTL SPUEYCFJDBGMTKWONQXHIVALZR NHFAVKQDJIOBRMESWYGZXUCPTL OQXHIVALZRSPUNEYCFJDBGMTKW WYZXUCPTLNHFAGVKQDJIOBRMES UEYCFJDBGMTKWNOQXHIVALZRSP GVQDJIOBRMESWKYZXUCPTLNHFA JBGMTKWNOQXHIDVALZRSPUEYCF OBMESWKYZXUCPRTLNHFAGVQDJI The ciphertext is : OAHQHCNYNXTSZJRRHJBYHQKSOUJY The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID
Factor
<lang factor>USING: arrays combinators fry io kernel locals math namespaces prettyprint sequences sequences.extras strings ; IN: rosetta-code.chaocipher
CONSTANT: zenith 0 CONSTANT: nadir 13
SYMBOLS: l-alphabet r-alphabet last-index ;
- init-alphabets ( -- )
"HXUCZVAMDSLKPEFJRIGTWOBNYQ" l-alphabet "PTLNBQDEOYSFAVZKGJRIHWXUMC" r-alphabet [ set ] 2bi@ ;
- zero-alphabet ( seq -- seq' )
last-index get rotate ;
- 3append ( a b c d -- abcd )
append append append ;
- permute-l-alphabet ( -- )
l-alphabet get zero-alphabet dup zenith 1 + swap nth :> extracted-char { [ 1 head ] [ nadir 1 + head 2 tail ] [ drop extracted-char 1string ] [ nadir 1 + tail ] } cleave 3append l-alphabet set ;
- permute-r-alphabet ( -- )
r-alphabet get zero-alphabet 1 rotate dup zenith 2 + swap nth :> extracted-char { [ 2 head ] [ nadir 1 + head 3 tail ] [ drop extracted-char 1string ] [ nadir 1 + tail ] } cleave 3append r-alphabet set ;
- encipher-char ( char alpha1 alpha2 -- char' )
'[ _ get index dup last-index set _ get nth ] call ;
- encipher ( str quot -- str' )
[ permute-l-alphabet permute-r-alphabet ] compose map init-alphabets ; inline
- encrypt ( str -- str' )
[ r-alphabet l-alphabet encipher-char ] encipher ;
- decrypt ( str -- str' )
[ l-alphabet r-alphabet encipher-char ] encipher ;
- main ( -- )
init-alphabets "WELLDONEISBETTERTHANWELLSAID" encrypt dup decrypt [ print ] bi@ ;
MAIN: main</lang>
- Output:
OAHQHCNYNXTSZJRRHJBYHQKSOUJY WELLDONEISBETTERTHANWELLSAID
Go
<lang go>package main
import(
"fmt" "strings" "unicode/utf8"
)
type Mode int
const(
Encrypt Mode = iota Decrypt
)
const(
lAlphabet = "HXUCZVAMDSLKPEFJRIGTWOBNYQ" rAlphabet = "PTLNBQDEOYSFAVZKGJRIHWXUMC"
)
func Chao(text string, mode Mode, showSteps bool) string {
len := len(text) if utf8.RuneCountInString(text) != len { fmt.Println("Text contains non-ASCII characters") return "" } left := lAlphabet right := rAlphabet eText := make([]byte, len) temp := make([]byte, 26)
for i := 0; i < len; i++ { if showSteps { fmt.Println(left, " ", right) } var index int if mode == Encrypt { index = strings.IndexByte(right, text[i]) eText[i] = left[index] } else { index = strings.IndexByte(left, text[i]) eText[i] = right[index] } if i == len - 1 { break }
// permute left for j := index; j < 26; j++ { temp[j - index] = left[j] } for j := 0; j < index; j++ { temp[26 - index + j] = left[j] } store := temp[1] for j := 2; j < 14; j++ { temp[j - 1] = temp[j] } temp[13] = store left = string(temp[:])
// permute right
for j := index; j < 26; j++ { temp[j - index] = right[j] } for j := 0; j < index; j++ { temp[26 - index + j] = right[j] } store = temp[0] for j := 1; j < 26; j++ { temp[j - 1] = temp[j] } temp[25] = store store = temp[2] for j := 3; j < 14; j++ { temp[j - 1] = temp[j] } temp[13] = store right = string(temp[:]) }
return string(eText[:])
}
func main() {
plainText := "WELLDONEISBETTERTHANWELLSAID" fmt.Println("The original plaintext is :", plainText) fmt.Print("\nThe left and right alphabets after each permutation ") fmt.Println("during encryption are :\n") cipherText := Chao(plainText, Encrypt, true) fmt.Println("\nThe ciphertext is :", cipherText) plainText2 := Chao(cipherText, Decrypt, false) fmt.Println("\nThe recovered plaintext is :", plainText2)
}</lang>
- Output:
Same as Kotlin entry.
Kotlin
This is based on the C# implementation referred to in the task description, except that the encrypt and decrypt operations are combined into a single method. <lang scala>// Version 1.2.40
enum class Mode { ENCRYPT, DECRYPT }
object Chao {
private val lAlphabet = "HXUCZVAMDSLKPEFJRIGTWOBNYQ" private val rAlphabet = "PTLNBQDEOYSFAVZKGJRIHWXUMC"
fun exec(text: String, mode: Mode, showSteps: Boolean = false): String { var left = lAlphabet var right = rAlphabet val eText = CharArray(text.length) val temp = CharArray(26)
for (i in 0 until text.length) { if (showSteps) println("$left $right") var index: Int if (mode == Mode.ENCRYPT) { index = right.indexOf(text[i]) eText[i] = left[index] } else { index = left.indexOf(text[i]) eText[i] = right[index] } if (i == text.length - 1) break
// permute left
for (j in index..25) temp[j - index] = left[j] for (j in 0 until index) temp[26 - index + j] = left[j] var store = temp[1] for (j in 2..13) temp[j - 1] = temp[j] temp[13] = store left = String(temp)
// permute right
for (j in index..25) temp[j - index] = right[j] for (j in 0 until index) temp[26 - index + j] = right[j] store = temp[0] for (j in 1..25) temp[j - 1] = temp[j] temp[25] = store store = temp[2] for (j in 3..13) temp[j - 1] = temp[j] temp[13] = store right = String(temp) }
return String(eText) }
}
fun main(args: Array<String>) {
val plainText = "WELLDONEISBETTERTHANWELLSAID" println("The original plaintext is : $plainText") println("\nThe left and right alphabets after each permutation" + " during encryption are :\n") val cipherText = Chao.exec(plainText, Mode.ENCRYPT, true) println("\nThe ciphertext is : $cipherText") val plainText2 = Chao.exec(cipherText, Mode.DECRYPT) println("\nThe recovered plaintext is : $plainText2")
}</lang>
- Output:
The original plaintext is : WELLDONEISBETTERTHANWELLSAID The left and right alphabets after each permutation during encryption are : HXUCZVAMDSLKPEFJRIGTWOBNYQ PTLNBQDEOYSFAVZKGJRIHWXUMC ONYQHXUCZVAMDBSLKPEFJRIGTW XUCPTLNBQDEOYMSFAVZKGJRIHW ADBSLKPEFJRIGMTWONYQHXUCZV OYSFAVZKGJRIHMWXUCPTLNBQDE HUCZVADBSLKPEXFJRIGMTWONYQ NBDEOYSFAVZKGQJRIHMWXUCPTL QUCZVADBSLKPEHXFJRIGMTWONY NBEOYSFAVZKGQDJRIHMWXUCPTL HFJRIGMTWONYQXUCZVADBSLKPE JRHMWXUCPTLNBIEOYSFAVZKGQD CVADBSLKPEHFJZRIGMTWONYQXU YSAVZKGQDJRHMFWXUCPTLNBIEO NQXUCVADBSLKPYEHFJZRIGMTWO BIOYSAVZKGQDJERHMFWXUCPTLN YHFJZRIGMTWONEQXUCVADBSLKP RHFWXUCPTLNBIMOYSAVZKGQDJE NQXUCVADBSLKPEYHFJZRIGMTWO MOSAVZKGQDJERYHFWXUCPTLNBI XCVADBSLKPEYHUFJZRIGMTWONQ AVKGQDJERYHFWZXUCPTLNBIMOS TONQXCVADBSLKWPEYHUFJZRIGM IMSAVKGQDJERYOHFWZXUCPTLNB SKWPEYHUFJZRILGMTONQXCVADB RYHFWZXUCPTLNOBIMSAVKGQDJE ZILGMTONQXCVARDBSKWPEYHUFJ LNBIMSAVKGQDJOERYHFWZXUCPT JILGMTONQXCVAZRDBSKWPEYHUF LNIMSAVKGQDJOBERYHFWZXUCPT RBSKWPEYHUFJIDLGMTONQXCVAZ RYFWZXUCPTLNIHMSAVKGQDJOBE RSKWPEYHUFJIDBLGMTONQXCVAZ YFZXUCPTLNIHMWSAVKGQDJOBER HFJIDBLGMTONQUXCVAZRSKWPEY LNHMWSAVKGQDJIOBERYFZXUCPT JDBLGMTONQUXCIVAZRSKWPEYHF MWAVKGQDJIOBESRYFZXUCPTLNH BGMTONQUXCIVALZRSKWPEYHFJD VKQDJIOBESRYFGZXUCPTLNHMWA YFJDBGMTONQUXHCIVALZRSKWPE HMAVKQDJIOBESWRYFGZXUCPTLN HIVALZRSKWPEYCFJDBGMTONQUX RYGZXUCPTLNHMFAVKQDJIOBESW QXHIVALZRSKWPUEYCFJDBGMTON SWYGZXUCPTLNHRMFAVKQDJIOBE KPUEYCFJDBGMTWONQXHIVALZRS NHMFAVKQDJIOBRESWYGZXUCPTL SPUEYCFJDBGMTKWONQXHIVALZR NHFAVKQDJIOBRMESWYGZXUCPTL OQXHIVALZRSPUNEYCFJDBGMTKW WYZXUCPTLNHFAGVKQDJIOBRMES UEYCFJDBGMTKWNOQXHIVALZRSP GVQDJIOBRMESWKYZXUCPTLNHFA JBGMTKWNOQXHIDVALZRSPUEYCF OBMESWKYZXUCPRTLNHFAGVQDJI The ciphertext is : OAHQHCNYNXTSZJRRHJBYHQKSOUJY The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID
Perl
Since rotate is not a built-in in Perl, using a custom one, not general-purpose but sufficient for this task. <lang perl>sub init {
@left = split , 'HXUCZVAMDSLKPEFJRIGTWOBNYQ'; @right = split , 'PTLNBQDEOYSFAVZKGJRIHWXUMC';
}
sub encode {
my($letter) = @_; my $index = index join(, @right), $letter; my $enc = $left[$index]; left_permute($index); right_permute($index); $enc
}
sub decode {
my($letter) = @_; my $index = index join(, @left), $letter; my $dec = $right[$index]; left_permute($index); right_permute($index); $dec
}
sub right_permute {
my($index) = @_; rotate(\@right, $index + 1); rotate(\@right, 1, 2, 13);
}
sub left_permute {
my($index) = @_; rotate(\@left, $index); rotate(\@left, 1, 1, 13);
}
sub rotate {
our @list; local *list = shift; my($n,$s,$e) = @_; @list = $s ? @list[0..$s-1, $s+$n..$e+$n-1, $s..$s+$n-1, $e+1..$#list] : @list[$n..$#list, 0..$n-1]
}
init; $e_msg .= encode($_) for split , 'WELLDONEISBETTERTHANWELLSAID'; init; $d_msg .= decode($_) for split , $e_msg;
print "$e_msg\n"; print "$d_msg\n";</lang>
- Output:
OAHQHCNYNXTSZJRRHJBYHQKSOUJY WELLDONEISBETTERTHANWELLSAID
Perl 6
<lang perl6>my @left; my @right;
sub reset {
@left = <HXUCZVAMDSLKPEFJRIGTWOBNYQ>.comb; @right = <PTLNBQDEOYSFAVZKGJRIHWXUMC>.comb;
}
sub encode ($letter) {
my $index = @right.first: $letter.uc, :k; my $enc = @left[$index]; $index.&permute; $enc
}
sub decode ($letter) {
my $index = @left.first: $letter.uc, :k; my $dec = @right[$index]; $index.&permute; $dec
}
sub permute ($index) {
@left.=rotate: $index; @left[1..13].=rotate; @right.=rotate: $index + 1; @right[2..13].=rotate;
}
reset; say 'WELLDONEISBETTERTHANWELLSAID'.comb».&encode.join; reset; say 'OAHQHCNYNXTSZJRRHJBYHQKSOUJY'.comb».&decode.join;</lang>
- Output:
OAHQHCNYNXTSZJRRHJBYHQKSOUJY WELLDONEISBETTERTHANWELLSAID
Phix
Originally translated from C, but ended up more of a direct implementation of the algorithm in the pdf. <lang Phix>-- demo\rosetta\Chao_cipher.exw constant l_alphabet = "HXUCZVAMDSLKPEFJRIGTWOBNYQ",
r_alphabet = "PTLNBQDEOYSFAVZKGJRIHWXUMC"
enum ENCRYPT, DECRYPT
function chao_cipher(string in, integer mode, bool show_steps)
integer len = length(in) string out = repeat(' ',len) string left = l_alphabet, right = r_alphabet for i=1 to len do if show_steps then printf(1,"%s %s\n", {left, right}) end if integer index = find(in[i],iff(mode==ENCRYPT?right:left)) out[i] = iff(mode==ENCRYPT?left:right)[index]
if i==len then exit end if /* permute left */ left = left[index..26]&left[1..index-1] left[2..14] = left[3..14]&left[2]
/* permute right */ right = right[index+1..26]&right[1..index] right[3..14] = right[4..14]&right[3] end for return out
end function
string plain_text = "WELLDONEISBETTERTHANWELLSAID" printf(1,"The original plaintext is : %s\n", {plain_text})
--printf(1,"\nThe left and right alphabets after each permutation"& -- " during encryption are :\n\n") --string cipher_text = chao_cipher(plain_text, ENCRYPT, true) string cipher_text = chao_cipher(plain_text, ENCRYPT, false) printf(1,"\nThe ciphertext is : %s\n", {cipher_text})
string plain_text2 = chao_cipher(cipher_text, DECRYPT, false) printf(1,"\nThe recovered plaintext is : %s\n", {plain_text2})</lang>
- Output:
The original plaintext is : WELLDONEISBETTERTHANWELLSAID The ciphertext is : OAHQHCNYNXTSZJRRHJBYHQKSOUJY The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID
zkl
<lang zkl>class Chao{
var [const private] lAlphabet = "HXUCZVAMDSLKPEFJRIGTWOBNYQ",
rAlphabet = "PTLNBQDEOYSFAVZKGJRIHWXUMC";
fcn encode(text){ code(text,encodeL); } fcn decode(text){ code(text,decodeL); } // reset alphabets each [en|de]code and maintain re-entrancy fcn code(text,f){ text.apply(f,Data(Void,lAlphabet),Data(Void,rAlphabet)) } fcn [private] encodeL(letter,left,right){ // encode a letter index:=right.index(letter); enc :=left[index].toChar(); permute(left,right,index); println(left.text," ",right.text," ",index); enc } fcn [private] decodeL(letter,left,right){ // decode a letter index:=left.index(letter); dec :=right[index].toChar(); permute(left,right,index); dec } fcn [private] permute(left,right,index){ left.append(left.pop(0,index)); // rotate index times left.insert(13,left.pop(1)); // rotate [1..13] once
right.append(right.pop(0,index+1)); # rotate index+1 times, idx==25==noop right.insert(13,right.pop(2)); // rotate [2..13] once }
}</lang> <lang zkl>plainText:="WELLDONEISBETTERTHANWELLSAID"; println("The original plaintext is : ",plainText); println("\nThe left and right alphabets after each permutation"
" during encryption are:");
cipherText:=Chao.encode(plainText); println("\nThe ciphertext is : ",cipherText);
plainText2:=Chao.decode(cipherText); println("\nThe recovered plaintext is : ",plainText2);</lang>
- Output:
The original plaintext is : WELLDONEISBETTERTHANWELLSAID The left and right alphabets after each permutation during encryption are: ONYQHXUCZVAMDBSLKPEFJRIGTW XUCPTLNBQDEOYMSFAVZKGJRIHW 21 ADBSLKPEFJRIGMTWONYQHXUCZV OYSFAVZKGJRIHMWXUCPTLNBQDE 10 HUCZVADBSLKPEXFJRIGMTWONYQ NBDEOYSFAVZKGQJRIHMWXUCPTL 20 QUCZVADBSLKPEHXFJRIGMTWONY NBEOYSFAVZKGQDJRIHMWXUCPTL 25 HFJRIGMTWONYQXUCZVADBSLKPE JRHMWXUCPTLNBIEOYSFAVZKGQD 13 CVADBSLKPEHFJZRIGMTWONYQXU YSAVZKGQDJRHMFWXUCPTLNBIEO 15 NQXUCVADBSLKPYEHFJZRIGMTWO BIOYSAVZKGQDJERHMFWXUCPTLN 21 YHFJZRIGMTWONEQXUCVADBSLKP RHFWXUCPTLNBIMOYSAVZKGQDJE 13 NQXUCVADBSLKPEYHFJZRIGMTWO MOSAVZKGQDJERYHFWXUCPTLNBI 12 XCVADBSLKPEYHUFJZRIGMTWONQ AVKGQDJERYHFWZXUCPTLNBIMOS 2 TONQXCVADBSLKWPEYHUFJZRIGM IMSAVKGQDJERYOHFWZXUCPTLNB 21 SKWPEYHUFJZRILGMTONQXCVADB RYHFWZXUCPTLNOBIMSAVKGQDJE 10 ZILGMTONQXCVARDBSKWPEYHUFJ LNBIMSAVKGQDJOERYHFWZXUCPT 10 JILGMTONQXCVAZRDBSKWPEYHUF LNIMSAVKGQDJOBERYHFWZXUCPT 25 RBSKWPEYHUFJIDLGMTONQXCVAZ RYFWZXUCPTLNIHMSAVKGQDJOBE 14 RSKWPEYHUFJIDBLGMTONQXCVAZ YFZXUCPTLNIHMWSAVKGQDJOBER 0 HFJIDBLGMTONQUXCVAZRSKWPEY LNHMWSAVKGQDJIOBERYFZXUCPT 7 JDBLGMTONQUXCIVAZRSKWPEYHF MWAVKGQDJIOBESRYFZXUCPTLNH 2 BGMTONQUXCIVALZRSKWPEYHFJD VKQDJIOBESRYFGZXUCPTLNHMWA 2 YFJDBGMTONQUXHCIVALZRSKWPE HMAVKQDJIOBESWRYFGZXUCPTLN 21 HIVALZRSKWPEYCFJDBGMTONQUX RYGZXUCPTLNHMFAVKQDJIOBESW 13 QXHIVALZRSKWPUEYCFJDBGMTON SWYGZXUCPTLNHRMFAVKQDJIOBE 23 KPUEYCFJDBGMTWONQXHIVALZRS NHMFAVKQDJIOBRESWYGZXUCPTL 10 SPUEYCFJDBGMTKWONQXHIVALZR NHFAVKQDJIOBRMESWYGZXUCPTL 25 OQXHIVALZRSPUNEYCFJDBGMTKW WYZXUCPTLNHFAGVKQDJIOBRMES 15 UEYCFJDBGMTKWNOQXHIVALZRSP GVQDJIOBRMESWKYZXUCPTLNHFA 12 JBGMTKWNOQXHIDVALZRSPUEYCF OBMESWKYZXUCPRTLNHFAGVQDJI 5 YFJBGMTKWNOQXCHIDVALZRSPUE JIBMESWKYZXUCOPRTLNHFAGVQD 23 The ciphertext is : OAHQHCNYNXTSZJRRHJBYHQKSOUJY The recovered plaintext is : WELLDONEISBETTERTHANWELLSAID