一种节省内存的SHA1实现

时间:2011-04-12 04:49:52

标签: c++ c hash cryptography sha1

我正在使用一个非常严格的嵌入式处理器,它只有128个字节的RAM。我想在它上面实现SHA1。 RFC3174在'方法2'中描述了一种实现SHA1的方法,该方法不需要分配80个32位字的数组(320字节,显然不实用),看起来应该是这样的可以在我的处理器上使用但是,我无法找到“方法2”的任何实现,RFC中的示例代码只实现了默认方法。

是否有人知道在C或C ++中使用内存效率的SHA1实现?

4 个答案:

答案 0 :(得分:10)

您应该能够快速调整方法1源到方法2.要更改的函数是方法1中的Sha1ProcessMessageBlock()。从消息初始化w[0:15],然后执行0到79的循环,在迭代16之后你只进行w[]操作,而临时计算取决于t的值(0-19使用一个,20-39使用另一个,等等)。需要记住的重要一点是,只要您处理index%16数组,就会使用index & 0x0fw[]

快速修改会是这样的(仔细检查对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数组中,添加填充并立即处理。如果没有,你将不得不两次调用进程:首先使用部分填充的输入,然后再使用其余的pad,等等。这类事情将是非常特定于应用程序的,我怀疑你是否能够找到为你做的代码。

顺便说一句,上面的代码是来自链接的类型1源的直接改编。如果你试图进一步优化它,你可能会更多地挤出它。

我想不出可以节省中间散列的方法,所以你需要总共108个字节(109,如果计数器也在RAM中),其中24个是本函数的本地,并且可以在其他地方重复使用 - 只要它们也是临时的。所以你很难做你想做的事。


编辑:如果所有消息都少于55个字节,则可以通过删除intermediate_hash[]存储来保存上下文中的另外20个字节。只需从常量初始化A-E,然后在最后添加常量。最后,不要将它们存储在单独的变量中,而是在此函数结束时覆盖输入。

答案 1 :(得分:3)

我已经为几个内存受限的环境实现了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 :(得分:2)

工作示例:

#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;


}

答案 3 :(得分:0)

考虑到所有事情,考虑到您的要求,我认为您将不得不改变您的规格。无论是更大的芯片,还是更简单的算法。即使实施SHA-1(没有HMAC)也是一个挑战,但它应该是可行的。