How to resolve the algorithm Vigenère cipher/Cryptanalysis step by step in the Go programming language
How to resolve the algorithm Vigenère cipher/Cryptanalysis step by step in the Go programming language
Table of Contents
Problem Statement
Given some text you suspect has been encrypted with a Vigenère cipher, extract the key and plaintext. There are several methods for doing this. See the Wikipedia entry for more information. Use the following encrypted text: Letter frequencies for English can be found here. Specifics for this task:
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Vigenère cipher/Cryptanalysis step by step in the Go programming language
This code is a Go program that performs a frequency analysis of an encrypted message and attempts to decrypt it.
Here's a breakdown of what the code does:
-
Input: The program starts with a pre-defined encrypted message stored in the
encoded
variable. This message is a string containing upper-case letters. -
Frequency Table: It defines a
freq
array with 26 elements, representing the expected frequencies of each letter in the English language. This array is used as a reference for the frequency analysis. -
Frequency Analysis:
- The
sum
function calculates the sum of a given array of floats. - The
bestMatch
function takes an array of floats representing letter frequencies and finds the best rotation (shift) that aligns the frequencies with the expected frequencies in thefreq
table. It does this by calculating a fitness score based on the difference between the rotated frequencies and the expected frequencies and selecting the rotation with the lowest fitness score.
- The
-
Nth Letter Analysis:
- The
freqEveryNth
function takes an array of integersmsg
representing the encrypted message and an empty byte arraykey
to populate. It iteratively analyzes everynth
character in the message (wheren
is the length of the key). - For each iteration, it performs a frequency analysis on the characters at that interval in the message.
- It uses the
bestMatch
function to find the best rotation for that interval and stores the corresponding rotated letter in thekey
array. - It also accumulates the letter frequencies over all intervals in the
accu
array. - Finally, it calculates a fitness score based on the accumulated frequencies and the expected frequencies.
- The
-
Decryption:
- The
decrypt
function takes an encrypted messagetext
and a keykey
and decrypts the message using the Vigenere cipher. It iteratively decrypts each character in the message by shifting it backward in the alphabet based on the corresponding character in the key.
- The
-
Main Function:
- The
main
function initializes a list of integerstxt
to represent the encrypted message by converting each letter inencoded
to its corresponding ASCII value minus 'A'. - It iterates through different key lengths from 1 to 26 and for each length:
- It creates a key of that length.
- It calculates the fitness score using the
freqEveryNth
function. - It prints the fitness score, key length, and key string.
- It marks the key with the lowest fitness score as the best so far.
- It prints the best key and decrypts the encoded message using this key.
- The
Overall, this code demonstrates a technique for deciphering encrypted messages using frequency analysis. It iterates through potential key lengths, analyzes the frequency of letters at regular intervals, and selects the key that produces the best fit with the expected letter frequencies in the English language.
Source code in the go programming language
package main
import (
"fmt"
"strings"
)
var encoded =
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" +
"VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" +
"ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" +
"FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" +
"ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" +
"ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" +
"JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" +
"LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" +
"MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" +
"QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" +
"RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" +
"TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" +
"SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" +
"ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX" +
"BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB" +
"BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA" +
"FWAML ZZRXJ EKAHV FASMU LVVUT TGK"
var freq = [26]float64{
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
0.00978, 0.02360, 0.00150, 0.01974, 0.00074,
}
func sum(a []float64) (sum float64) {
for _, f := range a {
sum += f
}
return
}
func bestMatch(a []float64) int {
sum := sum(a)
bestFit, bestRotate := 1e100, 0
for rotate := 0; rotate < 26; rotate++ {
fit := 0.0
for i := 0; i < 26; i++ {
d := a[(i+rotate)%26]/sum - freq[i]
fit += d * d / freq[i]
}
if fit < bestFit {
bestFit, bestRotate = fit, rotate
}
}
return bestRotate
}
func freqEveryNth(msg []int, key []byte) float64 {
l := len(msg)
interval := len(key)
out := make([]float64, 26)
accu := make([]float64, 26)
for j := 0; j < interval; j++ {
for k := 0; k < 26; k++ {
out[k] = 0.0
}
for i := j; i < l; i += interval {
out[msg[i]]++
}
rot := bestMatch(out)
key[j] = byte(rot + 65)
for i := 0; i < 26; i++ {
accu[i] += out[(i+rot)%26]
}
}
sum := sum(accu)
ret := 0.0
for i := 0; i < 26; i++ {
d := accu[i]/sum - freq[i]
ret += d * d / freq[i]
}
return ret
}
func decrypt(text, key string) string {
var sb strings.Builder
ki := 0
for _, c := range text {
if c < 'A' || c > 'Z' {
continue
}
ci := (c - rune(key[ki]) + 26) % 26
sb.WriteRune(ci + 65)
ki = (ki + 1) % len(key)
}
return sb.String()
}
func main() {
enc := strings.Replace(encoded, " ", "", -1)
txt := make([]int, len(enc))
for i := 0; i < len(txt); i++ {
txt[i] = int(enc[i] - 'A')
}
bestFit, bestKey := 1e100, ""
fmt.Println(" Fit Length Key")
for j := 1; j <= 26; j++ {
key := make([]byte, j)
fit := freqEveryNth(txt, key)
sKey := string(key)
fmt.Printf("%f %2d %s", fit, j, sKey)
if fit < bestFit {
bestFit, bestKey = fit, sKey
fmt.Print(" <--- best so far")
}
fmt.Println()
}
fmt.Println("\nBest key :", bestKey)
fmt.Printf("\nDecrypted text:\n%s\n", decrypt(enc, bestKey))
}
You may also check:How to resolve the algorithm Gaussian elimination step by step in the JavaScript programming language
You may also check:How to resolve the algorithm Julia set step by step in the Nim programming language
You may also check:How to resolve the algorithm File input/output step by step in the PARI/GP programming language
You may also check:How to resolve the algorithm Rot-13 step by step in the zkl programming language
You may also check:How to resolve the algorithm Motzkin numbers step by step in the Dart programming language