Ответ 1
Вы должны иметь возможность быстро адаптировать источник метода 1 к методу 2. Функция изменения Sha1ProcessMessageBlock()
в методе 1. Инициализируйте w[0:15]
из сообщения, затем выполните цикл от 0 до 79, где вы делаете w[]
манипуляция после итерации 16, а расчет темпа зависит от значения t
(0-19 использует один, 20-39 использует другой и т.д.). Важно помнить, что используется index%16
или index & 0x0f
всякий раз, когда вы обращаетесь к массиву w[]
.
Быстрая модификация будет примерно такой (дважды проверьте все обращения к w
, чтобы убедиться, что я не пропустил t & 0x0f
):
void SHA1ProcessMessageBlock(SHA1Context *context)
{
const uint32_t K[] = { /* Constants defined in SHA-1 */
0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6
};
int t; /* Loop counter */
uint32_t temp; /* Temporary word value */
uint32_t W[16]; /* Word sequence */
uint32_t A, B, C, D, E; /* Word buffers */
/*
* Initialize the first 16 words in the array W. You can move this to your
* context.
*/
for(t = 0; t < 16; t++)
{
W[t] = context->Message_Block[t * 4] << 24;
W[t] |= context->Message_Block[t * 4 + 1] << 16;
W[t] |= context->Message_Block[t * 4 + 2] << 8;
W[t] |= context->Message_Block[t * 4 + 3];
}
A = context->Intermediate_Hash[0];
B = context->Intermediate_Hash[1];
C = context->Intermediate_Hash[2];
D = context->Intermediate_Hash[3];
E = context->Intermediate_Hash[4];
for(t = 0; t < 80; t++) {
if (t >= 16) {
W[t&0xf] = SHA1CircularShift(1,W[(t-3)&0xf] ^ W[(t-8)&0xf] ^ W[(t-14)&0xf] ^ W[t&0xf]);
}
if (t<20) {
temp = SHA1CircularShift(5,A) +
((B & C) | ((~B) & D)) + E + W[t&0xf] + K[0];
}
else if (t<40) {
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t&0xf] + K[1];
}
else if (t < 60) {
temp = SHA1CircularShift(5,A) +
((B & C) | (B & D) | (C & D)) + E + W[t&0xf] + K[2];
}
else {
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t&0xf] + K[3];
}
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
context->Intermediate_Hash[0] += A;
context->Intermediate_Hash[1] += B;
context->Intermediate_Hash[2] += C;
context->Intermediate_Hash[3] += D;
context->Intermediate_Hash[4] += E;
context->Message_Block_Index = 0;
}
По-прежнему сохраняются сбережения: избавиться от массива w[]
в стеке и поместить его в контекст, предварительно инициализированный данными, которые вы получаете.
Кроме того, перед вызовом этой функции вам нужно много предварительной обработки. Например, если все ваши сообщения составляют менее 55 байт, вы можете поместить их в массив W, добавить дополнение и обработать немедленно. Если нет, вам придется дважды вызвать процесс: сначала с частично заполненным вводом, и снова с остальной частью пэда и т.д. Подобная вещь будет очень специфичной для приложения, и я сомневаюсь, что вы сможете найти код, чтобы сделать это для вас.
Кстати, приведенный выше код является прямой адаптацией от источника 1-го типа из вашей ссылки. Вы можете, вероятно, сжать немного больше, если попытаетесь оптимизировать его дальше.
Я не мог придумать способ получения экономии на промежуточном хэше, так что для этого вам понадобится в общей сложности 108 байт (109, если счетчик также находится в ОЗУ), и 24 из которых являются локальными для этой функции, и их можно использовать повторно в других местах, если они также временны. Поэтому очень сложно делать то, что вы хотите сделать.
EDIT: если все ваши сообщения составляют менее 55 байт, вы можете сохранить еще 20 байт в своем контексте, избавившись от хранилища intermediate_hash[]
. Просто инициализируйте A-E из констант и добавьте константы в конец. Наконец, вместо сохранения их в отдельной переменной перезапишите свой вход, когда эта функция закончится.