1

暗号化と復号化に RC4 ストリーム暗号を使用するカスタム iostream (つまり、読み取り、書き込み、シーク、およびクローズ) を実装しています。このストリームのコントラクトの 1 つは、双方向であり、呼び出し元のコードは、実際の読み取りまたは書き込みを行う前に、ストリーム内の任意の位置を任意にシークできる必要があるということです。

RC4 は、指定された「tell」位置までの以前のすべてのスワップ操作に依存するキーを使用するため、任意の位置を任意にシークする機能をどのように組み込むことができますか?

明らかに、実際の xor 変換プロセスを実行する前に、特定のシーク オフセット (次の例ではTHIS BITでマークされている) の位置までシークすることができます。たとえば、次のようになります。

/**
 * @brief called from a stream's read or write function
 * @param in the input buffer
 * @param out the output buffer
 * @param startPosition the current stream position (obtained via the streams
 * tellg or tellp functions for read and write respectively)
 * @param length the number of bytes to transform
 */
void transform(char *in, char *out,
               std::ios_base::streamoff startPosition,
               long length)
{

    // need to reset sbox from member s_box each time this
    // function is called
    long sbox[256];
    for (int i = 0; i<256; ++i) {
        sbox[i]=m_sbox[i];
    }

    // ***THIS BIT***
    // need to run the swap operation startPosition times
    // to get sbox integer sequence in order
    int i = 0, j = 0, k = 0;
    for (int a=0; a < startPosition; ++a) {
        i = (i + 1) % 256;
        j = (j + sbox[i]) % 256;
        swapints(sbox, i, j);
    }

    // now do the actual xoring process up to the length
    // of how many bytes are being read or written
    for (int a=0; a < length; ++a) {
        i = (i + 1) % 256;
        j = (j + sbox[i]) % 256;
        swapints(sbox, i, j);
        k = sbox[(sbox[i] + sbox[j]) % 256];
        out[a] = in[a] ^ k;
    }

}

次に、ストリーム実装の読み取りまたは書き込みから変換が呼び出されます。次のようになります。

MyStream&
MyStream::read(char * const buf, std::streamsize const n)
{
    std::ios_base::streamoff start = m_stream.tellg();
    std::vector<char> in;
    in.resize(n);
    (void)m_stream.read(&in.front(), n);
    m_byteTransformer->transform(&in.front(), buf, start, n);
    return *this;
}    

編集: ストリームには、変換関数がどのように機能するかについての知識がありません。変換機能は完全に独立しており、さまざまな変換の実装を自由に交換できるはずです。

編集: 関数 swapints は次のようになります。

void swapints(long *array, long ndx1, long ndx2)
{
    int temp = array[ndx1];
    array[ndx1] = array[ndx2];
    array[ndx2] = temp;
}

上記の変換関数の実際の問題は、xor 変換が適切に実行される前に startPosition 初期スワップ操作を実行する必要があるため、その遅さにあります。これは、多くのシーク操作が実行される場合に非常に問題になります。RC4 は高速であることを意図していると聞いたことがありますが、スワップ操作の初期セットを考えると、私の (おそらく悪い実装) は別の方法を提案しています。

だから私の本当の質問は、必要な操作の数を減らすために上記のコードを最適化するにはどうすればよいですか? 理想的には、スワップ操作の最初の (" THIS BIT ") セットを排除したいと考えています。

編集: 初期の sbox 設定を最適化することはおそらく些細なことです (たとえば、egur が提案するように memcpy を使用します)。私が考える重要な最適化は、THIS BITでマークされたループを最適化する方法です。おそらく、これらすべてのスワップ int は、for ループを必要とせずに、より簡潔にプログラムできます。

ありがとう、

ベン

4

2 に答える 2

0

いくつかの調査の結果、RC4 のキー ストリームへのランダム アクセスは不可能であることが判明しました。このリンクの議論を参照してください: crypto.stackexchange。より良い代替手段 (Rossum のコメントで指摘されているように) は、カウンター モードでブロック暗号を使用することです。

カウンター モードで行うことは、一連の数字を暗号化することです。このシーケンスはインクリメンタルで、データのストリーム全体の長さです。したがって、64 ビット (8 バイト) ブロック暗号を使用して、元のデータ ストリームの位置 '16' から始まる 8 バイトのデータを暗号化するとします。

一度に 8 バイト以上のプレーン テキストを操作するため、8 バイトを暗号化する必要があります。ランダムにオフセットしたい位置は 16 なので、基本的にこの数列の「ブロック 3」を暗号化します (バイト 0 から 7 == ブロック 1、バイト 8 から 15 == ブロック 2、バイト 16 から 23 == ブロック 3等々...)

たとえば、128 ビット キーを使用して 8 バイトのブロックを暗号化する XTEA アルゴリズムを使用すると、次のようになります。

ブロック 3:

// create a plain text number sequence 
uint8_t plainText[8];
plainText[0] = 16;
plainText[1] = 17;
.
.
.
plainText[7] = 23;

// encrypt the number sequence
uint8_t cipherText[8];
applyXTEATransformation(plainText, cipherText, keyOfLength128Bit);

// use the encrypted number sequence as a 
// key stream on the data to be encrypted
transformedData[16] = dataToBeEncrypted[16] ^ cipherText[0];
transformedData[17] = dataToBeEncrypted[17] ^ cipherText[1];
.
. 
.
transformedData[23] = dataToBeEncrypted[23] ^ cipherText[7];

tldr: RC4 でランダム アクセスを実行したかったのですが、それが不可能であることを発見したため、代わりに XTEA ブロック暗号でカウンター モードを使用しました。

ベン

于 2014-01-20T10:59:21.457 に答える
0

すべて% 255& 0xffに変更します。はるかに高速です。

i = (i + 1) % 256;

に:

i = (i + 1) & 0xFF;

編集:

初期化に多くの時間を浪費していますsboxsbox元のコピーが呼び出し間で更新されるように、パラメーターとして変換関数に渡す必要があります。あなたが今やっていることは、それを何度も何度も初期化することであり、startPosition が大きくなってから毎回時間がかかります。

void transform(char *in, char *out,
           long length,
           unsigned char* sbox)

一時的なものはクラスsboxのメンバーである必要があります。MyStream読み取り関数は次のようにする必要があります。

MyStream&
MyStream::read(char * const buf, std::streamsize const n)
{
    std::ios_base::streamoff start = m_stream.tellg();
    std::vector<char> in;
    in.resize(n);
    (void)m_stream.read(&in.front(), n);

    // init m_TempSbox on first call
    if (m_FirstCall) {
        initTempSbox();
    }

    m_byteTransformer->transform(&in.front(), buf, n, m_TempSbox);
    return *this;
}    
于 2014-01-14T11:52:37.760 に答える