#CFB is
footnote1
footnote2
#標準Packageのみでやりたい
##ライブラリならこう
package crypto
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"errors"
"io"
)
func encodeBase64(b []byte) string {
return base64.StdEncoding.EncodeToString(b)
}
func decodeBase64(s string) []byte {
data, err := base64.StdEncoding.DecodeString(s)
if err != nil {
panic(err)
}
return data
}
func Encrypt(key, text []byte) (string, error) {
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
b := base64.StdEncoding.EncodeToString(text)
cipt := make([]byte, aes.BlockSize+len(b))
iv := cipt[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return "", err
}
cfb := cipher.NewCFBEncrypter(block, iv)
cfb.XORKeyStream(cipt[aes.BlockSize:], []byte(b))
return encodeBase64(cipt), nil
}
func Decrypt(key []byte, t string) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
text := decodeBase64(t)
if len(text) < aes.BlockSize {
return nil, errors.New("too short")
}
iv := text[:aes.BlockSize]
text = text[aes.BlockSize:]
cfb := cipher.NewCFBDecrypter(block, iv)
cfb.XORKeyStream(text, text)
data, err := base64.StdEncoding.DecodeString(string(text))
if err != nil {
return nil, err
}
return data, nil
}
#ライブラリを使うにはこう
##encrypt
// keyは復号化用キーでもある。
enc, err := crypto.Encrypt([]byte(key), []byte(str))
if err != nil {
log.Fatalf("%+v", err)
}
fmt.Println(enc)
##decrypt
dec, err := crypto.Decrypt([]byte(key), enc)
if err != nil {
log.Fatalf("%+v", err)
}
fmt.Println(string(dec))
CFBモードを任意のxの整数倍の欠落に対しても同期を維持することが可能な自己同期型のストリーム暗号として利用するためには、ブロックサイズと初期化ベクトルのサイズでシフトレジスタを初期化する必要がある。これはブロック暗号によって暗号化され、暗号化結果の上位xビットは平文のxビットとのXORを取られ、これがxビットの暗号文となる。これらxビットの出力はシフトレジスタにシフトされ、次のxビットの平文の処理に用いられる。復号も同様であり、初期化ベクトルから始まり、復号、復号結果の上位xビットと暗号文のxビットのXORによりxビットの平文となり、これが次のxビットの暗号文の処理に用いられる。このような処理はCFB-8あるいはCFB-1として知られている(シフト量の大きさによる)
ブロック暗号を暗号化処理にのみ用いることと、ブロックサイズの整数倍にメッセージのパディングを行う必要がないことがメリットですね