LoginSignup
2
0

More than 1 year has passed since last update.

SSH 秘密鍵ファイルの保護の強度気にしてますか?あるいは ssh-keygen の -a (rounds) オプションを調べた話

Last updated at Posted at 2022-10-16

疑問

ssh-keygen コマンドで秘密鍵を生成するとき、 ssh-keygen -t ed25519 -a 128 のように -a オプションで rounds を指定できる。デフォルト値は16になっている。 rounds とは何だろうか?どうも秘密鍵ファイルの保護の強度に影響するようだが。

TL;DR: 結論までジャンプ

ドキュメントを読む

man ssh-keygen を引用すると、

When saving a private key, this option specifies the number of KDF (key derivation function, currently bcrypt_pbkdf(3)) rounds used. Higher numbers result in slower passphrase verification and increased resistance to brute-force password cracking (should the keys be stolen). The default is 16 rounds.

とのこと。秘密鍵ファイルを暗号化するための暗号鍵をパスフレーズから導出する bcrypt_pbkdf 関数のパラメータということだ。 bcrypt_pbkdf 関数は鍵導出関数である PBKDF2 を少し改変したものらしい。

PBKDF2 は rounds に似たパラメータとしてストレッチング回数あるいはイテレーションを持つ。入力されたパスワードとソルトにハッシュ関数を繰り返し適用する操作の回数のことで、導出された鍵の解読の困難さに直結し、コンピュータの計算性能が向上するに従って推奨される回数も引き上げられている。

2021年時点で OWASP が推奨1するストレッチング回数は PBKDF2-HMAC-SHA-256 の場合で31万回。

2000年時点でも推奨回数は1000回だったというから、 rounds がストレッチング回数だとすれば少なすぎるように思える。

実装を読む

実際はどうなのか、 bcrypt_pbkdf 関数の実装を見ていく。

		for (i = 1; i < rounds; i++) {
			/* subsequent rounds, salt is previous output */
			crypto_hash_sha512(sha2salt, tmpout, sizeof(tmpout));
			bcrypt_hash(sha2pass, sha2salt, tmpout);
			for (j = 0; j < sizeof(out); j++)
				out[j] ^= tmpout[j];
		}

出力を固定長のブロックに区切ってブロックごとハッシュ関数を rounds 回適用している。まさにストレッチング回数のことだ。

ただし、ここではハッシュ関数として bcrypt_hash を呼んでいるんでいることに注意しなければならない。

bcrypt_hash 関数はパスワードハッシュ関数の bcrypt を若干改変したもので、鍵拡張のラウンドは64回に固定されている。

n ラウンドの bcrypt 関数を m 回適用すれば n * m ラウンドの bcrypt 関数を1回適用するのに近い解読困難性を得られると 仮定 するなら、 bcrypt_pbkdf 関数全体の解読困難性はラウンドが ストレッチング回数 * 64 回の bcrypt 関数に近いと言える……のだろうか?(さらにブロックの個数を掛けるべきかどうかは分からない。)だとすると -a オプションのデフォルト値16では 16 * 64 = 1024 ラウンドの bcrypt 関数に近い。

bcrypt 関数のラウンド数は2014年時点でも4000回程度がいいとされている(現代ではもう何倍かすべきだろう)。 -a 128 くらいにしてもいいのかもしれない。当然だが増やしすぎると秘密鍵ファイルのアンロックに時間がかかる。

ベンチマークを取る

試しにいくつか秘密鍵ファイルを作り、アンロックにかかる時間を計測してみる。

まず作る。

for rounds in 16 32 64 128 256 512 1024; do
    ssh-keygen -a "$rounds" -f "key_$rounds" -N pass -C comment
done

hyperfine でベンチマークを取る。テストには秘密鍵ファイルのコメントを書き換えるサブコマンド ssh-keygen -c を使った。コマンドラインから -N でパスフレーズを渡せるサブコマンドはこれくらいなため。

% hyperfine \
    'ssh-keygen -c -f key_16 -N pass -C comment' \
    'ssh-keygen -c -f key_32 -N pass -C comment' \
    'ssh-keygen -c -f key_64 -N pass -C comment' \
    'ssh-keygen -c -f key_128 -N pass -C comment' \
    'ssh-keygen -c -f key_256 -N pass -C comment' \
    'ssh-keygen -c -f key_512 -N pass -C comment' \
    'ssh-keygen -c -f key_1024 -N pass -C comment'
実行結果
Benchmark 1: ssh-keygen -c -f key_16 -N pass -C comment
  Time (mean ± σ):     115.1 ms ±   0.7 ms    [User: 112.2 ms, System: 1.3 ms]
  Range (min … max):   114.5 ms … 117.5 ms    25 runs

Benchmark 2: ssh-keygen -c -f key_32 -N pass -C comment
  Time (mean ± σ):     226.3 ms ±   0.6 ms    [User: 222.8 ms, System: 1.5 ms]
  Range (min … max):   225.7 ms … 228.1 ms    13 runs

Benchmark 3: ssh-keygen -c -f key_64 -N pass -C comment
  Time (mean ± σ):     448.1 ms ±   0.5 ms    [User: 444.0 ms, System: 2.0 ms]
  Range (min … max):   447.6 ms … 449.2 ms    10 runs

Benchmark 4: ssh-keygen -c -f key_128 -N pass -C comment
  Time (mean ± σ):     890.8 ms ±   0.4 ms    [User: 886.2 ms, System: 2.7 ms]
  Range (min … max):   890.1 ms … 891.3 ms    10 runs

Benchmark 5: ssh-keygen -c -f key_256 -N pass -C comment
  Time (mean ± σ):      1.778 s ±  0.002 s    [User: 1.771 s, System: 0.005 s]
  Range (min … max):    1.776 s …  1.783 s    10 runs

Benchmark 6: ssh-keygen -c -f key_512 -N pass -C comment
  Time (mean ± σ):      3.554 s ±  0.008 s    [User: 3.542 s, System: 0.008 s]
  Range (min … max):    3.549 s …  3.568 s    10 runs

Benchmark 7: ssh-keygen -c -f key_1024 -N pass -C comment
  Time (mean ± σ):      7.102 s ±  0.025 s    [User: 7.081 s, System: 0.015 s]
  Range (min … max):    7.085 s …  7.171 s    10 runs

Summary
  'ssh-keygen -c -f key_16 -N pass -C comment' ran
    1.97 ± 0.01 times faster than 'ssh-keygen -c -f key_32 -N pass -C comment'
    3.89 ± 0.03 times faster than 'ssh-keygen -c -f key_64 -N pass -C comment'
    7.74 ± 0.05 times faster than 'ssh-keygen -c -f key_128 -N pass -C comment'
   15.45 ± 0.10 times faster than 'ssh-keygen -c -f key_256 -N pass -C comment'
   30.88 ± 0.21 times faster than 'ssh-keygen -c -f key_512 -N pass -C comment'
   61.70 ± 0.45 times faster than 'ssh-keygen -c -f key_1024 -N pass -C comment'
マシンスペック
% ssh -V
OpenSSH_8.6p1, LibreSSL 3.3.6

% system_profiler SPSoftwareDataType SPHardwareDataType
Software:

    System Software Overview:

      System Version: macOS 12.6 (21G115)
      Kernel Version: Darwin 21.6.0
      Boot Volume: Macintosh HD
      Boot Mode: Normal
      Computer Name: natsu
      User Name: uasi (uasi)
      Secure Virtual Memory: Enabled
      System Integrity Protection: Enabled
      Time since boot: 32 days 17:01

Hardware:

    Hardware Overview:

      Model Name: Mac Studio
      Model Identifier: Mac13,1
      Chip: Apple M1 Max
      Total Number of Cores: 10 (8 performance and 2 efficiency)
      Memory: 32 GB
      System Firmware Version: 7459.141.1
      OS Loader Version: 7459.141.1
      Serial Number (system): DXH63NHWCY
      Hardware UUID: 426393CF-E570-5F8B-96D1-083B7FDC0CC4
      Provisioning UDID: 00006001-000461C03445801E
      Activation Lock Status: Enabled

ベンチマーク結果は折りたたんでおくが、 rounds を倍にすると秘密鍵ファイルのアンロックにかかる時間もおよそ倍になる。 Mac Studio (M1 Max) で

  • rounds = 16: 115.1 ms
  • rounds = 128: 890.8 ms
  • rounds = 256: 1.778 s

程度。現代のハードウェアなら rounds を128にしても実用的な範囲に収まるだろう。

結論

  • ssh-keygen-a オプションの値 rounds は秘密鍵ファイル保護用のパスフレーズから暗号鍵を導出する計算量のこと。大きいほど秘密鍵ファイルの解読困難性が上がるが、アンロックにかかる時間も比例して長くなる
  • rounds のデフォルト値である16は2022年現在では低すぎるように思える(が確信はない)
  • 現在のハードウェアでは50〜100程度でもアンロックが1秒以内で終わるため、高めに設定しても損はないはず

既存の秘密鍵ファイルの rounds を変更するには ssh-keygen -p -a 128 -f /path/to/key でいける。元々パスフレーズ変更用のコマンドなので新しいパスフレーズの入力も促されるが、同じにしてよい。

  1. そもそも可能ならより高性能な他の鍵導出関数を使うべきだという話も書かれている

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0