如何在 Crypto++ 中进行异或运算?

How can I do XOR operation in Crypto++?

我想在使用新密钥在 AES(如 DESX)加密之前和之后在 AES 中执行异或运算。但是异或操作太费时间了。

如何减少异或运算时间?

这是我的代码:

string XOR(string value, string key)
{
    string retval(value);

    short unsigned int klen=key.length();
    short unsigned int vlen=value.length();
    short unsigned int k=0;
    short unsigned int v=0;

    for(v;v<vlen;v++)
    {
        retval[v]=value[v]^key[k];
        k=(++k<klen?k:0);
    }

    return retval;
}

int main(int argc, char* argv[])
{
    AutoSeededRandomPool prng;

    byte key1[AES::DEFAULT_KEYLENGTH];
    prng.GenerateBlock(key1, sizeof(key1));

    byte key[AES::DEFAULT_KEYLENGTH];
    prng.GenerateBlock(key, sizeof(key));

    byte key2[AES::DEFAULT_KEYLENGTH];
    prng.GenerateBlock(key2, sizeof(key2));

    byte iv[AES::BLOCKSIZE];
    prng.GenerateBlock(iv, sizeof(iv));

    string plain = "AESX CBC Mode Test";
    string cipher,encoded, encodediv, encodedkey1, encodedkey, 
    encodedkey2, recovered, prerecovered, postrecovered, 
    prewhiten, postwhiten;

    // Pretty print key1
    StringSource(key1, sizeof(key1), true,
        new HexEncoder(
            new StringSink(encodedkey1)
        ) // HexEncoder
    ); // StringSource
    cout << "key1: " << encodedkey1 << endl;

    // Pretty print iv
    StringSource(iv, sizeof(iv), true,
        new HexEncoder(
            new StringSink(encodediv)
        ) // HexEncoder
    ); // StringSource
    cout << "iv: " << encodediv << endl;

    // Pretty print key
    StringSource(key, sizeof(key), true,
        new HexEncoder(
            new StringSink(encodedkey)
        ) // HexEncoder
    ); // StringSource
    cout << "key: " << encodedkey << endl;

    // Pretty print key2
    StringSource(key2, sizeof(key2), true,
        new HexEncoder(
            new StringSink(encodedkey2)
        ) // HexEncoder
    ); // StringSource
    cout << "key2: " << encodedkey2 << endl;

    cout << "plain text: " << plain << endl;

    prewhiten = XOR(plain, encodedkey1);

    try
    {
        cout << "pre whiten text: " << prewhiten << endl;

        CBC_Mode< AES >::Encryption e;
        e.SetKeyWithIV(key, sizeof(key), iv);

        // The StreamTransformationFilter removes
        //  padding as required.
        StringSource s(prewhiten, true, 
            new StreamTransformationFilter(e,
                new StringSink(cipher)
            ) // StreamTransformationFilter
        ); // StringSource

    }
    catch(const CryptoPP::Exception& e)
    {
        cerr << e.what() << endl;
        exit(1);
    }

    /*********************************\
    \*********************************/

    // Pretty print
    encoded.clear();
    StringSource(cipher, true,
        new HexEncoder(
            new StringSink(encoded)
        ) // HexEncoder
    ); // StringSource
    cout << "cipher text: " << encoded << endl;

    postwhiten = XOR(encoded, encodedkey2);

    cout << "post whiten text: " << postwhiten << endl;

    //decryption

    prerecovered = XOR(postwhiten, encodedkey2);

    encoded.clear();
    StringSource(prerecovered, true,
        new HexEncoder(
            new StringSink(encoded)
        ) // HexEncoder
    ); // StringSource

    cout << "pre recovered text: " << encoded << endl;

    try
    {
        CBC_Mode< AES >::Decryption d;
        d.SetKeyWithIV(key, sizeof(key), iv);

        // The StreamTransformationFilter removes
        //  padding as required.
        StringSource s(prerecovered, true, 
            new HexDecoder(
                new StreamTransformationFilter(d,
                    new StringSink(recovered)
                ) // StreamTransformationFilter
            )//HexDecoder
        ); // StringSource

        cout << "recovered text: " << recovered << endl;
    }
    catch(const CryptoPP::Exception& e)
    {
        cerr << e.what() << endl;
        exit(1);
    }

    postrecovered = XOR(recovered, encodedkey1);

    cout << "post recovered text: " << postrecovered << endl;

    return 0;
}

如有任何帮助,我们将不胜感激。

How can I do XOR operation in Crypto++?

有两种方法可以使用该库执行 XOR。首先,misc.h中有两个函数xorbuf。第一个实现如下所示,它使用带有掩码的单个 in/out 缓冲区:

void xorbuf(byte *buf, const byte *mask, size_t count)
{
    size_t i=0;
    if (IsAligned<word32>(buf) && IsAligned<word32>(mask))
    {
        if (!CRYPTOPP_BOOL_SLOW_WORD64 && IsAligned<word64>(buf) && IsAligned<word64>(mask))
        {
            for (i=0; i<count/8; i++)
                ((word64*)(void*)buf)[i] ^= ((word64*)(void*)mask)[i];
            count -= 8*i;
            if (!count)
                return;
            buf += 8*i;
            mask += 8*i;
        }

        for (i=0; i<count/4; i++)
            ((word32*)(void*)buf)[i] ^= ((word32*)(void*)mask)[i];
        count -= 4*i;
        if (!count)
            return;
        buf += 4*i;
        mask += 4*i;
    }

    for (i=0; i<count; i++)
        buf[i] ^= mask[i];
}

还有一个 xorbuf(byte *output, const byte *input, const byte *mask, size_t count) 使用带有掩码的单独输入和输出缓冲区。

异或的第二种方法是使用来自 filters.h. Internally, ArrayXorSink calls xorbuf for you. You would use this is you prefer pipelinesArrayXorSink

size_t ArrayXorSink::Put2(const byte *begin, size_t length, int messageEnd, bool blocking)
{
    // Avoid passing NULL pointer to xorbuf
    size_t copied = 0;
    if (m_buf && begin)
    {
        copied = STDMIN(length, SaturatingSubtract(m_size, m_total));
        xorbuf(m_buf+m_total, begin, copied);
    }
    m_total += copied;
    return length - copied;
}

string XOR(string value, string key)
{
    string retval(value);

    short unsigned int klen=key.length();
    short unsigned int vlen=value.length();
    short unsigned int k=0;
    short unsigned int v=0;

    for(v;v<vlen;v++)
    {
        retval[v]=value[v]^key[k];
        k=(++k<klen?k:0);
    }

    return retval;
}

为此,您可以执行以下操作。它要求编译器 inline 函数,并通过常量引用传递 valuekey 以避免复制。

inline string XOR(const string& value, const string& key)
{
    ASSERT(key.length() == value.length());

    string retval(value);
    xorbuf(&retval[0], &key[0], retval.length());
    return retval; 
}

诀窍是,您必须使用元素 0 的地址来获取非常量指针并避免潜在的未定义行为。您可能需要转换为 byte*.


How can I reduce the XOR operation time?

您可能希望在可行时使用大于 1 字节的操作数大小。图书馆的 xorbuf 在可用时使用 word32word64

此外,如果您有 AVX,那么您最多可以对 512 位的缓冲区进行操作。如果您保持缓冲区对齐,那么 GCC 将尝试在 -O3 及以上使用更大的缓冲区。 -O3 很重要,因为那时 GCC 开始积极矢量化并使用 AVX 和 AVX2 提供的功能。

Crypto++ 库在几年前经历了一次不小的痛苦,因为它的缓冲区没有按照 GCC 的预期对齐,并且它导致了 SEGFAULT -O3 及以上。参见,例如,Crash on Cygwin i386 with -O3.

对齐问题不仅限于Cygwin; Cygwin 碰巧演示了它。该问题有时会在其他平台和 CPU 下出现,例如启用 NEON 时的 ARM。我们相信所有问题都已解决。