🚀

【Go】Goでヴィジュネル暗号を書いてみた

に公開

概要

暗号技術入門 第3版で最初の方に出てくる暗号、ヴィジュネル暗号をGo実装してみた

サンプルコード

package main

import (
    "crypto/rand"
    "fmt"
    "strings"
    "unicode"
)

type VigenereCipher struct {
    Key string
}

func NewVigenereCipher(text string) VigenereCipher {
    return VigenereCipher{Key: generateRandomAlphaKey(len(text))}
}

func generateRandomAlphaKey(length int) string {
    const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    key := make([]byte, length)
    _, err := rand.Read(key)
    if err != nil {
       panic(err)
    }
    for i := 0; i < length; i++ {
       key[i] = charset[key[i]%byte(len(charset))]
    }
    return string(key)
}

func (vc VigenereCipher) EncryptText(text string) string {
    return vc.transformText(text, vc.encryptShift)
}

func (vc VigenereCipher) DecryptText(text string) string {
    return vc.transformText(text, vc.decryptShift)
}

func (vc VigenereCipher) transformText(text string, shiftFunc func(rune, rune, rune) rune) string {
    var result strings.Builder
    keyIndex := 0
    keyLength := len(vc.Key)

    for _, char := range text {
       if unicode.IsLetter(char) { // Unicode上で文字と分類される場合のみを暗号化の対象とする
          base := rune('A')
          if unicode.IsLower(char) { // 暗号化対象の文字が小文字の場合
             base = rune('a')
          }

          // 暗号化対象の文字に対するkeyを取得
          keyChar := rune(vc.Key[keyIndex])
          if unicode.IsLower(char) { // 暗号化対象の文字が小文字の場合、keyを小文字にする
             keyChar = unicode.ToLower(keyChar)
          } else { // 暗号化対象の文字が大文字の場合、keyを大文字にする
             keyChar = unicode.ToUpper(keyChar)
          }

          // 暗号化(復号化)
          newChar := shiftFunc(char, keyChar, base)
          result.WriteRune(newChar)

          keyIndex = (keyIndex + 1) % keyLength
       } else { // 文字以外は暗号化しない
          result.WriteRune(char)
       }
    }
    return result.String()
}

func (vc VigenereCipher) encryptShift(char, keyChar, base rune) rune {
    // ((暗号化対象の文字のオフセット) + (keyの文字のオフセット) + 負の値防止) % 0~25の範囲に収める + 実際の文字コードに戻す
    return ((char-base)+(keyChar-base)+26)%26 + base
}

func (vc VigenereCipher) decryptShift(char, keyChar, base rune) rune {
    return ((char-base)-(keyChar-base)+26)%26 + base
}

func main() {
    textToEncrypt := "Hello World"
    cipher := NewVigenereCipher(textToEncrypt)

    encrypted := cipher.EncryptText(textToEncrypt)
    decrypted := cipher.DecryptText(encrypted)

    fmt.Printf("Original Text: %s\n", textToEncrypt)
    fmt.Printf("Random Key: %s\n", cipher.Key)
    fmt.Printf("Encrypted: %s\n", encrypted)
    fmt.Printf("Decrypted: %s\n", decrypted)
}


// 出力
// Original Text: Hello World
// Random Key: ijPHFQVervo
// Encrypted: Pnast Mjvcy
// Decrypted: Hello World
GitHubで編集を提案

Discussion