web-dev-qa-db-ja.com

GnuPGを使用して可能な限り最小の出力(対称暗号化)を取得するにはどうすればよいですか?

QRコードに埋め込むことができる非常に小さなOpenPGP暗号化ファイルを作成しようとしています。

ただし、たとえばOpenSSLと比較すると、GnuPGは「a」の単純な入力に対して非常に大きな結果を生成するようです。

$ echo -n a|openssl enc -aes-256-ctr|wc -c 
17
$ echo -n a|gpg --symmetric -o-|wc -c
71

マニュアルを読むと、違いの1つは、OpenSSLにはデフォルトで8バイトのヘッダーと8バイトのソルトしか含まれていないのに対し、GnuPGにはソルト、チェックサム、圧縮も含まれていることです。これらをオフにすると、ファイルサイズは小さくなりますが、それでも大きくなります。

$ echo -n a|gpg --symmetric --compress-algo none --disable-mdc --s2k-mode 0 -o-|wc -c
35

OpenPGPで暗号化されたメッセージをさらに最適化する方法はありますか(AESを有効にしたまま)?

7
Daan Bakker

GnuPGのバイナリ形式はかなりスペース効率が良いですが、絶対に最小のメッセージサイズではなく、柔軟性のために構築されています(通常、実際のメッセージは数バイトよりはるかに大きいです)。最小の「通常の」OpenPGPメッセージは31バイトの大きさですが、追加の作業を行うことで26バイトに削減できます。これは、シングルバイトコンテンツのOpenPGPv4メッセージとして可能な最小のものです。

OpenPGPメッセージの分析、バイト数のカウント

RFC 4880を見ると、メッセージの最小の長さを導き出すことができますが、これを下回ることはできません。

作成したコマンドの出力を見てみましょう。

$ echo -n a|gpg --symmetric --compress-algo none --disable-mdc --s2k-mode 0 -o-|gpg --list-packets
gpg: Note: simple S2K mode (0) is strongly discouraged
    gpg: AES encrypted data
gpg: encrypted with 1 passphrase
gpg: WARNING: message was not integrity protected

最初のパケットは 対称鍵暗号化セッション鍵パケット です。これは、文字列からキーへのメカニズムを使用してパスフレーズによって暗号化されたセッションキーのコピーを保持します。 OpenSSLはこれを行いませんが、パスフレーズの代わりにセッションキーを提供し、セッションキーを個別に提供しない限り、これをスキップすることはできません(以下で説明します)。このパケットは6バイトの大きさで、次のものから構築されます。

# off=0 ctb=8c tag=3 hlen=2 plen=4
:symkey enc packet: version 4, cipher 7, s2k 0, hash 10

これで、暗号化されたデータパケットが開始されます。を含む:

  • 2バイト パケットヘッダー(タグと長さ)
  • 18バイトのランダムプレフィックス(0バイトのIVの代わりに、OpenPGP CFBは暗号ブロックのサイズのランダムプレフィックスを使用し、最初の2バイトを繰り返します。AESは暗号ブロックの長さとして128ビット= 16バイトを使用します)
# off=6 ctb=c9 tag=9 hlen=2 plen=26 new-ctb
:encrypted data packet:
    length: 26

OpenPGPは、常にメッセージを リテラルデータパケット に格納します。これにより、メタデータが追加されます。圧縮を無効にすると、少なくとも追加の圧縮ヘッダーが削除されます。このパケットは最終的にさらに9バイトを追加します。

  • 2バイト パケットヘッダー(タグと長さ)
  • 1バイトのデータ形式
  • 1バイトのファイル名文字列の長さ(値はゼロ、ファイル名は続きません)
  • 4バイトのタイムスタンプ
  • 1バイトのコンテンツ
# off=26 ctb=cb tag=11 hlen=2 plen=6 new-ctb
:literal data packet:
    mode b (62), created 1503680075, name="",
    raw data: 0 bytes

まとめ:文字列からキーへの導出を省略し、パスフレーズの代わりにセッションキーを直接使用しない限り、さらに1バイトを保存することはできません。

文字列からキーへの関数の省略

GnuPGでは、--show-session-keyおよび--override-session-keyを使用してセッションキーを読み取って設定できます。 メッセージ構成の章 を読んで、有効なOpenPGPメッセージがセッションキーの暗号化を定義するパケットをまったく必要としないことに実際に驚いた。 GnuPGは確かにこの種の操作をサポートしていますが、これはOpenPGPを使用する非常に難解な方法であるため、他の実装には賭けません。

   OpenPGP Message :- Encrypted Message | Signed Message |
                      Compressed Message | Literal Message.
   Encrypted Message :- Encrypted Data | ESK Sequence, Encrypted Data.
   Encrypted Data :- Symmetrically Encrypted Data Packet |
         Symmetrically Encrypted Integrity Protected Data Packet

そうすることで、対称鍵暗号化セッション鍵パケットの6バイトを節約できます。

対称鍵暗号化セッション鍵パケットを使用しないOpenPGPメッセージの作成

GnuPGに事前定義されたセッションキーを使用させる方法が見つかりませんでした。ただし、対称的に暗号化されたメッセージを生成し、復号化中にセッションキーを抽出してから、メッセージを分割することができます。

メッセージの暗号化:

$ echo -n a|gpg --symmetric --compress-algo none --disable-mdc --s2k-mode 0 -o message.gpg

セッションキーの抽出(パスフレーズを要求します):

$ gpg --show-session-key 0 --decrypt message.gpg
gpg: AES encrypted data
gpg: encrypted with 1 passphrase
gpg: session key: '7:F7FBBA6E0636F890E56FBBF3283E524C'
agpg: WARNING: message was not integrity protected

OpenPGPメッセージを個々のパケットに分割します。

$ gpgsplit message.gpg

このフォルダには、暗号化されたmessage.gpg、暗号化されていないmessage、対称鍵で暗号化されたセッションキーパケット000001-003.sym_enc、最後に暗号化されたデータパケット000002-009.encryptedの4つのファイルが保持されます。

$ ls -l
total 16
-rw-r--r-- 1 jenserat jenserat  6 Aug 25 19:36 000001-003.sym_enc
-rw-r--r-- 1 jenserat jenserat 29 Aug 25 19:36 000002-009.encrypted
-rw-r--r-- 1 jenserat jenserat  1 Aug 25 19:04 message
-rw-r--r-- 1 jenserat jenserat 35 Aug 25 19:33 message.gpg

個々のパケットファイルをconcatenateして、message.gpgを取得することもできます。これらの2つのファイルはmessage.gpgの一部に分割されています。上記のサイズと正確に一致するファイルサイズを確認してください(もちろん、gpgsplitはパスフレーズを認識しないため、リテラルデータパケットのサイズは暗号化されたデータパケットに含まれます)。

別の暗号化されたデータパケットの復号化

この手順はかなり簡単です。

$ gpg --override-session-key '7:F7FBBA6E0636F890E56FBBF3283E524C' --decrypt 000002-009.encrypted 
agpg: WARNING: message was not integrity protected

出力である警告メッセージの前にあるaを見落とさないでください。

警告メッセージの意味

GnuPGは2つの警告メッセージを出力しました。

gpg:注:単純なS2Kモード(0)は強くお勧めしません

これは、単純なS2Kモードでは、ハッシュやソルトを使用しないため、パスフレーズに対するブルートフォース攻撃や辞書攻撃が安価で簡単になるためです。

もちろん、同じパスフレーズを使用して暗号化された複数のファイルに同じセッションキーを使用することもできますが、その結果に注意してください。

gpg:警告:メッセージは完全性保護されていませんでした

この警告メッセージは、復号化当事者がこの事実を認識できずに、攻撃者によってメッセージが変更された可能性があることを示しています。これは、--disable-mdcが原因です。もちろん、ファイルの暗号化されたチェックサムのためにいくつかのバイトが保存されます。 16進エディタで最後のバイトを変更することにより、自分で試すことができます。

8
Jens Erat