↓ Skip to main content
Security

GoLang: SimpleCipher

·4 mins
Table of Contents

Hello back again, Golang is just a new syntax for me. Even though behind the scenes they developers have simplified many things, for a consumer like me writing a program is more about learning the new syntax and getting familiarized with the control and stack.

In my constant quest to try something different, today I try and solve the simple cipher which by definition is a text replacement algorithm that makes the text a little difficult to break while reading with naked eyes.

SimpleCipher: Code available in GitHub

Caesar cipher with a left shift of 3: each letter is replaced by the one three places earlier in the alphabet

Version 1.0
#

The first version was a basic logic writing which allowed to check for the code and decode capability.
// Encrypt struct
type Encrypt struct {
	distance int
	key      string
}

// NewCaesar Object that implements the interface Cipher
func NewCaesar() Cipher {
	return Encrypt{distance: 3, key: ""}
}

// NewShift Object that implements the interface Cipher
func NewShift(distance int) Cipher {
	// Corner case when of 0, 26, -26
	if distance < -26 || distance > 26 || distance == 0 {
		return nil
	}
	return Encrypt{distance, ""}
}

// NewVigenere Object that implements the interface Cipher
func NewVigenere(key string) Cipher {

	if key == "" || checkKeyInvalid(key) {
		return nil
	}
	return Encrypt{0, key}
}

// checkAllAs Checks for all A's in the key.
func checkKeyInvalid(s string) (f bool) {

	// If any invalid character matches
	if matched, _ := regexp.MatchString(`[^a-z]`, s); matched {
		return true
	}

	for _, m := range s {
		switch m {
		case 'a':
			f = true
		default:
			f = false
			return
		}
	}
	return
}

I also wrote a utility to remove all invalid character basically all the chars that were not either of A-Z or a-z.

// removeAllOtherCharcterBeforeEncoding replace all the other elements
func removeAllOtherCharcterBeforeEncoding(s string) (o string) {
	o = RegularExp.ReplaceAllString(s, "")
	log.Printf(" String: %s", o)
	o = strings.ToLower(o)
	return
}

var RegularExp = regexp.MustCompile(`[^A-Za-z]`)

The basic logic of transforming the input string to encoded string was written in these two functions below

func transformWithString(s string, e string, flag bool) string {
	var sb strings.Builder

	em := []rune(e)

	for i, sm := range s {
		// The key has to be repeated
		var d rune = 0

		if i < len(em) {
			d = em[i] - 'a'
		} else {
			d = em[(i%len(em))] - 'a'
		}

		if flag {
			switch {
			case sm >= 'a' && sm <= 'z':
				fmt.Fprintf(&sb, "%s", string('a'+(sm-'a'+d)%26))
			}
		} else {
			switch {
			case sm >= 'a' && sm <= 'z':
				diff := ((sm - 'a' - d) % 26)
				newChar := ""

				if diff < 0 {
					newChar = string('z' + diff + 1)
				} else {
					newChar = string('a' + diff)
				}
				fmt.Fprintf(&sb, "%s", newChar)
			}
		}
	}
	return sb.String()
}

// transformWithDistance Allows transformation based on distance.
func transformWithDistance(s string, d int) string {

	rotateFunction := func(r rune) rune {
		switch {
		case r >= 'a' && r <= 'z':
			val := (r - 'a' + rune(d))
			if val < 0 && d < 0 {
				return 'z' + ((val + 1) % 26)
			}
			return 'a' + (val % 26)

		default:
			log.Printf(" Not a charcter: %s", string(r))
		}
		return ' '
	}

	return strings.Map(rotateFunction, s)

}

The basic functions that invoke these encode and decode functions are as under

// Encode Implements the interface Cipher
func (e Encrypt) Encode(s string) (o string) {
	o = ""
	s = removeAllOtherCharcterBeforeEncoding(s)

	if s == "" || len(s) <= 0 {
		return
	}

	// Iterate throught the runes

	switch {
	case e.distance != 0:
		o = strings.ReplaceAll(transformWithDistance(s, e.distance), " ", "")
	default:
		o = transformWithString(s, e.key, true)
	}

	return
}

// Decode decides the encrypted string
func (e Encrypt) Decode(s string) (o string) {
	o = ""

	log.Printf(" Decode: %s", s)

	if s == "" || len(s) <= 0 {
		return
	}

	switch {
	case e.distance != 0:
		log.Printf(" Distance: %d", e.distance)
		o = transformWithDistance(s, -e.distance)
	default:
		o = transformWithString(s, e.key, false)
	}

	return
}

Now the general feeling after writing this was I have too much the same code that I should remove for example

  • transformWithDistance
  • transformWithString

They are essentially doing the same thing?

Version 2…. to follow soon.

Author
Samarthya
Engineer, learner, tinkerer. This is my trophy shelf of everyday work and leisure.

Related

GOLANG: Proteins & RNA

·5 mins
It was an interesting exercise, and I solved in three ways. More details available here @ exercism.io Introduction # RNA can be broken into three nucleotide sequences called codons, and then translated to a polypeptide like so:

Say a Number

·4 mins
With the Corona-Lockdown in place “literally”, it was time to squeeze out some me-time to continue the quest for GO-Proficiency. Sometimes you re-do optimization in your head so many times that it takes a whole day to see through the mistake you are making.

Package String

Just like Java or C++ there are standard libraries (packages) available with golang. The one that you might end up using the most often is strings. For this blog, I was writing another practice exercise that is meant to count number of words in an input string.