Реализация SHA1 с эффективным использованием памяти - PullRequest
13 голосов
/ 12 апреля 2011

Я работаю с очень ограниченным встроенным процессором, который имеет только 128 байтов оперативной памяти. Я хотел бы реализовать SHA1 на нем. RFC3174 описывает в «методе 2» способ реализации SHA1, который не требует выделения массива из 80 32-битных слов (что при 320 байтах, очевидно, не практично) и выглядит как это должно быть применимо на моем процессоре. Однако я не могу найти никаких реализаций «метода 2», а пример кода в RFC реализует только метод по умолчанию.

Кто-нибудь знает о реализации SHA1 с эффективным использованием памяти в C или C ++?

Ответы [ 4 ]

10 голосов
/ 12 апреля 2011

Вы должны быть в состоянии быстро адаптировать источник метода 1 к методу 2. Изменяемая функция - Sha1ProcessMessageBlock() в методе 1. Инициализируйте w[0:15] из сообщения, затем выполните цикл от 0 до 79, где вы только делаете w[] манипуляция после итерации 16, и вычисление температуры зависит от значения t s (0-19 используют одно, 20-39 используют другое и т. Д.). Важно помнить, что всякий раз, когда вы обращаетесь к массиву w[], используйте index%16 или index & 0x0f.

Быстрая модификация будет выглядеть примерно так (дважды проверьте все обращения к 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, добавить заполнение и сразу же обработать. Если нет, вам придется вызывать process дважды: сначала с частично заполненным вводом, а затем с остальной частью пэда и т. Д. Подобные вещи будут зависеть от конкретного приложения, и я сомневаюсь, что вы сможете найти код, чтобы сделать это для вас.

Кстати, приведенный выше код является прямой адаптацией из источника типа 1 по вашей ссылке. Вероятно, вы можете выжать из него немного больше, если попытаетесь оптимизировать его дальше.

Я не мог придумать, как сэкономить промежуточный хеш, поэтому для этого вам понадобится всего 108 байт (109, если счетчик также находится в ОЗУ), и 24 из которых являются локальными для этой функции. и может быть повторно использован в других местах - при условии, что они также являются временными. Поэтому очень сложно делать то, что ты хочешь делать.


РЕДАКТИРОВАТЬ: Если все ваши сообщения меньше 55 байт, вы можете сохранить еще 20 байт в своем контексте, избавившись от хранилища intermediate_hash[]. Просто инициализируйте A-E из констант и добавьте константы в конце. Наконец, вместо того, чтобы хранить их в отдельной переменной, перезапишите ввод, когда эта функция завершится.

3 голосов
/ 12 апреля 2011

Я реализовал SHA-1 для нескольких ограниченных по памяти сред.Вы можете обойтись с

DWORD W[16] ;        // instead of H[80]
DWORD H[5] ;         // Intermediate hash value
DWORD BitCount[2] ;  // Probably a single DWORD is enough here

плюс несколько байтов служебной работы.W обновляется на лету как круговой буфер, а не генерируется в начале каждого раунда.

2 голосов
/ 17 декабря 2011

рабочий пример:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string>

using namespace std;

unsigned CircularShift(int bits, unsigned word)
{
    return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32-bits));
}

int main(void)
{
    string mess;
    cin >> mess;
    unsigned int lm = mess.length();
    unsigned int lmb = lm*8;
    unsigned char *messc;
    messc=(unsigned char*)malloc((sizeof(unsigned char))*64);

    for (unsigned short int i =0;i<64;i++)
    {
        messc[i]=char(0x00);
    }
    for(int i=0;i<mess.length();i++)
    {
        messc[i]=mess[i];
    }
    messc[lm]=(unsigned char)128;
    messc[56] = (lmb >> 24) & 0xFF;
    messc[57] = (lmb >> 16) & 0xFF;
    messc[58] = (lmb >> 8) & 0xFF;
    // messc[59] = (lmb) & 0xFF;
    messc[60] = (lmb >> 24) & 0xFF;
    messc[61] = (lmb >> 16) & 0xFF;
    messc[62] = (lmb >> 8) & 0xFF;
    messc[63] = (lmb) & 0xFF;
    for(int i =0 ;i<64;i++)
    {
        cout<< hex << (int)messc[i] << " ";
    }
    unsigned *H;
    H=(unsigned*)malloc(5*sizeof(unsigned));
    H[0]        = 0x67452301;
    H[1]        = 0xEFCDAB89;
    H[2]        = 0x98BADCFE;
    H[3]        = 0x10325476;
    H[4]        = 0xC3D2E1F0;
    const unsigned K[]={0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6};
    int         t;
    unsigned    temp;
    unsigned    *W;
    unsigned    A, B, C, D, E;
    W=(unsigned*)malloc(80*sizeof(unsigned));
    unsigned char *messh;
    messh=(unsigned char*)malloc(64*sizeof(unsigned char));
    int k;
    for(t = 0; t < 16; t++)
    {
        W[t] = ((unsigned) messc[t * 4])<< 24; ;
        W[t] |= ((unsigned) messc[t * 4 + 1])<< 16;
        W[t] |= ((unsigned) messc[t * 4 + 2]) << 8;
        W[t] |= ((unsigned) messc[t * 4 + 3]);
    }
    for(t = 16; t < 80; t++)
    {
        W[t] = CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
    }

    A = H[0];
    B = H[1];
    C = H[2];
    D = H[3];
    E = H[4];

    for(t = 0; t < 20; t++)
    {
        temp = CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
        temp &= 0xFFFFFFFF;
        E = D;
        D = C;
        C = CircularShift(30,B);
        B = A;
        A = temp;
    }

    for(t = 20; t < 40; t++)
    {
        temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
        temp &= 0xFFFFFFFF;
        E = D;
        D = C;
        C = CircularShift(30,B);
        B = A;
        A = temp;
    }

    for(t = 40; t < 60; t++)
    {
        temp = CircularShift(5,A) +
                ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
        temp &= 0xFFFFFFFF;
        E = D;
        D = C;
        C = CircularShift(30,B);
        B = A;
        A = temp;
    }

    for(t = 60; t < 80; t++)
    {
        temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
        temp &= 0xFFFFFFFF;
        E = D;
        D = C;
        C = CircularShift(30,B);
        B = A;
        A = temp;
    }

    H[0] = (H[0] + A) & 0xFFFFFFFF;
    H[1] = (H[1] + B) & 0xFFFFFFFF;
    H[2] = (H[2] + C) & 0xFFFFFFFF;
    H[3] = (H[3] + D) & 0xFFFFFFFF;
    H[4] = (H[4] + E) & 0xFFFFFFFF;

    cout <<"\nTHIS IS SHHHHHAAAAAAAAAAA\n";
    for(int i=0;i<5;i++)
    {
        cout << hex << H[i] << " ";
    }

    //Message_Block_Index = 0;


}
0 голосов
/ 12 апреля 2011

Учитывая все обстоятельства, учитывая ваши требования, я думаю, вам придется изменить свои спецификации. Либо больший чип, либо более простой алгоритм. Даже реализация SHA-1 (без HMAC) будет сложной задачей, но это должно быть выполнимо.

...