web-dev-qa-db-ja.com

暗号化と暗号学に関する教訓と誤解

暗号学は非常に幅広いテーマであり、経験豊富なプログラマーであっても、ほとんどの場合、最初の数回は間違いを犯します。ただし、暗号化は非常に重要なトピックであるため、多くの場合、これらの間違いを犯す余裕はありません。

この質問の目的は、特定のアルゴリズムまたはAPIで何を行うかnotを特定してリストすることです。このようにして、他の人の経験から学び、悪い習慣の蔓延を防ぐことができます。

この質問を建設的にするために、

  1. 「間違った」例を含める
  2. その例の何が悪いのかを説明する
  3. 正しい実装を提供します(該当する場合)。
  4. できる限り、上記の#2と#3に関する参照を提供してください。
68

独自の暗号をロールバックしないでください。

独自の暗号化アルゴリズムやプロトコルを発明しないでください。それは非常にエラーが発生しやすいです。ブルース・シュナイアーが言うのが好きなように、

「だれもが解読できない暗号化アルゴリズムを発明することができる。だれも解読できない暗号化アルゴリズムを発明するのははるかに難しい」と語った。

暗号アルゴリズムは非常に複雑であり、それらが安全であることを確認するために徹底的な調査が必要です。あなたが自分で発明したとしても、あなたはそれを得ることができません、そしてそれを実現せずに何かが安全でないものになってしまうことは非常に簡単です。

代わりに、標準の暗号化アルゴリズムとプロトコルを使用してください。おそらく、他の誰かが以前に問題に遭遇し、その目的に適したアルゴリズムを設計したことがあるでしょう。

最良のケースは、高レベルの十分に吟味されたスキームを使用することです。通信セキュリティのために、TLS(またはSSL)を使用します。保存データの場合は、GPG(またはPGP)を使用します。それができない場合は、 cryptlib 、GPGME、 Keyczar 、または NaCL などの高レベルの暗号ライブラリを使用してください。 OpenSSL、CryptoAPI、JCEなどの低レベルのものです。この提案を提供してくれたNate Lawsonに感謝します。

76
D.W.

メッセージ認証なしで暗号化を使用しないでください

認証せずにデータを暗号化することは非常に一般的なエラーです。

例:開発者はメッセージを秘密にしたいので、AES-CBCモードでメッセージを暗号化します。エラー:これは、アクティブな攻撃、リプレイ攻撃、リアクション攻撃などが存在する場合のセキュリティには不十分です。メッセージ認証なしの暗号化に対する既知の攻撃があり、攻撃は非常に深刻になる可能性があります。修正は、メッセージ認証を追加することです。

この間違いは、認証なしで暗号化を使用する展開されたシステムに重大な脆弱性をもたらしました ASP.NET[〜#〜] xml [〜#〜]暗号化Amazon EC2JavaServer Faces、Ruby on Rails、OWASP ESAPI[〜#〜] ipsec [〜#〜][〜#〜] wep [〜#〜]ASP.NET againSSH2 。このリストの次のものになりたくない。

これらの問題を回避するには、暗号化を適用するたびにメッセージ認証を使用する必要があります。その方法には2つの選択肢があります。

  • おそらく最も簡単な解決策は、 authenticated encryption を提供する暗号化スキームを使用することです(例:GCM、CWC、EAX、CCM、OCB)。 (参照: 1 。)認証された暗号化スキームがこれを処理するので、ユーザーが考える必要はありません。

  • または、次のように独自のメッセージ認証を適用できます。まず、適切な対称鍵暗号化スキーム(AES-CBCなど)を使用してメッセージを暗号化します。次に、暗号文全体(解読に必要なIV、ノンス、またはその他の値を含む)を取得し、メッセージ認証コード(AES-CMAC、SHA1-HMAC、SHA256-HMACなど)を適用し、結果のMACダイジェストを送信前の暗号文。受信側で、復号化する前にMACダイジェストが有効であることを確認します。これは、暗号化してから認証する構造と呼ばれます。 (参照: 12 。)これも正常に機能しますが、もう少し注意が必要です。

47
D.W.

ハッシュする前に、複数の文字列を連結するときは注意してください。

私が時々見るエラー:人々は文字列SとTのハッシュを望みます。彼らはそれらを連結して単一の文字列S || Tを取得し、それをハッシュしてH(S || T)を取得します。これには欠陥があります。

問題:連結により、2つの文字列の境界が曖昧になります。例:builtin || securely = built || insecurely。言い換えると、ハッシュH(S || T)は文字列SとTを一意に識別しないため、攻撃者はハッシュを変更せずに2つの文字列間の境界を変更できる可能性があります。たとえば、アリスが2つの文字列builtinsecurelyを送信したい場合、攻撃者はこれらを2つの文字列builtinsecurelyに変更し、ハッシュ。

文字列の連結にデジタル署名またはメッセージ認証コードを適用する場合も、同様の問題が発生します。

修正:単純な連結ではなく、明確にデコード可能なエンコードを使用します。たとえば、H(S || T)を計算する代わりに、H(length(S)|| S || T)を計算できます。ここで、length(S)は、Sの長さをバイトで表す32ビット値です。または、H(H(S)|| H(T))、またはH(H(S)|| T)を使用することもできます。

この欠陥の実際の例については、 Amazon Web Servicesのこの欠陥 または Flickrのこの欠陥 [pdf]を参照してください。

36
D.W.

ナンスまたはIVを再利用しないでください

多くの動作モードでは、IV(初期化ベクトル)が必要です。 IVに同じ値を2回再使用してはなりません。これを行うと、すべてのセキュリティ保証が取り消され、壊滅的なセキュリティ違反が発生する可能性があります。

  • CTRモードやOFBモードなどのストリーム暗号モードの操作では、IVの再利用はセキュリティ上の問題です。暗号化されたメッセージを簡単に回復できる可能性があります。

  • CBCモードなどの他の操作モードでは、IVを再利用すると、平文回復攻撃を促進する場合もあります。

使用する操作モードに関係なく、IVを再利用しないでください。それを正しく行う方法について疑問がある場合は、 NIST仕様 で、ブロック暗号の動作モードを適切に使用する方法の詳細なドキュメントを提供します。

Tarsnapプロジェクトは、この落とし穴の良い例を提供します。 Tarsnapは、バックアップデータをチャンクに分割して暗号化し、各チャンクをCTRモードのAESで暗号化します。 Tarsnapのバージョン1.0.22〜1.0.27では、同じIVが誤って再利用され、プレーンテキストのリカバリが可能になりました。

どうしてそうなった? Tarsnapコードを簡略化するために、そしてバグの可能性を減らすことを期待して、Colin Percivalは、AES-CTRコードを新しいファイル(Tarsnapソースコード内のlib/crypto/crypto_aesctr.c)に「リファクタリング」する機会を得ました)そして、これらのルーチンを利用するためにAES-CTRが使用された既存の場所を変更しました。新しいコードは次のようになります。

/*データを暗号化します。 */
-aes_ctr(&encr_aes-> key、encr_aes-> nonce ++、buf、len、
-filebuf + CRYPTO_FILE_HLEN); 
 + if((stream = 
 + crypto_aesctr_init(&encr_aes-> key、encr_aes-> nonce))== NULL)
 + goto err0; 
 + crypto_aesctr_stream(stream、buf、filebuf + CRYPTO_FILE_HLEN、len); 
 + crypto_aesctr_free(stream); 

リファクタリング中、encr_aes->nonce++誤ってencr_aes->nonce、その結果同じノンス値が繰り返し使用されました。特に、各チャンクが暗号化された後、CTR nonce値は増加しません。 (CTRカウンターは、データの16バイトが処理されるたびに正しくインクリメントされますが、このカウンターは新しいチャンクごとにゼロにリセットされます。)詳細は、Colin Percivalの http://www.daemonology。 net/blog/2011-01-18-tarsnap-critical-security-bug.html

29
Alex Holst

乱数ジェネレータに十分なエントロピーをシードするようにしてください。

キーの生成、IV /ノンスの選択などに、暗号強度の疑似乱数ジェネレータを使用してください。Rand()random()drand48()は使用しないでください、など.

疑似乱数ジェネレータに十分なエントロピーをシードするようにしてください。時刻を指定しないでください。それは推測可能です。

例:srand(time(NULL))は非常に悪いです。 PRNG=をシードする良い方法は、128ビットまたは真の乱数を取得することです。たとえば、/dev/urandom、CryptGenRandomなど。 Javaでは、Randomではなく、SecureRandomを使用してください。 .NETでは、System.Randomではなく、System.Security.Cryptography.RandomNumberGeneratorを使用します。 Pythonでは、ランダムではなく、random.SystemRandomを使用します。いくつかの例を提供してくれたNate Lawsonに感謝します。

実際の例: Netscapeのブラウザの初期バージョンのこの欠陥 を参照してください。これにより、攻撃者はSSLを破ることができました。

29
D.W.

対称暗号化にはECBでブロック暗号を使用しないでください

(AES、3DES、...に適用)

ECBモードで暗号化されていないコードがどのように生成されるかについては、 post と非常によく似た Microsoft KB記事 をご覧ください。

this like post も参照してください Rook から

プレーンテキストメッセージ:

alt text

ECBモードで暗号化された同じメッセージ(使用する暗号は関係ありません): alt text

CBCモードを使用したまったく同じメッセージ(ここでも、使用する暗号は関係ありません): alt text

間違った方法

public static string Encrypt(string toEncrypt, string key, bool useHashing)
{

byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);

if (useHashing)
    keyArray = new MD5CryptoServiceProvider().ComputeHash(keyArray);

var tdes = new TripleDESCryptoServiceProvider() 
    { Key = keyArray, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 };

ICryptoTransform cTransform = tdes.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(
    toEncryptArray, 0, toEncryptArray.Length);

return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}

エラーは次の行にあります

{Key = keyArray、Mode = CipherMode.ECB、Padding = PaddingMode.PKCS7};


正しい方法

Microsoftの優秀な方から、上記のリンク先のKB記事を修正するための次のコードが送られてきました。これは、ケース#111021973179005で参照されています

このサンプルコードは、AESを使用してデータを暗号化しています。AES暗号化のキーは、SHA256によって生成されたハッシュコードです。 AESはAdvanced Encryption Standard(AES)アルゴリズムです。 AESアルゴリズムは、置換と置換に基づいています。順列はデータの再配置であり、置換はデータの1つの単位を別の単位に置き換えます。 AESは、いくつかの異なる手法を使用して置換と置換を実行します。 AESの詳細については、MSDNマガジン http://msdn.Microsoft.com/en-us/magazine/cc164055.aspx)の記事「新しい高度な暗号化規格でデータを安全に保つ」を参照してください。

SHAはセキュアハッシュアルゴリズムです。 SHA-2(SHA-224、SHA-256、SHA-384、SHA-512)が推奨されるようになりました。 .NET Frameworkのハッシュ値の詳細については、 http://msdn.Microsoft.com/en-us/library/92f9ye3s.aspx#hash_values を参照してください。

AesCryptoServiceProviderの対称アルゴリズムの動作モードのデフォルト値はCBCです。 CBCは、Cipher Block Chainingモードです。フィードバックを紹介します。各プレーンテキストブロックが暗号化される前に、ビットごとに排他的なOR演算によって前のブロックの暗号テキストと結合されます。これにより、プレーンテキストに多数の同一ブロックが含まれている場合でも、それぞれが異なる暗号テキストブロックに暗号化します。初期化ベクトルは、ブロックが暗号化される前に、ビット単位の排他OR演算によって最初のプレーンテキストブロックと結合されます。暗号テキストブロックの単一ビットががマングルされると、対応するプレーンテキストブロックもマングルされます。さらに、後続のブロックの元のマングルビットと同じ位置にあるビットがマングルされます。CipherModeの詳細については、 http://msdn.Microsoft.com/en-us/library/system.security.cryptography.ciphermode.aspx を参照してください。

これがサンプルコードです。

// This function is used for encrypting the data with key and iv.
byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
{
    // Create an AESCryptoProvider.
    using (var aesCryptoProvider = new AesCryptoServiceProvider())
    {
        // Initialize the AESCryptoProvider with key and iv.
        aesCryptoProvider.KeySize = key.Length * 8;
        aesCryptoProvider.IV = iv;
        aesCryptoProvider.Key = key;

        // Create encryptor from the AESCryptoProvider.
        using (ICryptoTransform encryptor = aesCryptoProvider.CreateEncryptor())
        {
            // Create memory stream to store the encrypted data.
            using (MemoryStream stream = new MemoryStream())
            {
                // Create a CryptoStream to encrypt the data.
                using (CryptoStream cryptoStream = new CryptoStream(stream, encryptor, CryptoStreamMode.Write))
                    // Encrypt the data.
                    cryptoStream.Write(data, 0, data.Length);

                // return the encrypted data.
                return stream.ToArray();
            }
        }
    }
}

// This function is used for decrypting the data with key and iv.
byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
{
    // Create an AESCryptoServiceProvider.
    using (var aesCryptoProvider = new AesCryptoServiceProvider())
    {
        // Initialize the AESCryptoServiceProvier with key and iv.
        aesCryptoProvider.KeySize = key.Length * 8;
        aesCryptoProvider.IV = iv;
        aesCryptoProvider.Key = key;

        // Create decryptor from the AESCryptoServiceProvider.
        using (ICryptoTransform decryptor = aesCryptoProvider.CreateDecryptor())
        {
            // Create a memory stream including the encrypted data.
            using (MemoryStream stream = new MemoryStream(data))
            {
                // Create a CryptoStream to decrypt the encrypted data.
                using (CryptoStream cryptoStream = new CryptoStream(stream, decryptor, CryptoStreamMode.Read))
                {
                    // Create a byte buffer array.
                    byte[] readData = new byte[1024];
                    int readDataCount = 0;

                    // Create a memory stream to store the decrypted data.
                    using (MemoryStream resultStream = new MemoryStream())
                    {
                        do
                        {
                            // Decrypt the data and write the data into readData buffer array.
                           readDataCount = cryptoStream.Read(readData, 0, readData.Length);
                            // Write the decrypted data to resultStream.
                            resultStream.Write(readData, 0, readDataCount);
                        }
                        // Check whether there is any more encrypted data in stream.
                        while (readDataCount > 0);
                        // Return the decrypted data.
                        return resultStream.ToArray();
                    }
                }
            }
        }
    }
}



// This function is used for generating a valid key binary with UTF8 encoding and SHA256 hash algorithm.
byte[] GetKey(string key)
{
    // Create SHA256 hash algorithm class.
    using (SHA256Managed sha256 = new SHA256Managed())

    // Decode the string key to binary and compute the hash binary of the key.
    return sha256.ComputeHash(Encoding.UTF8.GetBytes(key));
}

サンプルコードのクラスの詳細については、次のリンクを参照してください。

AesCryptoServiceProvider Class

SHA256Managedクラス

CryptoStreamクラス

さらに、.NET Frameworkの暗号化について理解を深めるのに役立つ記事がいくつかあります。以下のリンクを参照してください。

暗号化サービス

。NET Framework暗号化モデル

暗号化の簡単なガイド

シークレットなしの暗号化

20

暗号化と認証の両方に同じキーを使用しないでください。暗号化と署名の両方に同じキーを使用しないでください。

キーを複数の目的で再利用しないでください。さまざまな微妙な攻撃が発生する可能性があります。

たとえば、RSA秘密/公開鍵のペアがある場合、暗号化(公開鍵で暗号化、秘密鍵で復号化)と署名(秘密鍵で署名、公開鍵で確認)の両方にそれを使用しないでください):単一の目的を選択し、その1つの目的にのみ使用します。両方の機能が必要な場合は、署名用と暗号化/復号化用の2つのキーペアを生成します。

同様に、対称暗号化では、暗号化に1つのキーを使用し、メッセージ認証に別の独立したキーを使用する必要があります。両方の目的で同じキーを再利用しないでください。

20
D.W.

Kerckhoffsの原則:暗号システムは、キーを除くシステムに関するすべてが公開されている場合でも安全である必要があります

間違った例:LANMANハッシュ

LANMANのハッシュは、誰もそのアルゴリズムを知らなければ理解するのが困難ですが、アルゴリズムが判明すると、解読するのは非常に簡単になります。

アルゴリズムは次のとおりです( wikipediaから ):

  1. ユーザーのASCIIパスワードは大文字に変換されます.
  2. このパスワードは14バイトになるようにヌルが埋め込まれます
  3. 「固定長」パスワードは2つの7バイトの半分に分割されます。
  4. これらの値は、2つのDES=キーを作成するために使用され、各7バイトのハーフから1つ
  5. 2つの鍵はそれぞれ、定数ASCII string“ KGS!@#$%”をDES暗号化するために使用され、2つの8バイトの暗号文の値になります。
  6. これら2つの暗号文の値は連結されて16バイトの値を形成します。これはLMハッシュです

これらのファクトの暗号文がわかったので、非常に簡単に暗号文を大文字である2つの暗号文に分割できます。これにより、パスワードの文字セットが制限される可能性があります。

正しい例:AES暗号化

  • 既知のアルゴリズム
  • テクノロジーに合わせて拡張できます。より多くの暗号化が必要な場合は、鍵のサイズを大きくします
17
Chris Dale

暗号化キーとしてパスワードを使用しないようにしてください。

多くのシステムの共通の弱点は、パスワードまたはパスフレーズ、またはパスワードまたはパスフレーズのハッシュを暗号化/復号化キーとして使用することです。問題は、これがオフラインのキーサーチ攻撃の影響を非常に受けやすいことです。ほとんどのユーザーは、そのような攻撃に対抗するのに十分なエントロピーを持っていないパスワードを選択します。

最良の修正は、パスワード/パスフレーズから決定論的に生成されたものではなく、真にランダムな暗号化/復号化キーを使用することです。

ただし、パスワード/パスフレーズに基づくものを使用する必要がある場合は、適切なスキームを使用して、徹底的なキー検索を遅くしてください。私はお勧めします PBKDF2 、これは反復ハッシュを使用します(H(H(H(....H(password)...))))辞書検索の速度を落とすために十分な数の反復を使用して、このプロセスがユーザーのマシンでキーを生成するのに、たとえば100ミリ秒かかるようにします。

13
D.W.

暗号化プロトコルでは:すべての認証済みメッセージを認識可能にする:2つのメッセージが同じに見えるべきではありません

一般化/バリアント:

  • ハッシュする前に、複数の文字列を連結するときは注意してください。
  • キーを再利用しないでください。
  • Nonceを再利用しないでください。

暗号化プロトコルの実行中に、シークレット(キーまたはノンス)なしでは偽造できない多くのメッセージを交換できます。これらのメッセージは、彼が公開(署名)鍵を知っているため、または彼と送信者だけが対称鍵またはノンスを知っているため、受信者によって検証できます。これにより、これらのメッセージが変更されていないことが確認されます。

しかし、これはではありませんこれらのメッセージがプロトコルの同じ実行中に発行されていることを確認してください:敵対者が以前に、またはプロトコルの同時実行。攻撃者は、暗号プロトコルの同時実行を多数開始して、有効なメッセージをキャプチャし、変更せずに再利用する可能性があります。

メッセージを巧みに再生することにより、RNGや暗号などを攻撃することなく、主キーを危険にさらすことなくプロトコルを攻撃できる可能性があります。

プロトコルのすべての認証済みメッセージを受信者にとって明確に区別することにより、変更されていないメッセージを再生する機会が減少します(排除されません)。

13
curiousguy

安全でないキーの長さを使用しないでください。

十分に長いキーのアルゴリズムを使用していることを確認してください。

対称キー暗号化では、少なくとも80ビットのキーをお勧めします。可能であれば、128ビットのキーをお勧めします。 40ビットの暗号を使用しないでください。それは、すべての可能なキーを徹底的に試すだけで、アマチュアによって安全でなく簡単に破られます。 56ビットDESを使用しないでください。破壊することは簡単ではありませんが、DESを破壊することは、熱心な攻撃者の手の届くところにあります。 AESのような128ビットのアルゴリズムは、40ビットの暗号よりもかなり遅くなることはないため、Crummy Cryptoを使用するための言い訳はありません。

公開鍵暗号方式の場合、鍵の長さに関する推奨事項は、アルゴリズムと必要なセキュリティのレベルによって異なります。また、キーのサイズを大きくするとパフォーマンスが低下するため、大量のオーバーキルは経済的ではありません。したがって、これは対称鍵の鍵サイズの選択よりももう少し考える必要があります。 RSA、El Gamal、またはDiffie-Hellmanの場合、キーは絶対最小値として少なくとも1024ビットにすることをお勧めします。ただし、1024ビットのキーは近いうちにクラック可能になる可能性のあるものの端にあり、一般的に現代の使用には推奨されないため、できれば1536ビットまたは2048ビットのキーを推奨します。楕円曲線暗号では、160ビットのキーで十分であり、224ビットのキーの方が適しています。 対称鍵と公開鍵の鍵サイズの大まかな同等性 を確立する公開されたガイドラインを参照することもできます。

8
D.W.

両方向で同じキーを使用しないでください。

ネットワーク通信でよくある間違いは、A-> B方向の通信にB-> A方向と同じキーを使用することです。これは、AからBに送信された何かをAに戻すリプレイ攻撃を可能にすることが多いため、悪い考えです。

最も安全な方法は、各方向に1つずつ、2つの独立したキーをネゴシエートすることです。または、単一のキーKをネゴシエートし、一方の方向にK1 = AES(K、00..0)を使用し、もう一方の方向にK2 = AES(K、11..1)を使用できます。

8
D.W.

アルゴリズムによってキーが引き伸ばされる場合、ワンタイムパッドはワンタイムパッドではありません

識別子「ワンタイムパッド」(Vernam暗号とも呼ばれます)は、破壊できないセキュリティを主張する目的で、さまざまな暗号化ソリューションに誤って適用されることがよくあります。しかし、定義により、バーナム暗号は、次の3つの条件がすべて満たされた場合にのみ安全です。

  • 重要な資料は本当に予測不可能です。そして
  • キーマテリアルは平文と同じ長さです。そして
  • キーマテリアルは決して再利用されません。

これらの条件に違反すると、それはワンタイムパッド暗号ではなくなります。

よくある間違いは、短いキーがアルゴリズムで引き伸ばされることです。このアクションは、予測不能性ルールに違反します(キーの長さのルールを気にしないでください)。これが完了すると、ワンタイムパッドは数学的にキーストレッチアルゴリズムに変換されます。短いキーとランダムなバイトを組み合わせると、キーストレッチアルゴリズムを総当たりするために必要な検索スペースのみが変更されます。同様に、「ランダムに生成された」バイトを使用すると、乱数ジェネレータアルゴリズムがセキュリティアルゴリズムに変わります。

これは簡単な例です。暗号的に安全な機能をキージェネレーターとして使用する「ワンタイムパッド」を使用して暗号化するというメッセージがあります。私は秘密鍵を選び、それが再利用されないように乱数を追加しました。私はキーを再利用していないので、あるメッセージから別のメッセージを差し引いて暗号文を攻撃する方法はありません。

          plaintext : 1234567890123456789012345678901234567890
       key material : 757578fbf23ffa4d748e0800dd7c424a46feb0cc
OTP function (xor)  : ----------
         ciphertext : 67412E83622DCE1B0C1E1A348B04D25872A8C85C

鍵素材は、SHA-1を使用して安全に生成され、秘密のパスワード(およびランダム)をハッシュして、伸ばしました。しかし、使用されているストレッチングアルゴリズム*がSHA-1であることを知っている攻撃者は、SHA-1へのさまざまな入力を試行し、出力を暗号文でXORすることで攻撃できます。 「OTP」キーを推測することは、暗号化アルゴリズムへの結合された入力を推測することよりも難しくありません。この特性は、選択された基本暗号アルゴリズム、それが保持する複雑さの尺度、または実装またはシードの方法に関係なく当てはまります。

あなたは非常に良いキーストレッチアルゴリズムを持っているかもしれません。非常に安全な乱数ジェネレーターを使用することもできます。ただし、アルゴリズムは本質的にワンタイムパッドではないため、ワンタイムパッドの壊れないプロパティはありません。

*ケルコフの原則を適用するということは、攻撃者が常に使用されるアルゴリズムを決定できると想定する必要があることを意味します。

3
John Deters

正しいモードを使用してください

同様に、ライブラリのデフォルト設定に依存してセキュリティを保護しないでください。具体的には、AESを実装する多くのライブラリは、FIPS 197で説明されているアルゴリズムを実装します。これは、いわゆるECB(電子コードブック)モードと呼ばれます。

AES(plaintext [32]byte, key [32]byte) -> ciphertext [32]byte

非常に安全ではありません。推論は簡単ですが、キースペース内の可能なキーの数は非常に多いですが、ここでの弱いリンクはメッセージのエントロピーの量です。いつものように、xkcd.comは私よりも優れていると記述しています http://xkcd.com/257/

基本的に暗号文[i]をマッピングにするCBC(暗号ブロック連鎖)のようなものを使用することは非常に重要です:

ciphertext[i] = SomeFunction(ciphertext[i-1], message[i], key)

この種の間違いが起こりやすいいくつかの言語ライブラリを指摘するだけです。 http://golang.org/pkg/crypto/aes/ は、単純に使用すると、結果はECBモードになります。

新しいAESオブジェクトを作成するとき、pycryptoライブラリはデフォルトでECBモードになります。

OpenSSLはこれを正しく行います。すべてのAES呼び出しは、動作モードについて明示的です。 IMOが本当に安全なのは、このような低レベルの暗号化を自分で行わないようにすることです。強制されている場合は、割れたガラスの上を(注意深く)歩いているかのように進み、ユーザーが自分のデータを保護するために信頼していることを正当化するようにしてください。

3
Shane Hansen

多くのデバイスで同じキーを再利用しないでください。

暗号化キーを広く共有するほど、それを秘密にしておくことができなくなります。一部の導入済みシステムでは、システム上のすべてのデバイスで同じ対称鍵が再利用されています。これの問題は、遅かれ早かれ、誰かが単一のデバイスからキーを抽出し、他のすべてのデバイスを攻撃できるようになることです。だから、それをしないでください。

このブログ記事 の「対称暗号化#6:多くのデバイス間で単一のキーを共有しない」も参照してください。マシュー・グリーンの功績。

3
D.W.

ディスク暗号化ではOTPまたはストリーム暗号を使用しないでください

例1

2つのファイルがストリーム暗号/ OTPを使用して保存されているとします。マイナーな編集後にファイルを再保存すると、攻撃者は特定のビットのみが変更されたことを確認し、ドキュメントに関する情報を推測できます。 (あいさつ文「De​​ar Bob」を「Dear Alice」に変更することを想像してください)。

例2

出力に整合性はありません。攻撃者は、データをXORするだけで暗号文を変更し、データの内容を変更できます。

削除:暗号文への変更は検出されず、平文に予測可能な影響があります。

ソリューション

メッセージの整合性チェックを含むこれらの状況では、ブロック暗号を使用します

1

基準を信頼しないでください。

暗号化には多くの標準が存在し、場合によってはそれらを使用する必要があります。しかし、標準を作成している人々が必要な暗号を十分に理解しているとは限りません。たとえば、EAXはネットワーク標準で作り直されました。 EAXにはセキュリティの証拠があります。再加工されたバージョンはしませんでした。

MD5が標準です。それは今壊れています。チップとPINは、数多くの危険な機能のおかげで、何度も何度も壊れています。GPGは、短すぎて快適ではないDSAキーをサポートしています。SSLには、使用すべきでないオプションがあり、必要ですそれらを避けるように注意してください。

これについて何ができますか?注意深く、既知のリスクを理解し、新しいリスクの研究についていく。

1
Watson Ladd

メッセージ拡張攻撃に対して脆弱でないMACのみを使用

MACは、特定のプレーンテキストのメッセージの整合性(変更などなし)を保証するハッシュコードです。多くの実装と公開されている標準では、MACに追加のデータを追加する攻撃者からMACを保護できません。

これに対する解決策は、MAC実装が2番目の(異なる)キーを使用し、最終出力を再暗号化することです。

ECBCとNMACは、メッセージ拡張攻撃を正しく防ぐ暗号の例です。

解決:

  • _raw CBC_の代わりにEncrypted CBC (ECBC)を使用します
  • NMACの代わりにcascadeを使用します
0

ワンタイムパッド(OTP)またはストリーム暗号キーを2回以上使用しないでください

OTPを2回適用すると、「完全な秘密」で暗号化されたデータが復号化され、平文になります。これは、データが2回XORされたために発生します。

同じキーを持つOTPまたはストリームが再利用されていると想定します。

攻撃者はクライアントからサーバーに送信された大量のデータを収集し、2つのパケットが互いに(またはそのサブセット)を復号化するまで、2つのパケットのセットをXORします。

ASCIIエンコーディングには十分な冗長性があります。つまり、十分な暗号文が与えられると、元のメッセージを(秘密のOTPキーとともに)デコードできます。

実世界の例

  • ロシア人が使用し、その後米国の諜報機関が解読したOTPの例については、プロジェクトヴェローナ(1941-46)

  • MicrosoftのPPTPv1では、クライアントとサーバーの両方が同じキーを使用してデータを暗号化します。

  • WEPは、2 ^ 24パケットが送信されるか、NICカードがリセットされると、同じキーを再利用します。最初の問題は、IVが24ビット長であるため、1600万フレーム後に2つ目のタイムパッドが送信されます。2番目の問題は、電源サイクル後にIVがゼロにリセットされ、2つのタイムパッドが発生するハードウェア実装で発生します。IVはクリアテキストで送信されるため、この問題は簡単に確認できます。

推奨

  • セッションごとに新しいキーを作成する必要があります(TLSなど)。

  • クライアントはサーバーで1つのOTP(またはPRG付きストリーム暗号)を使用する必要があり、サーバーはクライアントへのデータを暗号化するときに別のキーを使用する必要があります

  • 多くの多くのキーを生成するのではなく、PRGを使用して単一のキーを長いストリームに拡張し(PRGを信頼していると想定)、その拡張の各セグメントをキーとして使用することが可能です。

  • すべてのPRGがインクリメントモードで動作するように作成されているわけではなく、ランダムな入力が必要になる場合があることを理解してください。 (RC4には、インクリメントモードでこの問題があります)

0

RC4を使用しない

RC4は、ストリーム暗号として使用するために1987年に設計されました。 HTTPSとWEPで使用されます。

弱点があります

  1. 初期出力にバイアスがあります:Pr [2番目のバイト= 0] = 2/256
  2. ゼロに等しい16ビットの確率は1/256 ^ 2 + 1/256 ^ 3です。これは、数ギグのデータが暗号化された後に発生します。
  3. IVのみが変更され、キーは同じままである、関連するキー攻撃に対して脆弱です。

テイクアウェイRC4を使用する必要がある場合は、最初の256バイトがバイアスされているため、無視してください。データのギグにRC4を使用する場合、RC4のバイアスにより、以前に暗号化されたすべてのデータの攻撃が可能になります。

0

ハードウェアまたはソフトウェアで適切に動作する最新のストリームプロセッサを使用します

すべてのストリーム暗号がハードウェアまたはソフトウェアで実装されるように設計されているわけではありません。 線形フィードバックシフトレジスタ(LFSR) は、簡単に破られる、広く展開されているハードウェア暗号の例です。

LFSRは以下で使用されます。

  • DVD暗号化(CSSとも呼ばれます)2 LFSR
  • GSM暗号化(A5/1.2)3 LSFR
  • Bluetooth(E0):4 LFSR

上記のハードウェアは広く導入されているため、更新したり、最新の標準に準拠したりすることは困難です。上記のすべてはひどく壊れており、安全な通信のために信頼されるべきではありません。

攻撃:

暗号化中にキーは2つのセクション(17ビットと25ビット)に分割され、それらのビットは同じ暗号テキストの暗号化に使用されるため、MPEG形式の知識を使用し、17ビットキーをブルートフォースして25ビットキーを推定することができます。です。

これはほとんど新しいことではありませんが、この問題を示すFOSSは簡単に見つかります。

ソリューション:

eStreamプロジェクト (2008年)は、使用する必要がある5つのストリーム暗号を認定しました。顕著な違いは、IVでキーを使用する代わりに、暗号はキー、ノンス、およびカウンターを使用することです。 Salsa20はこのように動作し、ハードウェアとソフトウェアの両方で簡単に使用できるように設計されています。具体的には、x86 SSE2命令セットに含まれています。

さておき

最新の暗号はより安全であるだけでなく、より高速です。

PRG          Speed (MB/sec)
RC4              126         (obsolete)
Salsa20/12       643         (modern)
Sosemaunk        727         (modern)
0