编写一个使用RC4流密码的C++iostream.如何优化我的实施

Writing a C++ iostream that uses the RC4 stream cipher. How can I optimize my implementation?

本文关键字:何优化 C++iostream 优化 我的 一个 RC4 密码      更新时间:2023-10-16

我正在实现一个自定义iostream(即读、写、寻道和关闭),它使用RC4流密码进行加密和解密。这个流的一个约定是它是双向的,调用代码需要能够在进行任何实际读取或写入之前任意查找流中的任何位置。

现在,由于RC4使用了一个密钥,该密钥依赖于所有先前的掉期操作,直到给定的"告知"位置,我如何才能结合任意寻找任何位置的能力?

显然,在进行实际的异或转换过程之前,我可以搜索到给定搜索偏移的位置(在下面的例子中用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;
}    

EDIT:流应该不知道转换函数是如何工作的。转换函数是完全独立的,我应该能够在不同的转换实现中自由交换。

编辑:功能转换如下:

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循环。

谢谢,

Ben

将所有% 255更改为& 0xff,速度更快:

i = (i + 1) % 256;

收件人:

i = (i + 1) & 0xFF;

编辑:

您在初始化sbox时浪费了很多时间。您应该将sbox作为参数传递给transform函数,以便在调用之间更新原始副本。您现在所做的是一次又一次地初始化它,每次都需要更长的时间才能使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;
}    

经过一些研究,发现随机访问RC4的密钥流是不可能的。参见这个链接的讨论:crypto.stackeexchange。一个更好的选择(正如Rossum在他的评论中指出的)是在计数器模式下使用分组密码。

您在计数器模式下所做的是加密一系列数字。这个序列是递增的,是整个数据流的长度。因此,假设您希望使用64位(8字节)分组密码加密从原始数据流的位置"16"开始的8字节数据。

8个字节需要加密,因为您一次操作超过8个字节的纯文本。由于我们想要随机偏移到的位置是16,所以我们本质上加密这个数字序列的"块3"(字节0到7==块1,字节8到15==块2,字节16到23==块3等等…)

例如,使用XTEA算法,该算法使用128位密钥加密8字节的块,我们可以做如下操作:

区块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分组密码上使用了计数器模式。

Ben