pqc_rails 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +41 -0
- data/LICENSE.txt +104 -0
- data/README.md +306 -0
- data/Rakefile +4 -0
- data/docs/CRYPTO_INVENTORY.md +47 -0
- data/docs/MIGRATION.md +107 -0
- data/docs/THREAT_MODEL.md +146 -0
- data/lib/pqc_rails/active_record/context.rb +42 -0
- data/lib/pqc_rails/active_record/key_provider.rb +67 -0
- data/lib/pqc_rails/algorithms.rb +74 -0
- data/lib/pqc_rails/blob_packing.rb +25 -0
- data/lib/pqc_rails/cipher.rb +74 -0
- data/lib/pqc_rails/configuration.rb +47 -0
- data/lib/pqc_rails/dh_kem.rb +66 -0
- data/lib/pqc_rails/envelope_cipher.rb +59 -0
- data/lib/pqc_rails/ffi/kem.rb +40 -0
- data/lib/pqc_rails/ffi/sig.rb +68 -0
- data/lib/pqc_rails/generators/install/install_generator.rb +48 -0
- data/lib/pqc_rails/generators/install/templates/initializer.rb +10 -0
- data/lib/pqc_rails/hybrid_kem.rb +128 -0
- data/lib/pqc_rails/kem.rb +116 -0
- data/lib/pqc_rails/key_source.rb +84 -0
- data/lib/pqc_rails/length_validation.rb +16 -0
- data/lib/pqc_rails/session/encryptor.rb +45 -0
- data/lib/pqc_rails/session/key_manager.rb +43 -0
- data/lib/pqc_rails/session/pqc_cookie_store.rb +56 -0
- data/lib/pqc_rails/sig.rb +159 -0
- data/lib/pqc_rails/version.rb +5 -0
- data/lib/pqc_rails.rb +26 -0
- data/sig/pqc_rails.rbs +4 -0
- metadata +151 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 250cd3e1bab5ae8124f2cc0d6441a47eb345eae6335018afd753106e4bdb8dac
|
|
4
|
+
data.tar.gz: 82a5414aeb14643970385b6bcb7304a0705d7a0a1398dd2a43c244ea12a20b8f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: bb87fe83e203d59c9b467bc0b1fb3ec03f6133910817a992bf6bfc8de4f41faaa3c8a4a9f5b24749033e7d5bd452d781f38ad53f53a7c85450e2dd9b2b3bcfa8
|
|
7
|
+
data.tar.gz: 631e9d0db9810ca52adc069b6c876b4d7f044c74eb3f3d1f4272a16a468224644a64c1d135bdbbbf88347021c78793a39e895845cfe786628ef861769fe3ccf3
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-07-22
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- FFI bindings to [liboqs](https://github.com/open-quantum-safe/liboqs) for NIST-standardized
|
|
15
|
+
post-quantum algorithms: ML-KEM (FIPS 203, levels 512/768/1024) and ML-DSA (FIPS 204, levels
|
|
16
|
+
44/65/87), exposed as `PqcRails::Kem` and `PqcRails::Sig`.
|
|
17
|
+
- `PqcRails::Algorithms` registry resolving symbols (e.g. `:ml_kem_768`) to liboqs algorithm
|
|
18
|
+
names, while still allowing raw liboqs strings for algorithms outside the registry (e.g.
|
|
19
|
+
Classic McEliece, HQC).
|
|
20
|
+
- `PqcRails::HybridKem`: a KEM-DEM hybrid public-key encryption scheme combining X25519 (classical
|
|
21
|
+
ECDH) with a post-quantum KEM via HKDF-SHA256, backed by `PqcRails::EnvelopeCipher`
|
|
22
|
+
(AES-256-GCM).
|
|
23
|
+
- `PqcRails::Session::PqcCookieStore`: a drop-in replacement for Rails' `cookie_store` that
|
|
24
|
+
encrypts session data with `HybridKem` instead of the standard AES-256-GCM signed/encrypted
|
|
25
|
+
cookie jar.
|
|
26
|
+
- `PqcRails::ActiveRecord::Context` and `PqcRails::Cipher` / `PqcRails::ActiveRecord::KeyProvider`:
|
|
27
|
+
a full `ActiveRecord::Encryption` integration, replacing Rails' default cipher and key provider
|
|
28
|
+
with the `HybridKem`-based implementation.
|
|
29
|
+
- Multi-generation key rotation for both the session store and `ActiveRecord::Encryption`:
|
|
30
|
+
`previous_keypairs` support lets old keys keep decrypting existing data/sessions while new
|
|
31
|
+
writes use the current key.
|
|
32
|
+
- `pqc_rails:install` generator, scaffolding the initializer and writing session/record keys to
|
|
33
|
+
Rails credentials.
|
|
34
|
+
- `docs/MIGRATION.md`: dual-stack migration guide (adopting `pqc_rails` alongside existing
|
|
35
|
+
encrypted data), key rotation procedure, key-loss recovery guidance, and rollback steps.
|
|
36
|
+
- `docs/THREAT_MODEL.md` and `docs/CRYPTO_INVENTORY.md`: threat model and crypto-inventory
|
|
37
|
+
documentation for decision-makers and developers.
|
|
38
|
+
- CI workflow building liboqs from source and running the test suite on push/PR.
|
|
39
|
+
|
|
40
|
+
[Unreleased]: https://github.com/mabutast/pqc_rails/compare/v0.1.0...HEAD
|
|
41
|
+
[0.1.0]: https://github.com/mabutast/pqc_rails/releases/tag/v0.1.0
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
Business Source License 1.1
|
|
2
|
+
|
|
3
|
+
License text copyright (c) 2024 MariaDB plc, All Rights Reserved.
|
|
4
|
+
"Business Source License" is a trademark of MariaDB plc.
|
|
5
|
+
|
|
6
|
+
-----------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
Parameters
|
|
9
|
+
|
|
10
|
+
Licensor: Haruyuki Onodera
|
|
11
|
+
|
|
12
|
+
Licensed Work: pqc_rails
|
|
13
|
+
The Licensed Work is (c) 2026 Haruyuki Onodera
|
|
14
|
+
|
|
15
|
+
Additional Use Grant: You may make production use of the Licensed Work,
|
|
16
|
+
provided that such use is not a Commercial Use.
|
|
17
|
+
"Commercial Use" means use of the Licensed Work, or
|
|
18
|
+
any derivative work, in connection with a product or
|
|
19
|
+
service (i) for which a fee is charged, or (ii) which
|
|
20
|
+
is provided by or on behalf of a for-profit entity as
|
|
21
|
+
part of its business operations.
|
|
22
|
+
|
|
23
|
+
Change Date: 2030-07-16 (July 16th, 2030)
|
|
24
|
+
|
|
25
|
+
Change License: Apache License, Version 2.0
|
|
26
|
+
|
|
27
|
+
-----------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
Terms
|
|
30
|
+
|
|
31
|
+
The Licensor hereby grants you the right to copy, modify, create derivative
|
|
32
|
+
works, redistribute, and make non-production use of the Licensed Work. The
|
|
33
|
+
Licensor may make an Additional Use Grant, above, permitting limited
|
|
34
|
+
production use.
|
|
35
|
+
|
|
36
|
+
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
37
|
+
available distribution of a specific version of the Licensed Work under this
|
|
38
|
+
License, whichever comes first, the Licensor hereby grants you rights under
|
|
39
|
+
the terms of the Change License, and the rights granted in the paragraph
|
|
40
|
+
above terminate.
|
|
41
|
+
|
|
42
|
+
If your use of the Licensed Work does not comply with the requirements
|
|
43
|
+
currently in effect as described in this License, you must purchase a
|
|
44
|
+
commercial license from the Licensor, its affiliated entities, or authorized
|
|
45
|
+
resellers, or you must refrain from using the Licensed Work.
|
|
46
|
+
|
|
47
|
+
All copies of the original and modified Licensed Work, and derivative works
|
|
48
|
+
of the Licensed Work, are subject to this License. This License applies
|
|
49
|
+
separately for each version of the Licensed Work and the Change Date may vary
|
|
50
|
+
for each version of the Licensed Work released by Licensor.
|
|
51
|
+
|
|
52
|
+
You must conspicuously display this License on each original or modified copy
|
|
53
|
+
of the Licensed Work. If you receive the Licensed Work in original or
|
|
54
|
+
modified form from a third party, the terms and conditions set forth in this
|
|
55
|
+
License apply to your use of that work.
|
|
56
|
+
|
|
57
|
+
Any use of the Licensed Work in violation of this License will automatically
|
|
58
|
+
terminate your rights under this License for the current and all other
|
|
59
|
+
versions of the Licensed Work.
|
|
60
|
+
|
|
61
|
+
This License does not grant you any right in any trademark or logo of
|
|
62
|
+
Licensor or its affiliates (provided that you may use a trademark or logo of
|
|
63
|
+
Licensor as expressly required by this License).
|
|
64
|
+
|
|
65
|
+
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
|
66
|
+
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
|
67
|
+
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
|
68
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
|
69
|
+
TITLE.
|
|
70
|
+
|
|
71
|
+
MariaDB hereby grants you permission to use this License's text to license
|
|
72
|
+
your works, and to refer to it using the trademark "Business Source License",
|
|
73
|
+
as long as you comply with the Covenants of Licensor below.
|
|
74
|
+
|
|
75
|
+
-----------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
Covenants of Licensor
|
|
78
|
+
|
|
79
|
+
In consideration of the right to use this License's text and the "Business
|
|
80
|
+
Source License" name and trademark, Licensor covenants to MariaDB, and to all
|
|
81
|
+
other recipients of the licensed work to be provided by Licensor:
|
|
82
|
+
|
|
83
|
+
1. To specify as the Change License the GPL Version 2.0 or any later version,
|
|
84
|
+
or a license that is compatible with GPL Version 2.0 or a later version,
|
|
85
|
+
where "compatible" means that software provided under the Change License can
|
|
86
|
+
be included in a program with software provided under GPL Version 2.0 or a
|
|
87
|
+
later version. Licensor may specify additional Change Licenses without
|
|
88
|
+
limitation.
|
|
89
|
+
|
|
90
|
+
2. To either: (a) specify an additional grant of rights to use that does not
|
|
91
|
+
impose any additional restriction on the right granted in this License, as
|
|
92
|
+
the Additional Use Grant; or (b) insert the text "None".
|
|
93
|
+
|
|
94
|
+
3. To specify a Change Date.
|
|
95
|
+
|
|
96
|
+
4. Not to modify this License in any other way.
|
|
97
|
+
|
|
98
|
+
-----------------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
Notice
|
|
101
|
+
|
|
102
|
+
The Business Source License (this document, or the "License") is not an Open
|
|
103
|
+
Source license. However, the Licensed Work will eventually be made available
|
|
104
|
+
under an Open Source License, as stated in this License.
|
data/README.md
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# PqcRails
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/rb/pqc_rails)
|
|
4
|
+
[](https://github.com/mabutast/pqc_rails/actions/workflows/test.yml)
|
|
5
|
+
|
|
6
|
+
**pqc_rails** は、既存の Ruby on Rails アプリケーションに耐量子暗号(PQC: Post-Quantum Cryptography)を組み込むための gem です。[liboqs](https://github.com/open-quantum-safe/liboqs) への FFI バインディングを通じて、NIST 標準化アルゴリズムを Ruby ネイティブに呼び出します。
|
|
7
|
+
|
|
8
|
+
ジェネレータを実行した後、2 行の設定を追加するだけで Rails アプリのセッションと DB を PQC 化できます。
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
rails generate pqc_rails:install
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
# config/application.rb
|
|
16
|
+
config.session_store :pqc_cookie_store
|
|
17
|
+
|
|
18
|
+
# config/initializers/pqc_rails.rb
|
|
19
|
+
PqcRails::ActiveRecord::Context.install!
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## PQC 対応が必要な理由
|
|
23
|
+
|
|
24
|
+
PQC 対応の義務化を待つ理由はありません。今この瞬間も、ハーベスト攻撃(Harvest Now, Decrypt Later:暗号化通信を今傍受し、将来の量子コンピュータで解読する攻撃)によってデータは蓄積され続けています。
|
|
25
|
+
|
|
26
|
+
過去に漏れたデータは取り返せませんが、これから先の通信は今日から守ることができます。`pqc_rails` は、既存の Rails アプリケーションに耐量子暗号を組み込み、この現在進行形のリスクに対処します。
|
|
27
|
+
|
|
28
|
+
詳しい脅威モデルはこちら → [docs/THREAT_MODEL.md](docs/THREAT_MODEL.md)
|
|
29
|
+
|
|
30
|
+
自組織のクリプト・インベントリに `pqc_rails` の利用箇所を記載する際の記入例はこちら → [docs/CRYPTO_INVENTORY.md](docs/CRYPTO_INVENTORY.md)
|
|
31
|
+
|
|
32
|
+
## 現在の対応状況
|
|
33
|
+
|
|
34
|
+
| 機能 | 状態 |
|
|
35
|
+
| ----------------------------- | ------------------------------------------------ |
|
|
36
|
+
| KEM(鍵カプセル化機構) | ✅ 対応済み(ML-KEM-512/768/1024 で動作確認) |
|
|
37
|
+
| DSA(署名アルゴリズム) | ✅ 対応済み(ML-DSA-44/65/87 で動作確認) |
|
|
38
|
+
| セッション暗号化 | ✅ 対応済み(`PqcCookieStore`) |
|
|
39
|
+
| ActiveRecord::Encryption 連携 | ✅ 対応済み(`PqcRails::Cipher` + `KeyProvider`) |
|
|
40
|
+
| 鍵ローテーション | ✅ 対応済み(セッション・DB 双方で旧鍵世代を併用可能。詳細は [docs/MIGRATION.md](docs/MIGRATION.md#鍵ローテーションpqc_rails鍵世代間)) |
|
|
41
|
+
|
|
42
|
+
KEM と DSA に加え、セッション Cookie と ActiveRecord::Encryption の両方を ML-KEM ベースのハイブリッド暗号(KEM-DEM 構成)で保護します。liboqs がサポートする他のアルゴリズムも、アルゴリズム名を文字列で指定するだけで利用できます(liboqs 側のビルド設定に依存します)。
|
|
43
|
+
|
|
44
|
+
## スコープ
|
|
45
|
+
|
|
46
|
+
- **対象はアプリケーション層の暗号化**(セッション Cookie・DB カラム)です。TLS 通信路そのものの PQC 化(Web サーバ・ロードバランサ側の設定)は対象外です。Ruby / RubyGems エコシステム側でも標準ライブラリ全体を PQC 対応させる議論([Ruby Feature #22068](https://bugs.ruby-lang.org/issues/22068))が進んでいますが、これは輸送路の話であり、`pqc_rails` が担うアプリケーションデータの暗号化とはレイヤーが異なります。
|
|
47
|
+
- **PKI・証明書管理基盤の代替ではありません**。鍵の発行・ライフサイクル管理・監査ログといった機能は提供しません。`pqc_rails` が担うのは Rails アプリ内のセッション・DB カラムの暗号化のみです。
|
|
48
|
+
- **量子コンピュータそのものを使う暗号方式(QKD、量子署名など)は対象外です**。`pqc_rails` が提供するのは、古典コンピュータ上で動作し量子コンピュータに対して耐性を持つ暗号(PQC: Post-Quantum Cryptography)です。
|
|
49
|
+
- **JWT/トークン署名は対象外です**。`PqcRails::Sig`(ML-DSA)はスタンドアロンの署名プリミティブとして提供していますが、セッション・DB統合と違いJWT等のトークンフォーマットへの統合は行っていません。この用途には [jwt-pq](https://rubygems.org/gems/jwt-pq) のような専用 gem を検討してください(`pqc_rails` とは別々の liboqs を読み込むため、併用しても競合しません)。
|
|
50
|
+
|
|
51
|
+
より詳しい対応範囲・スコープ外は [docs/THREAT_MODEL.md](docs/THREAT_MODEL.md#for-developers) を参照してください。
|
|
52
|
+
|
|
53
|
+
## 想定するユースケース
|
|
54
|
+
|
|
55
|
+
長期保存が必要なデータを扱う Rails アプリケーション全般が対象ですが、特に以下のような用途では緊急度が高くなります。
|
|
56
|
+
|
|
57
|
+
- 医療記録・法務文書など、10年20年単位で機密性が求められるデータを扱うアプリケーション
|
|
58
|
+
- 金融・暗号資産関連のセッション管理や取引履歴を扱うアプリケーション(秘密鍵・取引データの窃取が量子コンピュータ実用化後に致命的な損失に直結するため)
|
|
59
|
+
|
|
60
|
+
## 必要要件
|
|
61
|
+
|
|
62
|
+
- Ruby >= 3.2.0
|
|
63
|
+
- Rails >= 7.1
|
|
64
|
+
- RubyGems / Bundler >= 4.0.16 を推奨(rubygems.org は X25519MLKEM768 + ML-DSA-65 によるハイブリッド TLS を提供しており、4.0.16 未満では `Gem::Request` / `Bundler::Fetcher` のクライアント証明書鍵種別が RSA に決め打ちされる不具合の影響を受けます)
|
|
65
|
+
- [liboqs](https://github.com/open-quantum-safe/liboqs)(C ライブラリ)がビルド・インストール済みであること
|
|
66
|
+
- 本 gem は liboqs を同梱しません。事前に共有ライブラリ(`liboqs.dylib` / `liboqs.so`)をビルドし、システムに配置してください。
|
|
67
|
+
|
|
68
|
+
## ⚠️ liboqs の成熟度について
|
|
69
|
+
|
|
70
|
+
本 gem は [liboqs](https://github.com/open-quantum-safe/liboqs) を基盤としています。liboqs は [Open Quantum Safe (OQS)](https://openquantumsafe.org/) プロジェクトによって開発されている、NIST の耐量子暗号標準化プロジェクトに基づくアルゴリズム実装です。
|
|
71
|
+
|
|
72
|
+
liboqs 自身の公式ドキュメントでは、以下の点が明記されています:
|
|
73
|
+
|
|
74
|
+
- liboqs は研究・プロトタイピングを目的としており、**本番環境や機密データの保護に依存することは現時点では推奨されていません**
|
|
75
|
+
- セキュリティバグを避けるための最善の努力はされていますが、本番投入に必要な水準の監査・分析はまだ実施されていません
|
|
76
|
+
|
|
77
|
+
`pqc_rails` は liboqs を「正しく安全に呼び出す」ことに責任を持ちますが、liboqs 自体の暗号実装の正しさ・安全性を保証するものではありません。本番環境への導入を検討される際は、上記の liboqs の現状を踏まえ、利用するシステムの重要度に応じたリスク評価を行ってください。
|
|
78
|
+
|
|
79
|
+
NIST 標準化アルゴリズム自体(ML-KEM, ML-DSA など)は確定した仕様ですが、その「実装」の成熟度は今後も liboqs 側の改善とともに変わっていく可能性があります。
|
|
80
|
+
|
|
81
|
+
## インストール
|
|
82
|
+
|
|
83
|
+
Gemfile に以下を追記:
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
gem "pqc_rails"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
その後:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
bundle install
|
|
93
|
+
rails generate pqc_rails:install
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
ジェネレータが `config/initializers/pqc_rails.rb` を生成し、セッション用・DB 用の鍵を Rails credentials に書き込みます。
|
|
97
|
+
|
|
98
|
+
## 設定
|
|
99
|
+
|
|
100
|
+
### liboqs ライブラリパス
|
|
101
|
+
|
|
102
|
+
liboqs の共有ライブラリへのパスを指定します。未設定の場合、環境変数 `LIBOQS_PATH`、それも無ければ OS ごとの一般的な場所(macOS: `/usr/local/lib/liboqs.dylib`、Linux: `/usr/local/lib/liboqs.so`)を仮定します。
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
# config/initializers/pqc_rails.rb
|
|
106
|
+
PqcRails.configure do |config|
|
|
107
|
+
config.liboqs_path = "/usr/local/lib/liboqs.dylib"
|
|
108
|
+
end
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### セッション暗号化
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
# config/application.rb
|
|
115
|
+
config.session_store :pqc_cookie_store
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Rails の `cookie_store` を ML-KEM ベースの PQC ストアで完全に置き換えます。既存のセッションは切り替え時に無効化されます(全ユーザーが再ログインになります)。
|
|
119
|
+
|
|
120
|
+
鍵は Rails credentials の `pqc_session_key` から読み込みます。環境変数 `PQC_SESSION_KEY` で上書き可能です。
|
|
121
|
+
|
|
122
|
+
#### Cookie サイズについて
|
|
123
|
+
|
|
124
|
+
`HybridKem` の ciphertext を含むため、Cookie は Rails 標準(AES-256-GCM)より大きくなります。実測値(開発機、単純なセッション内容での計測)は次の通りです。
|
|
125
|
+
|
|
126
|
+
| 内容 | pqc_rails(ML-KEM-768、デフォルト) | Rails 標準 |
|
|
127
|
+
| ----------------------------- | ------------------------------------ | ---------- |
|
|
128
|
+
| 空セッション | 約1,770 bytes | 約170 bytes |
|
|
129
|
+
| `user_id` + CSRF トークン程度 | 約1,850 bytes | 約260 bytes |
|
|
130
|
+
|
|
131
|
+
単一 Cookie の上限(多くのブラウザで4,096 bytes)には収まりますが、他の Cookie(analytics・A/B テスト用等)と合算されるリクエストヘッダ全体の上限(多くのサーバ/プロキシで8KB前後)には注意してください。
|
|
132
|
+
|
|
133
|
+
より小さいサイズが必要な場合、`pq_alg_name: :ml_kem_512` を指定するとサイズを抑えられます(NIST セキュリティレベルは768の「レベル3」から512の「レベル1」に下がります)。
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
config.session_store :pqc_cookie_store, pq_alg_name: :ml_kem_512
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### ActiveRecord::Encryption
|
|
140
|
+
|
|
141
|
+
```ruby
|
|
142
|
+
# config/initializers/pqc_rails.rb
|
|
143
|
+
PqcRails::ActiveRecord::Context.install!
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
```ruby
|
|
147
|
+
# モデル
|
|
148
|
+
class User < ApplicationRecord
|
|
149
|
+
encrypts :email, :phone_number
|
|
150
|
+
end
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`ActiveRecord::Encryption` の Cipher と KeyProvider を ML-KEM ベースの実装に置き換えます。新規導入の場合はそのまま利用できます。既存の ActiveRecord::Encryption(Rails デフォルト)で暗号化済みのデータがある場合、切り替え後はデフォルトでは復号できなくなります。一括での再暗号化が難しい場合は、Rails 標準の `previous:` スキーム機構を使って段階移行できます → [docs/MIGRATION.md](docs/MIGRATION.md)
|
|
154
|
+
|
|
155
|
+
鍵は Rails credentials の `pqc_record_key` から読み込みます。環境変数 `PQC_RECORD_KEY` で上書き可能です。セッション用の鍵とは別管理です。
|
|
156
|
+
|
|
157
|
+
## 使い方
|
|
158
|
+
|
|
159
|
+
### アルゴリズムの指定方法
|
|
160
|
+
|
|
161
|
+
`PqcRails::Kem` / `PqcRails::Sig` は、liboqs の生のアルゴリズム名文字列(`"ML-KEM-512"` 等)に加えて、シンボル(`:ml_kem_512` 等)でも指定できます。シンボルは `PqcRails::Algorithms` レジストリ経由で liboqs 名に解決されます。
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
PqcRails::Kem.new(:ml_kem_512) # シンボル指定(推奨)
|
|
165
|
+
PqcRails::Kem.new("ML-KEM-512") # liboqs の生の名前を直接指定
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
現在レジストリに登録済みのアルゴリズム:
|
|
169
|
+
|
|
170
|
+
| 種別 | シンボル | NIST セキュリティレベル |
|
|
171
|
+
| ---- | ---------------------------------------------- | ----------------------- |
|
|
172
|
+
| KEM | `:ml_kem_512` / `:ml_kem_768` / `:ml_kem_1024` | 1 / 3 / 5 |
|
|
173
|
+
| SIG | `:ml_dsa_44` / `:ml_dsa_65` / `:ml_dsa_87` | 2 / 3 / 5 |
|
|
174
|
+
|
|
175
|
+
未登録のシンボルを渡すと `PqcRails::Algorithms::UnknownAlgorithmError`(`PqcRails::Error` のサブクラス)が発生します。
|
|
176
|
+
|
|
177
|
+
このレジストリ経由の解決方式により、アプリケーションコードは liboqs の生の名前や個々のアルゴリズムの実装詳細に直接依存しません。将来 NIST 標準の追加・非推奨化や liboqs 側の命名変更があっても、レジストリ側の対応表を更新するだけで済みます。これはクリプトグラフィック・アジリティ(暗号アルゴリズムを迅速に切り替えられる性質)の実装例で、金融庁「預金取扱金融機関の耐量子計算機暗号への対応に関する検討会 報告書」が具体的な実現方法として挙げる「メインルーチンでは抽象化した暗号機能の呼び出しに留め、具体的なアルゴリズム・パラメータによる処理を分離しておく」という設計パターンに沿っています。
|
|
178
|
+
|
|
179
|
+
#### レジストリ未登録のアルゴリズムを使う(例: Classic McEliece)
|
|
180
|
+
|
|
181
|
+
シンボルレジストリに無いアルゴリズムでも、liboqs 側でビルドされていれば liboqs の生の名前を文字列で渡すことで利用できます。例えば符号ベース暗号の Classic McEliece([ISO/IEC 18033-2:2006/Amd 2:2026](https://www.iso.org/standard/86890.html) として標準化済み)は次のように使えます。
|
|
182
|
+
|
|
183
|
+
```ruby
|
|
184
|
+
PqcRails::Kem.open("Classic-McEliece-348864") do |kem|
|
|
185
|
+
keypair = kem.generate_keypair
|
|
186
|
+
keypair.public_key.bytesize # => 261120(約255KB。ML-KEM-512の800バイトと比べ大幅に大きい)
|
|
187
|
+
end
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
公開鍵サイズが大きい(348864 パラメータセットで約255KB)ため TLS ハンドシェイクのような頻繁な鍵交換には向きませんが、鍵交換の頻度が低い長期保存データの暗号化では ML-KEM が万一破られた場合のバックアップとして選択肢になります。異なる数学的困難性(符号の復号問題)に安全性の根拠を置くため、ML-KEM(格子問題)とは異なるリスクプロファイルを持ちます。
|
|
191
|
+
|
|
192
|
+
同様に、NIST が ML-KEM のバックアップとして選定した符号ベースKEM「HQC」も liboqs 0.16.0 以降ではデフォルトで有効化されており、生の名前(`"HQC-1"` / `"HQC-3"` / `"HQC-5"`)を渡すことで利用できます。ただしHQCはまだNIST標準化作業中(FIPS番号未確定)のため、シンボルレジストリには未登録です。
|
|
193
|
+
|
|
194
|
+
```ruby
|
|
195
|
+
PqcRails::Kem.open("HQC-1") do |kem|
|
|
196
|
+
keypair = kem.generate_keypair
|
|
197
|
+
keypair.public_key.bytesize # => 2241
|
|
198
|
+
end
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 鍵交換(KEM)の基本フロー
|
|
202
|
+
|
|
203
|
+
```ruby
|
|
204
|
+
PqcRails::Kem.open("ML-KEM-512") do |kem|
|
|
205
|
+
# 受信側: 鍵ペアを生成
|
|
206
|
+
keypair = kem.generate_keypair
|
|
207
|
+
|
|
208
|
+
# 送信側: 受信側の公開鍵から共有秘密と ciphertext を生成
|
|
209
|
+
encapsulation = kem.encapsulate(keypair.public_key)
|
|
210
|
+
|
|
211
|
+
# 受信側: ciphertext と自分の秘密鍵から共有秘密を復元
|
|
212
|
+
shared_secret = kem.decapsulate(encapsulation.ciphertext, keypair.secret_key)
|
|
213
|
+
|
|
214
|
+
shared_secret == encapsulation.shared_secret # => true
|
|
215
|
+
end
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
`PqcRails::Kem.open` はブロックを抜けると自動的にネイティブメモリを解放します。手動でリソースを管理したい場合は `new` / `free` を直接使うこともできます。
|
|
219
|
+
|
|
220
|
+
```ruby
|
|
221
|
+
kem = PqcRails::Kem.new("ML-KEM-512")
|
|
222
|
+
# ...
|
|
223
|
+
kem.free
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
#### 鍵長の参照
|
|
227
|
+
|
|
228
|
+
```ruby
|
|
229
|
+
kem = PqcRails::Kem.new("ML-KEM-512")
|
|
230
|
+
kem.length_public_key # => 800
|
|
231
|
+
kem.length_secret_key # => 1632
|
|
232
|
+
kem.length_ciphertext # => 768
|
|
233
|
+
kem.length_shared_secret # => 32
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### 署名(DSA)の基本フロー
|
|
237
|
+
|
|
238
|
+
```ruby
|
|
239
|
+
PqcRails::Sig.open("ML-DSA-44") do |sig|
|
|
240
|
+
# 署名者: 鍵ペアを生成
|
|
241
|
+
keypair = sig.generate_keypair
|
|
242
|
+
|
|
243
|
+
# 署名者: メッセージに署名
|
|
244
|
+
signature = sig.sign("hello world", keypair.secret_key)
|
|
245
|
+
|
|
246
|
+
# 検証者: 署名を検証
|
|
247
|
+
sig.verify("hello world", signature, keypair.public_key) # => true
|
|
248
|
+
end
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
`verify` は、署名が無効な場合に例外を発生させず `false` を返します(liboqs の `OQS_SIG_verify` の挙動に準拠)。
|
|
252
|
+
|
|
253
|
+
```ruby
|
|
254
|
+
sig.verify("tampered message", signature, keypair.public_key) # => false
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
`PqcRails::Sig` も `PqcRails::Kem` と同様、`open` によるブロック形式と `new` / `free` による手動管理の両方をサポートしています。
|
|
258
|
+
|
|
259
|
+
#### 鍵長・署名長の参照
|
|
260
|
+
|
|
261
|
+
```ruby
|
|
262
|
+
sig = PqcRails::Sig.new("ML-DSA-44")
|
|
263
|
+
sig.length_public_key # => 1312
|
|
264
|
+
sig.length_secret_key # => 2560
|
|
265
|
+
sig.length_signature # => 2420(最大長。実際の署名はこれより短いことがあります)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## エラーハンドリング
|
|
269
|
+
|
|
270
|
+
- 未知のアルゴリズム名や、liboqs が有効化していないアルゴリズムを指定すると `PqcRails::Error` が発生します。
|
|
271
|
+
- `encapsulate` / `decapsulate` / `sign` に渡すバイト列の長さが不正な場合は `ArgumentError` が発生します。
|
|
272
|
+
- `free` 済みのインスタンスに対する操作は `PqcRails::Error` が発生します。
|
|
273
|
+
- `PqcRails::Sig#verify` は、署名が無効な場合でも例外を発生させず `false` を返します(KEM とは異なる設計です)。
|
|
274
|
+
- `ActiveRecord::Encryption` で復号に失敗した場合は `ActiveRecord::Encryption::Errors::Decryption` が発生します。
|
|
275
|
+
- セッション Cookie が不正・改竄されている場合は空のセッションとして扱います(クラッシュしません)。
|
|
276
|
+
|
|
277
|
+
## 動作確認済み環境
|
|
278
|
+
|
|
279
|
+
- Ruby 3.2 / 3.3 / 3.4
|
|
280
|
+
- Rails 7.1 / 8.1
|
|
281
|
+
- liboqs 0.15.0 / 0.16.0
|
|
282
|
+
|
|
283
|
+
[CI](.github/workflows/test.yml) では Ruby 3.4 + Rails 8.1 + liboqs 0.15.0 の組み合わせを push・PR のたびに継続的に検証しています。liboqs 0.16.0、および他の Ruby/Rails バージョンの組み合わせは手動で動作確認済みです(CIのマトリクス化は今後の対応予定)。
|
|
284
|
+
|
|
285
|
+
## 開発
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
bin/setup
|
|
289
|
+
bundle exec rspec
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## ライセンス
|
|
293
|
+
|
|
294
|
+
[Business Source License 1.1 (BSL)](LICENSE.txt) を採用しています。
|
|
295
|
+
|
|
296
|
+
- ソースコードは公開し、開発・検証・非商用利用は無料です
|
|
297
|
+
- 商用利用(対価を得る用途、または営利企業が事業活動の一環として使う用途)には別途ライセンス契約が必要です
|
|
298
|
+
- 各バージョンのリリースから4年後、自動的にオープンソースライセンス(Apache License 2.0)に移行します
|
|
299
|
+
|
|
300
|
+
詳細な条件は [LICENSE.txt](LICENSE.txt) を参照してください。商用利用に関するお問い合わせは contact@rubyquantum.dev までご連絡ください。
|
|
301
|
+
|
|
302
|
+
商用利用の判定基準(Additional Use Grant の文言)は、正式な法律レビューを経る前の暫定版です。実際に商用ライセンス契約を結ぶ段階までに見直す可能性があります。
|
|
303
|
+
|
|
304
|
+
## コントリビューション
|
|
305
|
+
|
|
306
|
+
Issue・Pull Request は [GitHub](https://github.com/mabutast/pqc_rails) で受け付けています。
|
data/Rakefile
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# クリプト・インベントリ テンプレート
|
|
2
|
+
|
|
3
|
+
クリプト・インベントリとは、組織内で利用している暗号モジュールや暗号方式の一覧です。PQCへの移行を計画する際、まず「どこで・何のために・どの暗号方式を使っているか」を把握することが出発点になります。金融庁「預金取扱金融機関の耐量子計算機暗号への対応に関する検討会 報告書」(2024年11月)は、この構築を移行準備の柱の一つとして挙げています。
|
|
4
|
+
|
|
5
|
+
このドキュメントは、`pqc_rails` を導入したアプリケーションが、自組織のクリプト・インベントリに `pqc_rails` の利用箇所をどう記載すればよいかの記入例です。実際の値はアプリケーションの設定(鍵管理方法、DB暗号化対象カラム等)によって変わるため、記入例を出発点に、自組織の実際の設定に置き換えて利用してください。
|
|
6
|
+
|
|
7
|
+
## 記入項目と pqc_rails の記入例
|
|
8
|
+
|
|
9
|
+
| 項目 | 内容 |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| **スコープ** | 自組織開発のシステム、または自組織外から提供されたgem・製品(`pqc_rails` はこちらに該当) |
|
|
12
|
+
| **暗号利用場面** | セッションCookieの暗号化(`PqcCookieStore` 経由)。ActiveRecordモデルの特定カラムの暗号化(`encrypts` 宣言経由) |
|
|
13
|
+
| **暗号用途** | セッション: ユーザーとの通信内容(セッションデータ)の保護。DBカラム: お客様情報を安全に保存するため |
|
|
14
|
+
| **暗号実装箇所** | 自組織外から提供された製品(gem `pqc_rails`)。内部では [liboqs](https://github.com/open-quantum-safe/liboqs) へのFFIバインディングを経由 |
|
|
15
|
+
| **利用アルゴリズム** | 鍵交換: ML-KEM(NIST FIPS 203) + X25519のハイブリッド構成(`HybridKem`)。データ本体: AES-256-GCM(`EnvelopeCipher`)。デフォルトパラメータセットは ML-KEM-768 |
|
|
16
|
+
| **利用している暗号鍵長** | ML-KEM-768: 公開鍵1184バイト / 秘密鍵2400バイト / 暗号文1088バイト / 共有鍵32バイト。AES-256-GCM: 256ビット鍵 |
|
|
17
|
+
| **暗号鍵の更新頻度** | 現時点では鍵ローテーション(複数世代の鍵の切り替え)は未対応です。単一世代の鍵を使い続ける構成のため、鍵を更新する場合は再暗号化が必要になります |
|
|
18
|
+
| **暗号鍵管理方法** | Rails credentials(`pqc_session_key` / `pqc_record_key`)、または環境変数(`PQC_SESSION_KEY` / `PQC_RECORD_KEY`)。セッション用とDB用で鍵は分離されています。HSM・クラウドKMSとの統合は現時点で未対応です |
|
|
19
|
+
| **長期保護データとの接点有無** | セッションCookieは通常ログインセッション程度の短期間ですが、DBカラムに保存するデータの保護期間はアプリケーションの用途に依存します。医療記録・法務文書・金融取引データ等、長期保護が必要なデータをこの経路で扱う場合は、[THREAT_MODEL.md](THREAT_MODEL.md#どのデータが危険か) のX+Y>Zフレームワークで緊急度を評価してください |
|
|
20
|
+
|
|
21
|
+
## 収集方法
|
|
22
|
+
|
|
23
|
+
`pqc_rails` の利用箇所そのものは、以下の方法で機械的に洗い出せます。
|
|
24
|
+
|
|
25
|
+
- `config/application.rb` の `config.session_store :pqc_cookie_store` の有無(セッション暗号化の利用有無)
|
|
26
|
+
- `config/initializers/pqc_rails.rb` の `PqcRails::ActiveRecord::Context.install!` の有無(DBカラム暗号化の利用有無)
|
|
27
|
+
- 各モデルの `encrypts :カラム名` 宣言(暗号化対象カラムの特定)
|
|
28
|
+
|
|
29
|
+
これらはコード解析ツール(`grep -rn "encrypts \|pqc_cookie_store\|Context.install"` 等)で機械的に検出可能です。
|
|
30
|
+
|
|
31
|
+
## 自組織用の記入欄(空欄テンプレート)
|
|
32
|
+
|
|
33
|
+
| 項目 | 記入欄 |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| スコープ | |
|
|
36
|
+
| 暗号利用場面 | |
|
|
37
|
+
| 暗号用途 | |
|
|
38
|
+
| 暗号実装箇所 | |
|
|
39
|
+
| 利用アルゴリズム | |
|
|
40
|
+
| 利用している暗号鍵長 | |
|
|
41
|
+
| 暗号鍵の更新頻度 | |
|
|
42
|
+
| 暗号鍵管理方法 | |
|
|
43
|
+
| 長期保護データとの接点有無 | |
|
|
44
|
+
|
|
45
|
+
## 参考
|
|
46
|
+
|
|
47
|
+
- [金融庁「預金取扱金融機関の耐量子計算機暗号への対応に関する検討会 報告書」](https://www.fsa.go.jp/singi/pqc/houkokusyo.pdf)(表5.1「クリプト・インベントリの構成例」を参考に項目を選定)
|
data/docs/MIGRATION.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# 既存データの移行(Dual-Stack)
|
|
2
|
+
|
|
3
|
+
`PqcRails::ActiveRecord::Context.install!` は `ActiveRecord::Encryption` のグローバル設定(cipher・key_provider)を置き換えます。既に Rails 標準の `ActiveRecord::Encryption`(AES-256-GCM + 導出鍵)で暗号化済みのデータがある場合、切り替え後はデフォルトでは復号できません。
|
|
4
|
+
|
|
5
|
+
一括で全レコードを再暗号化できない場合は、Rails 標準の `previous:` スキーム機構を使って段階移行できます。新しい書き込みは `pqc_rails` で暗号化しつつ、既存データは旧方式のまま読み出せる状態にする方法です。
|
|
6
|
+
|
|
7
|
+
## 設定
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
class User < ApplicationRecord
|
|
11
|
+
encrypts :email, previous: [
|
|
12
|
+
{
|
|
13
|
+
cipher: ActiveRecord::Encryption::Cipher.new,
|
|
14
|
+
key_provider: ActiveRecord::Encryption::DerivedSecretKeyProvider.new(OLD_PRIMARY_KEY)
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
end
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- `OLD_PRIMARY_KEY` は、`pqc_rails` 導入前に使っていた `Rails.application.credentials.active_record_encryption.primary_key`(または `config.active_record.encryption.primary_key`)の値です。credentials から削除する前に控えておいてください。
|
|
21
|
+
- `cipher:` に Rails 標準の `ActiveRecord::Encryption::Cipher.new` を明示的に指定するのが要点です。`previous:` は `key_provider:` だけでなく `cipher:` も含めた実行コンテキストをまるごと差し替えるため、暗号化アルゴリズム自体が異なる pqc_rails 導入前後のデータを同じ属性宣言で両方読めるようになります。
|
|
22
|
+
|
|
23
|
+
## 動作
|
|
24
|
+
|
|
25
|
+
| 操作 | 挙動 |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| 新規レコードの書き込み | 現在の設定(`Context.install!` 後の pqc_rails の Cipher + KeyProvider)で暗号化される |
|
|
28
|
+
| pqc_rails 導入後に書き込まれたレコードの読み出し | 現在の設定でそのまま復号される |
|
|
29
|
+
| pqc_rails 導入前に書き込まれたレコードの読み出し | 現在の設定での復号に失敗すると、`previous:` に列挙したスキームを順番に試し、旧方式(AES-256-GCM + 導出鍵)で復号される |
|
|
30
|
+
|
|
31
|
+
読み出しのたびに現在の設定→`previous:`の順で試行するため、`previous:` に列挙するスキームが増えるほど、失敗した場合の復号コストが増える点には注意してください。移行が完了し旧方式のデータが残っていないことを確認できたら、`previous:` オプションと `OLD_PRIMARY_KEY` は削除して構いません。
|
|
32
|
+
|
|
33
|
+
## 一括再暗号化したい場合
|
|
34
|
+
|
|
35
|
+
段階移行ではなく一括で再暗号化したい場合は、Rails 標準の `bin/rails db:encryption:init` 相当の仕組みは pqc_rails には無いため、対象モデルの全レコードを読み出して `save!` するマイグレーションタスクを自前で用意してください(読み出し時に上記の `previous:` 機構で旧データが復号され、書き込み時には現在の設定=pqc_rails で再暗号化されます)。
|
|
36
|
+
|
|
37
|
+
## 鍵ローテーション(pqc_rails鍵世代間)
|
|
38
|
+
|
|
39
|
+
上記の `previous:` は「pqc_rails 導入前の暗号方式」からの移行を扱いますが、ここで扱うのは「pqc_rails 導入後、鍵そのものを世代交代させたい」場合の手順です。セッション・DB のどちらも、現行鍵に加えて旧鍵世代を併用できます。
|
|
40
|
+
|
|
41
|
+
### DB(ActiveRecord::Encryption)
|
|
42
|
+
|
|
43
|
+
`PqcRails::ActiveRecord::KeyProvider#decryption_keys` は、現行鍵に続けて旧鍵世代を返します。ローテーションの手順は次の通りです。
|
|
44
|
+
|
|
45
|
+
1. 新しい鍵ペアを生成し、`PQC_RECORD_KEY`(または `pqc_record_key` credentials)に設定する
|
|
46
|
+
2. 元々 `PQC_RECORD_KEY` に設定していた値を `PQC_RECORD_PREVIOUS_KEYS`(または `pqc_record_previous_keys` credentials)に移す
|
|
47
|
+
3. アプリを再起動する。新規の暗号化は新しい鍵で行われ、旧鍵で暗号化済みのレコードもそのまま復号できる
|
|
48
|
+
4. 旧鍵で暗号化されたレコードが残っている間は `PQC_RECORD_PREVIOUS_KEYS` を維持する。全レコードを新しい鍵で再暗号化し終えたら(上記「一括再暗号化したい場合」の手順を新旧鍵の組で実行)、`PQC_RECORD_PREVIOUS_KEYS` を削除してよい
|
|
49
|
+
|
|
50
|
+
`PQC_RECORD_PREVIOUS_KEYS` は複数の旧鍵をカンマ区切りで指定できます(credentials の場合は配列)。世代数に上限はありません。
|
|
51
|
+
|
|
52
|
+
### セッション(PqcCookieStore)
|
|
53
|
+
|
|
54
|
+
`PqcCookieStore` は書き込み(`set_cookie`)には常に現行鍵のみを使い、読み込み(`get_cookie`)は現行鍵で復号できなかった場合に旧鍵世代を順に試します。手順は DB 側と同様に `PQC_SESSION_KEY` / `PQC_SESSION_PREVIOUS_KEYS`(または `pqc_session_key` / `pqc_session_previous_keys` credentials)を使います。
|
|
55
|
+
|
|
56
|
+
セッションは DB のレコードと異なり、Cookie の有効期限(`expire_after` 等)が過ぎれば自然に失効します。そのため `PQC_SESSION_PREVIOUS_KEYS` は「ローテーション後、旧鍵で発行されたセッションが有効期限切れになるまで」の一時的な設定として運用し、その期間を過ぎたら削除してください(DB側のような一括再暗号化の手順は不要です)。
|
|
57
|
+
|
|
58
|
+
### 外部鍵ソース(HSM等)への差し替えについて
|
|
59
|
+
|
|
60
|
+
鍵の取得元は、デフォルトでは `PqcRails::KeySource::EnvCredentials`(ENV → Rails credentials)です。`#current_keypair` / `#previous_keypairs` の2メソッドを実装したオブジェクトであれば差し替えられます。
|
|
61
|
+
|
|
62
|
+
- **DB側**: `PqcRails::ActiveRecord::KeyProvider.new(key_source: your_source)` のように、`Context.install!` に渡す `KeyProvider` へ直接注入できます。
|
|
63
|
+
- **セッション側**: `PqcRails::Session::KeyManager` はモジュール実装のため同様の注入口はありませんが、`PqcCookieStore` は `keypair:` / `previous_keypairs:` オプションで実際の鍵ペアを直接受け取れます(`KeyManager` を経由しない)。外部鍵ソースから取得した鍵ペアをこのオプションに渡すことで、同様に差し替え可能です。
|
|
64
|
+
|
|
65
|
+
将来 HSM/PKCS#11 経由の鍵管理と連携する場合の拡張ポイントとして用意していますが、pqc_rails 自体は具体的な HSM 連携実装を提供しません。
|
|
66
|
+
|
|
67
|
+
## 鍵の紛失・災害復旧
|
|
68
|
+
|
|
69
|
+
`PQC_RECORD_KEY` / `PQC_SESSION_KEY`(または対応する credentials)を紛失すると、その鍵で暗号化された DB カラム・セッション Cookie は二度と復号できません。pqc_rails 自体は鍵のエスクロー機能を持たず、liboqs にもその機能はないため、鍵のバックアップは利用者側の運用に完全に委ねられています。特に DB カラムは長期間残り続けるデータであるため、**鍵紛失イコールデータの永久喪失**に直結します。
|
|
70
|
+
|
|
71
|
+
以下は推奨する運用です。
|
|
72
|
+
|
|
73
|
+
- **Rails credentials 経由で鍵を管理する場合**:実質的な「鍵の鍵」は `config/master.key`(または `RAILS_MASTER_KEY`)です。`config/credentials.yml.enc` はリポジトリに含まれますが、`master.key` はバージョン管理から除外されるため、これ自体を通常のインフラ資産と同様のバックアップ体制(社内のシークレット管理システム、複数人でのオフライン保管等)に含めてください。
|
|
74
|
+
- **環境変数(`PQC_RECORD_KEY` 等)経由で管理する場合**:値そのものを手動でファイルに控えるのではなく、AWS Secrets Manager・HashiCorp Vault・GCP Secret Manager 等のシークレットマネージャが提供するバージョニング・自動バックアップ機能を利用してください。
|
|
75
|
+
- **定期的な復旧リハーサル**:バックアップした鍵が「存在すること」の確認だけでは不十分です。実際にその鍵をテスト環境へ復元し、既存の暗号化データを復号できることまで確認してください。バックアップ手順自体の欠陥(フォーマット破損、鍵の取り違え等)は、復旧を試みて初めて発覚します。
|
|
76
|
+
- **鍵ローテーションを平常運用に組み込む**:上記の鍵ローテーション手順を定期的に実施することで、単一世代の鍵に依存し続ける期間そのものを短くできます。
|
|
77
|
+
|
|
78
|
+
複数管理者による鍵の分散管理(Shamir's Secret Sharing 等による鍵分割)や鍵のエスクローが必要な場合、pqc_rails 自体はその機能を提供しないため、前述の外部鍵ソース差し替え機構を経由した HSM/KMS の利用を検討してください。
|
|
79
|
+
|
|
80
|
+
## ロールバック手順(pqc_rails 導入前の状態に戻す)
|
|
81
|
+
|
|
82
|
+
pqc_rails 導入後に、何らかの理由で導入前の状態へ戻す必要が生じた場合の手順です。
|
|
83
|
+
|
|
84
|
+
### DB(ActiveRecord::Encryption)
|
|
85
|
+
|
|
86
|
+
考え方は導入時の段階移行と対称です。`previous:` に pqc_rails 側のスキームを指定することで、新規の書き込みを Rails 標準方式に戻しつつ、pqc_rails で暗号化済みのデータも読み出せる状態にします。
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
class User < ApplicationRecord
|
|
90
|
+
encrypts :email, previous: [
|
|
91
|
+
{
|
|
92
|
+
cipher: PqcRails::Cipher.new,
|
|
93
|
+
key_provider: PqcRails::ActiveRecord::KeyProvider.new
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
end
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
- `Context.install!` の呼び出し自体を削除(または呼ばない状態に戻す)することで、新規の暗号化は Rails 標準(AES-256-GCM + 導出鍵)に戻ります。
|
|
100
|
+
- 完全に pqc_rails 以前の状態へ戻したい場合は、上記「一括再暗号化したい場合」と同じ要領で全レコードを読み出して `save!` し、Rails 標準方式で再暗号化してください。
|
|
101
|
+
- 移行が完了し pqc_rails 方式のデータが残っていないことを確認できるまで、`PQC_RECORD_KEY`(または `pqc_record_key` credentials)は削除しないでください。
|
|
102
|
+
|
|
103
|
+
### セッション(PqcCookieStore)
|
|
104
|
+
|
|
105
|
+
セッションには DB のような「既存データを段階的に読み替える」仕組みはそもそも必要ありません。セッション Cookie は元々 `expire_after` 等で有効期限が切れる一時的なデータであるためです。
|
|
106
|
+
|
|
107
|
+
`config.session_store` を `:pqc_cookie_store` から `:cookie_store`(Rails 標準)へ戻すだけでロールバックは完了しますが、これは導入時の移行と同様に**その時点で有効な全セッションが無効化される(全ユーザーが再ログインになる)**ことを意味します。これは不具合ではなく、導入時と対称な想定内の挙動です。段階的にロールバックしたい場合の仕組み(旧方式との併用)は現時点では提供していません。
|