libsodiumでファイル暗号化を試してみました。

Introduction

何故ファイル暗号化にlibsodiumが必要なのかというと

  • C++で使いたい
  • OpenSSLはビルドが面倒
  • ライセンスが緩い

という3点です。

そんなlibsodiumはこちら

**Networking and Cryptography library (NaCL)**の構成コンポーネントのフォークです。

  • クロスプラットフォーム
  • ISCライセンス
    • 2条項BSDライセンスと同等
  • 開発が活発
  • PHP 7.2から暗号化のコアとして採用

という特徴があります。
そんあlibsodiumを使って暗号化処理を試してみました。

How to do?

ソースは下記です。

公式提供のサンプルコードをベースにしているのですが、

  • C++化
    • iostreamを使っているためfopenとか除去
  • 引数チェックなど追加
  • libsodiumをCMakeから利用
  • libsodiumは静的リンク

と改良してあります。

暗号方式は、ChaCha20-Poly1305になります。
詳細はググっていただければと思いますが

とモダンな感じがするアルゴリズムです。

そして、libsodiumにはChaCha20-Poly1305の実装として下記が提供されています。

  • ChaCha20-Poly1305 (オリジナル実装)
  • IETF ChaCha20-Poly1305
  • XChaCha20-Poly1305 (今回使ったのはこれ)

実装の際は、Nonceの長さやメッセージの最大長が違ったりするといった感じに見えます。
(今回使った)XChaCha20-Poly1305での暗号/復号化に必要なのはKEYのみ。
どうも、Nonceは暗号化ファイルのヘッダーに埋め込まれる感じに見えます。
ただ、ヘッダー自体がKEYを使って生成されているので、Nonceが生で入っているような感じでは無いです (未確認)

1
2
3
4
5
typedef struct crypto_secretstream_xchacha20poly1305_state {
unsigned char k[crypto_stream_chacha20_ietf_KEYBYTES];
unsigned char nonce[crypto_stream_chacha20_ietf_NONCEBYTES];
unsigned char _pad[8];
} crypto_secretstream_xchacha20poly1305_state;
1
2
3
4
5
6
static int encrypt(std::string & target_file, std::string & source_file,
const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES])
{
unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
crypto_secretstream_xchacha20poly1305_state st;
crypto_secretstream_xchacha20poly1305_init_push(&st, header, key);

ヘッダーにnonceフィールドがあるのできっとそうなのでしょう。
また、暗号化は

  1. ヘッダー挿入
  2. チャンクサイズ(4096)毎に暗号化

するだけです。
復号化も

  1. ヘッダー解析
  2. チャンクサイズ(4096)毎に復号化

というシンプルさなのも実装が容易で好ましいです。