さまざまなプロトコル(MQTT、HTTP、AMQPなど)を使用してサードパーティからデータを受信するアプリがあります。
一部のクライアントはTLS(TLSサポートのないiotデバイス)を使用できないため、暗号化されたデータを受信するためのコンパクトで簡単な方法を見つける必要があります。
私の考えは、対称アルゴリズム(AES256または類似のもの)を使用することですが、データの送信方法をどのように形式化できますか?
暗号化されたデータと共に、InitializationVectorも渡す必要があります。 encryptedData
+ IV
?をパッケージ化する方法を説明する一般的な「コンテナ」形式があります。
もちろん、ASN.1または他のシリアル化形式を使用して独自の形式を作成することもできますが、何かが存在する場合は、すべての開発者に説明する方が簡単です。
[〜#〜]更新[〜#〜]
暗号化メッセージ構文(CMS PKCS 7) は有効な解決策になりますか?または、小型のIoTデバイスに実装するには複雑すぎますか?
UPDATE 2@AndrolGenhaldによって指摘されたように、デバイス内にキーを保存する場合、saltを渡す必要はありません。塩の要件を削除しました。
UPDATE 3TLSを使用するのが最善の解決策であり、実際、ほとんどのデバイスで使用できます。残念ながら、一部のサードパーティ開発者は、デバイスタイプにTLSがないと私に言っています。詳細は正確にはわかりません(おそらくもっと調査する必要があります...)。 TLSなしで暗号化されたデータを送信する方法を提供するように求められます。
暗号文とIVをパッケージ化する方法の質問に答えるには、連結で十分です:IV || ciphertext || tag
。この形式は、暗号化のストリーミングを可能にするので便利です。 IVを生成して送信し、暗号化をストリーミングしてから、認証タグを計算して送信します(最初にタグを確認する必要があるため、復号化出力はストリーミングできません)。
もちろん、欠点は、アルゴリズムを変更したり、複数のアルゴリズムをサポートしたりすることが難しくなることです。暗号化されていないアルゴリズム識別子を含めることもできますが、攻撃者がそれを好きなように変更して、 ダウングレード攻撃への扉を開く可能性があるため、非常に注意する必要があります 。
しかし、TLSの代わりに事前共有キーを使用してこれを実行したいので、それだけではありません。 TLSは機密性を提供するだけでなく、キーの管理と信頼性(特に)も処理します。事前共有キーの問題は、制約をvery認識している必要があることです。 RFC 4107 は一読の価値があります。
ChaCha20-Poly1305とAES-GCMはどちらも96ビットのnonceを使用します。つまり、2の後で50%の確率で繰り返します。48 ランダムなナンスを使用する場合のメッセージなので、その前にキーを変更する必要があります( NISTによると 2の前32 GCMのメッセージ)。特定のアルゴリズムでは、ランダムIVの代わりにカウンターを使用することもできますが、これにも問題があります。このリスクのため、CMSで使用される ChaCha20-Poly1305 および AES-GCM のRFCは両方とも必要ですrequire自動化された鍵管理システムを使用すること。
最も単純なキー管理システムは、対称キー暗号化キーです。コンテンツキーはメッセージごとにランダムに生成され、暗号化に使用されます。事前共有キーは、メッセージとともに送信するコンテンツキーを暗号化するために使用されます。
あなたの質問は、あなたがパスワードを使用していることを意味する塩に言及しています。これは悪い考えです。パスワードからキーを導出するには、Argon2、bcrypt、またはPBKDF2のような低速のKDFが必要であり、制約されたデバイスは、そのようなKDFを安全に実行するのに十分なコストで実行するには十分な速度ではない可能性があります。少なくとも128ビットのエントロピーで事前共有鍵を生成する方がはるかに良いでしょう。紛らわしいことに、パスワードを変更することを意味するソルトも送信したいのですが、これはデバイスに「キー」を置いたというコメントと矛盾します。
TLSは信頼性を提供します。これは、CBCやCTRなどの一般的に使用される暗号化モードが 可鍛性 であるため重要です。 ChaCha20-Poly1305やAES-GCMのような [〜#〜] aead [〜#〜] モードを使用するか、それが失敗すると、Encrypt-Then-MACでHMACを使用するのが最適です。
暗号で保護されたランダム性を生成できない(したがって、ランダムnonce/IVまたはメッセージごとのキーを生成できない)制約のあるデバイスでは、格納されたnonceカウンターを持つ事前共有キーが最善の方法です。 非常に注意する必要がありますデバイスの電源を入れ直してもノンスの再利用が防止されていることを確認し、必要に応じてキーを簡単に変更できるようにします必要になります。
いつものように、独自の暗号化アルゴリズムをロールすることはおそらくお勧めできません(これには送信フォーマットも含まれます)。初期化ベクトルの送信、パスフレーズからの鍵導出のシード、暗号文自体などを標準化したOpenPGP形式の使用をお勧めします。
gpg
をインストールしてコマンドラインから使用するか(例 here を参照)、または BouncyCastle's 実装を使用します。 SE上のBouncyCastleとGPGに関するいくつかの質問があります。たとえば、Java/GPGの相互運用性を具体的にカバーする this one を参照してください。シンプルな byte[]
復号化/暗号化サービス BouncyCastleのサンプルで実装され、開始点として機能します。
私の考えは、対称アルゴリズム(AES256または類似のもの)を使用することですが、データの送信方法をどのように形式化できますか?
AES256は、使用する細かい対称アルゴリズムです。ただし、モードを選択して正しく使用する必要もあります。 AESの認証済み暗号化モード(GCMなど)を使用することをお勧めします。この場合、暗号化にはMAC(GCMのGMACなど)が追加されます。認証された暗号化モードは、データの暗号化と完全性のタグ付け(MACを介して)の両方を実行するため、データが秘密に保たれるだけでなく、知らないうちに変更することもできません。
暗号化されたデータとともに、InitializationVectorも渡す必要があります。 encryptedData + IVをパッケージ化する方法を説明する一般的な「コンテナ」形式がありますか?
データを暗号化するたびに、新しいランダムIVを作成する必要があります。 IVは、AE暗号化の暗号テキスト出力の最初または最後に単純に連結されます。特定のコンテナーは必要ありません。それ自体は、IV+ciphertext
を送信する(MACタグはAEモードの暗号テキスト出力に含まれている)か、またはciphertext+IV
を送信するだけです。実際には問題ありません。
重要なモードは、暗号化キーをデバイスに保存する安全な方法があり、送信するデータを暗号化するたびに新しいランダムIVを生成することです。
説明したシステム(TLSを使用できない場合)では、エンドポイントに秘密の対称鍵を配布し、それらを安全に保つ必要があると考えられます。これは問題の難しい部分です。 TLSを使用している場合は、サーバーの公開鍵のみが必要であり、世界中のすべてのデバイスで安全に保管する必要がないため、TLSについてそれほど心配する必要はありません。
コメントで、ソフトウェアの制限はないと言っています。私のアドバイスは、OpenSSLライブラリーまたは類似の暗号化ライブラリーをソフトウェアに組み込み、それがTLSチャネルを処理できるようにすることです。独自の暗号化スキームを導入する必要はありません。
さらに、対称暗号化にAESのみを使用すると、その暗号化のために対称鍵を交換する方法の問題が残ります。ハードコーディングは悪いアドバイスであり、鍵交換スキームを作成することは、TLSの再実装または独自のローリングに由来します。どちらの場合も、悪いアドバイスです。