144 lines
3.0 KiB
Go
144 lines
3.0 KiB
Go
|
package cipher
|
||
|
|
||
|
import (
|
||
|
"regexp"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
// Cipher is an interface for all ciphers
|
||
|
type Cipher interface {
|
||
|
Encode(string) string
|
||
|
Decode(string) string
|
||
|
}
|
||
|
|
||
|
// ShiftCipher is a cipher that shifts all letters a fixed distance
|
||
|
type ShiftCipher struct {
|
||
|
width int
|
||
|
}
|
||
|
|
||
|
// NewShift returns a new ShiftCipher
|
||
|
func NewShift(w int) *ShiftCipher {
|
||
|
if w == 0 || w < -25 || w > 25 {
|
||
|
return nil
|
||
|
}
|
||
|
c := new(ShiftCipher)
|
||
|
c.width = w
|
||
|
return c
|
||
|
}
|
||
|
|
||
|
// Encode encodes a string using the current ShiftCipher
|
||
|
func (c *ShiftCipher) Encode(s string) string {
|
||
|
var ret string
|
||
|
s = strings.ToLower(s)
|
||
|
re := regexp.MustCompile("[^a-z]")
|
||
|
s = re.ReplaceAllString(s, "")
|
||
|
for i := range s {
|
||
|
newChar := s[i] + byte(c.width)
|
||
|
if newChar < 'a' {
|
||
|
newChar = 'z' - ('a' - newChar) + 1
|
||
|
}
|
||
|
if newChar > 'z' {
|
||
|
newChar = 'a' + (newChar - 'z') - 1
|
||
|
}
|
||
|
ret = ret + string(newChar)
|
||
|
}
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
// Decode decodes a string using the current ShiftCipher
|
||
|
func (c *ShiftCipher) Decode(s string) string {
|
||
|
var ret string
|
||
|
s = strings.ToLower(s)
|
||
|
re := regexp.MustCompile("[^a-z]")
|
||
|
s = re.ReplaceAllString(s, "")
|
||
|
for i := range s {
|
||
|
newChar := s[i] - byte(c.width)
|
||
|
if newChar < 'a' {
|
||
|
newChar = 'z' - ('a' - newChar) + 1
|
||
|
}
|
||
|
if newChar > 'z' {
|
||
|
newChar = 'a' + (newChar - 'z') - 1
|
||
|
}
|
||
|
ret = ret + string(newChar)
|
||
|
}
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
// A CeasarCipher is a ShiftCipher, just hardcoded at 3
|
||
|
type CeasarCipher struct {
|
||
|
c *ShiftCipher
|
||
|
}
|
||
|
|
||
|
// NewCaesar creates a new CaesarCipher
|
||
|
func NewCaesar() *CeasarCipher {
|
||
|
c := new(CeasarCipher)
|
||
|
c.c = NewShift(3)
|
||
|
return c
|
||
|
}
|
||
|
|
||
|
// Encode just calls the shift cipher in the caesar cipher
|
||
|
func (c *CeasarCipher) Encode(s string) string {
|
||
|
return c.c.Encode(s)
|
||
|
}
|
||
|
|
||
|
// Decode just calls the shift cipher in the caesar cipher
|
||
|
func (c *CeasarCipher) Decode(s string) string {
|
||
|
return c.c.Decode(s)
|
||
|
}
|
||
|
|
||
|
// VigenereCipher a cipher where each character can have a different shift width
|
||
|
type VigenereCipher struct {
|
||
|
key string
|
||
|
}
|
||
|
|
||
|
// Encode encodes the given string
|
||
|
func (c *VigenereCipher) Encode(s string) string {
|
||
|
var ret string
|
||
|
s = strings.ToLower(s)
|
||
|
re := regexp.MustCompile("[^a-z]")
|
||
|
s = re.ReplaceAllString(s, "")
|
||
|
for i := range s {
|
||
|
keyChar := c.key[i%len(c.key)] - 'a'
|
||
|
newChar := s[i] + keyChar
|
||
|
if newChar < 'a' {
|
||
|
newChar = 'z' - ('a' - newChar) + 1
|
||
|
}
|
||
|
if newChar > 'z' {
|
||
|
newChar = 'a' + (newChar - 'z') - 1
|
||
|
}
|
||
|
ret = ret + string(newChar)
|
||
|
}
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
// Decode decodes the given string
|
||
|
func (c *VigenereCipher) Decode(s string) string {
|
||
|
var ret string
|
||
|
s = strings.ToLower(s)
|
||
|
re := regexp.MustCompile("[^a-z]")
|
||
|
s = re.ReplaceAllString(s, "")
|
||
|
for i := range s {
|
||
|
keyChar := c.key[i%len(c.key)] - 'a'
|
||
|
newChar := s[i] - keyChar
|
||
|
if newChar < 'a' {
|
||
|
newChar = 'z' - ('a' - newChar) + 1
|
||
|
}
|
||
|
if newChar > 'z' {
|
||
|
newChar = 'a' + (newChar - 'z') - 1
|
||
|
}
|
||
|
ret = ret + string(newChar)
|
||
|
}
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
// NewVigenere returns a new Vigenere Cipher
|
||
|
func NewVigenere(key string) *VigenereCipher {
|
||
|
re := regexp.MustCompile("[^a-z]")
|
||
|
if len(key) < 3 || re.MatchString(key) {
|
||
|
return nil
|
||
|
}
|
||
|
c := new(VigenereCipher)
|
||
|
c.key = key
|
||
|
return c
|
||
|
}
|