dorakueyon

今の時代にブロック暗号(ECB)をGoでやってみる

暗号化、特に可逆な暗号化について. ひょんなことから可逆な暗号化であるブロック暗号、特にECBに興味がでたので、実際にGoで触ってみたときのメモです.

元データによって(よらなくても)は、他の暗号化より圧倒的に復号化しやすいという意味で安全性に難ありなので、まちがってもビジネス上で利用していないことを祈ります.

実際にやってみる

ECBのライブラリーがGoのcrypto/cipherに存在しないか色々と調べてみると、公式では対応しない選択をしたことがわかった.

We left ECB out intentionally: it’s insecure, and if needed it’s trivial to implement.”

だそうです.

なので自作の道でやりたいと思います.

Repositoryは下記の通りです.

前処理 (PKCS#5 Padding)

ブロック暗号を行う場合、暗号元のデータ長が、ブロック長の倍数である必要があります.

ブロック長毎に暗号化を行なっていくので、なにかしらの手段で暗号元のデータをブロック長と同じ長さにする処理を、暗号化前に実行します.具体的にはパディング処理です.

今回はPKCS#5 Paddingを利用しました.

PKCS#5 Paddingは、足りない長さを、その長さの数値でパディングします.

暗号化の長さがあと2バイトたりない場合は、0x02を2回ファイルの末尾に追加(padding)することで、ファイルの長さを合わせます.

逆に、暗号化の長さとぴったり一緒の場合は、ブロック長のバイト数を、ブロック長回数分ファイル末尾に追加(padding)します. 例えばブロック長の長さが8byteで、ファイルの長さが8の倍数の場合(8, 16, 24…)、0x08を8回となります

実装すると下記のような感じ.

func PKCS5Padding(text []byte, blockSize int) []byte {
	padding := blockSize - len(text) % blockSize //padingは上記でいうブロック長に足りない長さ.ちょうどの場合はブロック長
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(text, padtext...)
}

上記で前処理完了.

ECB

さっそくECB.

の記事には、実装の手本がのっている.

bs := block.BlockSize()
if len(plaintext) % bs != 0 { //前処理をしていれば、ブロック長倍になっている
  panic("Need a multiple of the blocksize")
}
ciphertext := make([]byte, len(plaintext))
for len(plaintext) > 0 {
  block.Encrypt(ciphertext, plaintext)
  plaintext = plaintext[bs:]
  ciphertext = ciphertext[bs:]
}

ciphertext := make([]byte, len(plaintext))で暗号化前の文章のサイズ分の領域を作っておき、for文以下で、ブロック長文毎、暗号化を行なっていく.

つなげてみた

keyに暗号化で利用するkey、srcに暗号化したいinputをパラメーターでわたす. inputがpaddingされ、ECBされる.

$ go run main.go -key private-key -src hoge
[38 138 235 189 120 176 89 240]

暗号化されたものが出力された. なるほど.

まとめ

Goを使ったECBの実装をざっとおうことができた. 次の機会には、「暗号技術入門」なんかを読み直しつつ、気になる暗号化処理を触ってみたい.

tech