x/crypto/openpgpでデータを暗号化する
OpenPGPはPGP(Pretty Good Privacy)をベースとした暗号化フォーマットです。 Go言語でもgolang.org/x/crypto/openpgp という準標準パッケージで提供されています。 PGPは公開鍵暗号としてメールの暗号化等でよく使用されますが、パスフレーズを用いた対称暗号として使用することもできますので、今回はこちらを紹介します。 TL;DR 暗号化にはSymmetricallyEncrypt()を使用する 復号にはReadMessage()を使用する prompt次第で無限ループする恐れがあるので注意 暗号化 x/crypto/openpgpパッケージでパスフレーズを用いてファイルを暗号化するには、SymmetricallyEncrypt関数を使用します。 シグネチャは次のようになっています。 1 func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) 順番に見て行きます。まずは引数から。 第一引数であるciphertextには、暗号化されたテキストを出力するio.Writerを与えます。*os.Fileなどを与えてもいいですが、*bytes.Bufferなどを与えてその後*os.Fileにコピーする方が良いでしょう。可読なテキストではなく、バイト列が出力されます。 第二引数のpassphraseはその名の通り、パスフレーズを与えます。 第三引数のhintsには暗号化するファイルのメタデータなどを含むことができますが、単純にnilを与えても良いです。 第四引数のconfigで暗号化方式や乱数エントロピーソース、圧縮アルゴリズムなどを設定することができます。設定しなければ乱数としてcrypto/rand.Readerが、ハッシュ関数としてSHA-256が、暗号化関数としてAES-128が、現在時刻としてtime.Nowが、RSAのビット数として2048がそれぞれ使用されます。圧縮はされません。 返り値は二値で、io.WriteCloserとerrorです。返り値のio.WriteCloserに暗号化したい内容を書き込むことで暗号化が行われます。必ずCloseする必要があるので忘れないように注意しましょう。 使用例 1 2 3 4 5 6 7 8 func encrypt(in io.Reader, out io.Writer, passphrase []byte) error { // omit error handling w, _ := openpgp.SymmetricallyEncrypt(out, passphrase, nil, nil) defer w.Close() io.Copy(w, in) return nil } 復号 暗号化したファイルを復号するには、ReadMessage関数を使用します。Decrypt〜のような関数ではないので注意が必要でしょう。関数のシグネチャは次のようになっています。 1 func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *packet.Config) (*MessageDetails, error) こちらも順に見て行きましょう。 第一引数のio.Readerには暗号化されたファイルを与えます。読み込みですから、*os.Fileを直接与えてもいいかもしれません。 第二引数は復号に使用する鍵へのKeyRingですから、パスフレーズで暗号化した今回はnilを与えます。 第三引数であるpromptがこの関数の肝で、パスフレーズを返すコールバック関数を与えます。PromptFunctionの定義は次のようになっています。 1 type PromptFunction func(keys []Key, symmetric bool) ([]byte, error) 今回の用途の場合は引数を使用する必要はありません。基本的には単純にパスフレーズを返す関数とするか、標準入力等からパスフレーズを読み込んで返す、という関数として作成すれば良いでしょう。 一点だけ注意点があり、ドキュメントに次のような記載があります。 If the decrypted private key or given passphrase isn’t correct, the function will be called again, forever. ...