1

私は現在、AES暗号化を必要とするファイルシステムの目的でいくつかのカーネル開発を経験しており、次の制約に遭遇します。

  • 任意の長さの平文を暗号化できなければなりません
  • パディング(ある場合)は目立たない
  • バイトのパディングの結果として生じる可能性のあるオーバーヘッドは許容できません

紙の上では、これを解決する簡単な方法があります:CTR暗号化モードを使用してください!

その素晴らしいアイデア(うーん...)で、私はLinuxカーネルの暗号化APIソースに飛び込んで、始める方法を学びます。

この時点で、暗号化関数にはその他の関数の使用が含まれていることに気付きました。

  • crypt_inplace関数。その目的は、ユーザーが暗号文を指定された平文と同じメモリ領域に格納したい場合を処理することです。( crypt_segmentと同じですが、メモリの制約があります)
  • crypt_segment関数。標準の暗号化機能です。データのブロック全体(つまり、AESの場合は16バイト)を暗号化します。
  • crypt_final関数。指定されたプレーンテキストの長さLが、基になるブロック暗号ブロックサイズの倍数でない場合、この関数は残りのバイトに対して暗号化を実行します。

したがって、Lバイト長のプレーンテキストとAESを使用すると、最初のL / 16ブロックは、要求された内容に応じてcrypt_segmentまたはcrypt_inplaceを使用して処理されます。残りのLmod16バイトは、crypt_finalを使用して暗号化されます。

内部のcrypt_segment関数は次のように定義されています:( crypt_inplaceは非常に似ています)

static int crypto_ctr_crypt_segment(struct blkcipher_walk *walk,
                    struct crypto_cipher *tfm)
{
    void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
                   crypto_cipher_alg(tfm)->cia_encrypt;
    unsigned int bsize = crypto_cipher_blocksize(tfm);
    u8 *ctrblk = walk->iv;
    u8 *src = walk->src.virt.addr;
    u8 *dst = walk->dst.virt.addr;
    unsigned int nbytes = walk->nbytes;

    do {
        /* create keystream */
        fn(crypto_cipher_tfm(tfm), dst, ctrblk);
        crypto_xor(dst, src, bsize);

        /* increment counter in counterblock */
        crypto_inc(ctrblk, bsize);

        src += bsize;
        dst += bsize;
    } while ((nbytes -= bsize) >= bsize);

    return nbytes;
}

ご覧のとおり、カウンターはブロックサイズごとにインクリメントされます。ほとんどのユースケースでは問題にはなりませんが、次のシナリオを検討してください。

  1. 指定された場所pで要求を書き込みます(これは、たとえばハードドライブ上の(セクター、オフセット)特定の値である可能性があります):11バイト長のプレーンテキスト
  2. p + 3での8バイトの読み取り要求:ここでは、書き込まれた暗号文から最初の平文の最後の8バイトを取得します。

最初のステップは、暗号化シーケンスでcrypt_finalを1回呼び出すだけで実行されます。次に、11個の暗号化されたバイトが適切な場所に書き込まれます。しかし、「ブロック全体」の暗号化のために、このデータチャンクの最後の8バイトを取得する場合、解読操作を実行するには、 pp + 1、およびp+2に格納されている前の3バイトが必要です。

明らかに、ファイルシステムの観点では、読み取りが要求されたときに、ハードウェアに依存する仮定を行わない限り、カーネルがこの種のことを知る方法はありません。

したがって、ここに私の質問があります:バイトベースで常に(解読)操作を実行するようにCTRモードを設定する方法はありますか、それともこれを強制するためにCTRモードの独自の実装を作成する必要がありますか?(この構成操作を実行するためのエントリポイントがctrソースコードに見つかりませんでした。何かを見逃した可能性があります)

よろしくお願いします。大きな投稿であなたを驚かせていないことを願っています!

PS:この投稿のコードスニペットは、Linuxカーネルソースツリーのcryptoディレクトリの下にあるctr.cファイルにあります。表示されるバージョンは、3.8-rc3カーネルリリースのものです。


編集 :

実際、CTRモードは、任意の長さのデータを処理するように設計されています。ISO /IEC10116仕様にある説明を思い出します。

平文Pが等しい長さ(jビット)のチャンク(P i0<i<nに分割されていると仮定します。Kを暗号化用に提供されたキーとし、IVをカウンターの初期化ベクトルとします 。 暗号文Cは、平文Pのようにチャンク(C i0<i<nに分割されます。 CTRモードでは、処理された各チャンクをウォークするカウンターが導入されます。とはいえ、チャンクP i(またはC i )の暗号化(または解読)に使用されるカウンターブロックを呼び出します。


CTR i
最後に、CTR 1 = IV
とします。これらの表記法を使用すると、計算は次のようになります。

1からnまでのiの場合

  1. Y = AES_encrypt(CTR iK)<-Yは16バイト長です
  2. E = Truncate(Y、j)<- Yの左端のjビットのみを保持します
  3. C i = P i XOR E
  4. CTR i + 1 = ComputeNextCTR(CTR i)<-通常、 ComputeNextCTRは単純なインクリメントです。

終わり

LinuxカーネルにあるCTRバージョンでは、この動作は、jが基になるブロック暗号ブロックサイズ(AESでは128ビット)の値を取得することで強制されます。ただし、指定された平文が適切な長さでない場合に切り捨てが発生する最後のステップを除きます。 。

私の質問は:暗号化APIに必要なjパラメータを適用するように指示する方法はありますか?私には、答えは「いいえ」のように思われるので、この追加機能を取得するには、ホイールを「再発明」し、CTRモードの新しい実装を作成する必要があります。何か見落としているかもしれませんので、はっきりと述べてくださる方に感謝いたします。

ボーナス1:答えが「いいえ」の場合、Crypto APIのアルガピがどのように機能するかについての簡単な概要は非常に歓迎されます(私は現在これを掘り下げています)。

よろしくお願いします。

4

1 に答える 1

0

暗号ソースを掘り下げた後、私は言うことができます...いいえ、CTRモードの質問で紹介したjパラメーターを設定できません。

それにもかかわらず、この回答を関連させるために、内部暗号 API についていくつかの詳細を説明します。ここで公開されている詳細は、暗号化 API で新しいアルゴリズム/モードのサポートを追加するための内部低レベル API について説明しています。


暗号オブジェクト

まず、crypto API はさまざまなオブジェクトのコレクションを管理します。私がオブジェクトという言葉を使っているのは、それは C プログラミングですが、コードは明らかにオブジェクト指向のようなものだからです。3 つの主要なオブジェクトがあります。

  • アルゴリズム :struct crypto_alg
  • テンプレート:struct crypto_template
  • インスタンス :struct crypto_instanceおよびstruct crypto_spawn
  • Transforms :struct crypto_tfmと友達 ( struct crypto_blkcipher, ...)。

最初のカテゴリーは、この内なる獣のマイルストーンです。新しいアルゴリズムを作成したいときは、 を作成しstruct crypto_alg、適切なフィールドに入力して登録するだけです。
テンプレートは、特定のアルゴリズム構造に依存しているため、少し異なります。アルゴリズム オブジェクトは、実行時に必要なときに渡されます。したがって、テンプレートは、カスタム実行モードを作成するのに適したオブジェクトです (元の質問で暗示されているように)。
次に、インスタンスとスポーンは、この小さな世界が外部およびそれ自体とどのように相互作用するかを内部的に処理するためにここにあります。
最後に、変換構造は、外部インターフェイスに公開される「1 回限りの」特定の構造です (これらは、何かを暗号化/復号化する必要がある他のモジュールから使用されます)。


新しいテンプレートの作成

基本的に、手順はかなり単純で、ctr.c ファイルの下にあるような既存のテンプレートから開始できます。それにもかかわらず、いくつかの詳細を示します。


上記は crypto API によってどのように処理されますか

この部分では、内側の暗号部分がテンプレートまたはアルゴリズムの作成を処理する方法と、暗号機能をユーザーに提供する方法 (ユーザーによって、他のモジュールを理解する) について説明します。

注:この回答は作成中です。定期的に編集して追加情報を追加します。

于 2013-01-28T14:59:04.127 に答える