nnfewl's Blog

Vigenère cipher implementation

June 17, 2020

A note about go implementation of Vigenère cipher.

Go code from Get programming with Go:

func decipher() {
	cipherText := "CSOITEUIWUIZNSROCNKFD"
	keyword := "GOLANG"
	message := ""
	keyIndex := 0
	for i := 0; i < len(cipherText); i++ {
		// A=0, B=1, ... Z=25
		c := cipherText[i] - 'A'
		k := keyword[keyIndex] - 'A'
		// cipher letter - key letter
		c = (c-k+26)%26 + 'A'
		message += string(c)
		// increment keyIndex
		keyIndex++
		keyIndex %= len(keyword)
	}
	fmt.Println(message)
}

Since I’m such a loser who couldn’t grasp this piece of code at first glance, I need to write it down to harden my memorize. As you can see, My ad-hoc solution below is rather straightforward, it simply use the keyword to divide ciphertext to get exact number of times that capable of using whole keyword to decrypt ciphertext; after that, use partial keyword to decrypt what is left from ciphertext accordingly. But it can’t satisfy its original requirements.

Cause both ciphertext and keyword were consiste of Capitalize Character, c := cipherText[i] - 'A' and k := keyword[keyIndex] - 'A' set ciphertext and keyword to A=0, B=1, ... Z=25 format respectively. Now, procced to decipher. code c - k litreally stands for shift c back by k. While (c - k + 26) % 26 in whole is to deal with situation when a given character is subpass maximum character which is Z, then cipher need to wrap back.

  • When difference bewteen c and f is no more than 26, (c - k + 26) % 26 is equal to literal result of c-z.

  • When difference bewteen c and f is surpass 26, say it’s 28, then it needs wrap back, simplist way is to subtract 26 from it, but it will need an if condition to branch such a situation. What (c - k + 26) % 26 actually mean is (c' - k' + 26 + 26) % 26, so it’s actually doing a wrap back.

In the case of 28, what we really want to get is 28 - 26 = 2 . Place it into code is (2 + 26 + 26) % 26, hence we will get 2 from this code.

Same logic apply to keyIndex %= len(keyword):

Among execution, value of keyIndex after exection of keyIndex++ is from 0 all the way to length of keyword. What keyIndex %= len(keyword) do is keep keyIndex at a iteration of 0, 1, 2, 3, 4, 5, 0, 1 … till the end of ciphertext.

My ad-hoc code:

func decipher() {
	cipherText := "CSOITEUIWUIZNSROCNKFD"
	keyword := "GOLANG"
	message := ""

	whole := len(cipherText) / len(keyword)
	i := 0

	for ; i < whole*len(keyword); i += 6 {
		for j := 0; j < len(keyword); j++ {
			// fmt.Printf("%c %c\n", cipherText[j+i], keyword[j])
			p := int(cipherText[j+i]) - int(keyword[j]) + int('A')
			if p < 'A' {
				p += 26
			}
			fmt.Printf("%c %c %c\n", cipherText[j+i], keyword[j], p)
			message = message + fmt.Sprintf("%c", p)
		}
		fmt.Println("")
	}

	for j := 0; j < len(keyword); j++ {
		if i+j < len(cipherText) {
			// fmt.Printf("%c %c\n", cipherText[i+j], keyword[j])
			p := int(cipherText[i+j]) - int(keyword[j]) + int('A')
			if p < 'A' {
				p += 26
			}
			fmt.Printf("%c %c %c\n", cipherText[i+j], keyword[j], p)
			message = message + fmt.Sprintf("%c", p)
		}
	}
	fmt.Println(message)
}

After analysis of the decipher process, the cipher process is just the reverse computation of the decipher code.

Here is my cipher code:

package main

import (
	"fmt"
    "strings"
)

func main() {
	plainText := "your message goes here"
	keyword := "GOLANG"
	plainText = strings.Replace(plainText, " ", "", -1)
	plainText = strings.ToUpper(plainText)
	message := ""

	keyIndex := 0
	for i := 0; i < len(plainText); i++ {
		fmt.Printf("%c %v\n", plainText[i], keyIndex)

		p := plainText[i] - 'A'      // [1]
		k := keyword[keyIndex] - 'A' // [2]
		c := (p+k+26)%26 + 'A'       // [3]

		keyIndex++
		keyIndex %= len(keyword)
		message += string(c)
	}
	fmt.Printf("%v\n", message)
}

Line [1] and Line [2] shift plaintext and keyword in a format like A=0, B=1, ... Z=25. Line [3] encrypt plaintext by using keyword, and plus 'A' to shift it back to original ascii format.

Result:

$ go run cipher.go
Y 0
O 1
U 2
R 3
M 4
E 5
S 0
S 1
A 2
G 3
E 4
G 5
O 0
E 1
S 2
H 3
E 4
R 5
E 0
ECFRZKYGLGRMUSDHRXK

Written by nnfewl, a noob. Follow me on Twitter