4

の素朴な実装は次のmemcmp()ようになります(この回答から):

int memcmp_test(const char *cs_in, const char *ct_in, size_t n)
{
   size_t i;  
   const unsigned char * cs = (const unsigned char*) cs_in;
   const unsigned char * ct = (const unsigned char*) ct_in;

   for (i = 0; i < n; i++, cs++, ct++)
   {
       if (*cs < *ct)
       {
          return -1;
       }
       else if (*cs > *ct)
       {
          return 1;
       }
   }
   return 0;
}

ここでは、最初の不一致バイトが見つかると、ブロックのトラバーサルが停止します。これは、実行時間がブロックの内容に依存するようになり、タイミング攻撃が可能になるため、暗号化アプリケーションには適していません。したがって、OpenSSL はこれを使用します (ここから取得):

int CRYPTO_memcmp(const void *in_a, const void *in_b, size_t len)
{
    size_t i;
    const unsigned char *a = in_a;
    const unsigned char *b = in_b;
    unsigned char x = 0;

    for (i = 0; i < len; i++)
         x |= a[i] ^ b[i];

    return x;
}

break途中にs やsがないreturnため、このコードはブロック全体をトラバースする必要があります。少なくともこれは意図です。

次に、使用例を 1 つ示します (ここから):

 static int des_ede3_unwrap(EVP_CIPHER_CTX *ctx,
     unsigned char *out, const unsigned char *in, size_t inl)
 {
      unsigned char icv[8], iv[8], sha1tmp[SHA_DIGEST_LENGTH];
      //whatever, unrelated then...
      if (!CRYPTO_memcmp(sha1tmp, icv, 8))
         rv = inl - 16;
      //whatever, unrelated
 }

リンク時のコード生成 (Visual C++ LTCG) またはリンク時の最適化 (gcc LTO) を使用すると、コンパイラはCRYPTO_memcmp()実装と呼び出しサイトの両方を確認できます (それらが異なる翻訳単位にある場合でも)。呼び出しサイトは実際の値を使用せず、null と比較するだけであることがわかります。したがってCRYPTO_memcmp()、最初の不一致のバイト ペアを見つけたらすぐに戻るように自由に変換でき、「安全な」バージョンのmemcmp()は安全ではなくなります。

memcmp()標準準拠のコンパイラがタイミング攻撃を支援するバージョンに変換しないように実装するにはどうすればよいですか?

4

1 に答える 1