SHA-1 in C on little-endian environment





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







1















Most implementations of SHA-1 (even on Wikipedia) I came across are coded for big-endian runtimes. So I'm trying to implement my own version for my machine (little-endian).



I've followed the pseudo-code form Wikipedia and have the following code. I found a function that converts the byte ordering but still not getting the correct output.



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

#define rotateleft(x,n) ((x<<n) | (x>>(32-n)))

unsigned int endian_reverse(unsigned int n)
{
unsigned int m = 0;
m |= n << 24;
m |= ((n >> 8) << 24) >> 8;
m |= ((n << 8) >> 24) << 8;
m |= n >> 24;
return m;
}

void SHA1(unsigned char * str1)
{
unsigned long int h0,h1,h2,h3,h4,a,b,c,d,e,f,k,temp;

h0 = 0x67452301;
h1 = 0xEFCDAB89;
h2 = 0x98BADCFE;
h3 = 0x10325476;
h4 = 0xC3D2E1F0;

unsigned char * str;

str = (unsigned char *)malloc(strlen((const char *)str1)+100);
strcpy((char *)str,(const char *)str1);

int current_length = strlen((const char *)str);
int original_length = current_length;

str[current_length] = 0x80;
str[current_length + 1] = '';

char ic = str[current_length];

current_length++;
int ib = current_length % 64;

int i, j;

if(ib<56)
ib = 56-ib;
else
ib = 120 - ib;

for(i=0;i < ib;i++)
{
str[current_length]=0x00;
current_length++;
}

str[current_length + 1]='';

for(i=0;i<6;i++)
{
str[current_length]=0x0;
current_length++;
}

str[current_length] = (original_length * 8) / 0x100 ;
current_length++;
str[current_length] = (original_length * 8) % 0x100;
current_length++;
str[current_length+i]='';

int number_of_chunks = current_length/64;
unsigned long int word[80];

for(i=0;i<number_of_chunks;i++)
{
for(j=0;j<16;j++)
{
word[j] =
str[i*64 + j*4 + 0] * 0x1000000 + str[i*64 + j*4 + 1] * 0x10000 +
str[i*64 + j*4 + 2] * 0x100 + str[i*64 + j*4 + 3];
}
for(j=16;j<80;j++)
{
word[j] = rotateleft((word[j-3] ^ word[j-8] ^ word[j-14] ^ word[j-16]),1);
}
a = h0;
b = h1;
c = h2;
d = h3;
e = h4;
for(int m=0;m<80;m++)
{
if(m<=19)
{
f = (b & c) | ((~b) & d);
k = 0x5A827999;
}
else if(m<=39)
{
f = b ^ c ^ d;
k = 0x6ED9EBA1;
}
else if(m<=59)
{
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
}
else
{
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
temp = (rotateleft(a,5) + f + e + k + word[m]) & 0xFFFFFFFF;
e = d;
d = c;
c = rotateleft(b,30);
b = a;
a = temp;

}

h0 = h0 + a;
h1 = h1 + b;
h2 = h2 + c;
h3 = h3 + d;
h4 = h4 + e;

}

h0 = endian_reverse(h0);
h1 = endian_reverse(h1);
h2 = endian_reverse(h2);
h3 = endian_reverse(h3);
h4 = endian_reverse(h4);

printf("nn");
printf("Hash: %x %x %x %x %x",h0, h1, h2, h3, h4);
printf("nn");
}

int main()
{
SHA1((unsigned char *)"abc");
return 0;
}


SHA-1 ("abc"):



Resulting



Hash: f7370736 e388302f 15815610 1ccacd49 e7649bb6


Correct (actual)



Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d


Am I doing my endianness conversion correctly or in the correct spot?










share|improve this question

























  • My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.

    – xornoz
    Nov 23 '18 at 4:47













  • I've clarified the question at the end. But I guess to narrow it down: "Am I doing my endianness conversion correctly?"

    – xornoz
    Nov 23 '18 at 4:55













  • Okay, I hope to have cleared it up the main body now.

    – xornoz
    Nov 23 '18 at 5:00











  • Most implementations I have seen are for both big-endian and little endian. Try this link, it's for little endian github.com/B-Con/crypto-algorithms/blob/master

    – Barmak Shemirani
    Nov 23 '18 at 5:00








  • 1





    By the way endianness comes into play when reinterpreting memory, not for just general arithmetic (including bitwise operations). There is no reinterpretation in this code so it should not matter.

    – harold
    Nov 23 '18 at 6:19


















1















Most implementations of SHA-1 (even on Wikipedia) I came across are coded for big-endian runtimes. So I'm trying to implement my own version for my machine (little-endian).



I've followed the pseudo-code form Wikipedia and have the following code. I found a function that converts the byte ordering but still not getting the correct output.



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

#define rotateleft(x,n) ((x<<n) | (x>>(32-n)))

unsigned int endian_reverse(unsigned int n)
{
unsigned int m = 0;
m |= n << 24;
m |= ((n >> 8) << 24) >> 8;
m |= ((n << 8) >> 24) << 8;
m |= n >> 24;
return m;
}

void SHA1(unsigned char * str1)
{
unsigned long int h0,h1,h2,h3,h4,a,b,c,d,e,f,k,temp;

h0 = 0x67452301;
h1 = 0xEFCDAB89;
h2 = 0x98BADCFE;
h3 = 0x10325476;
h4 = 0xC3D2E1F0;

unsigned char * str;

str = (unsigned char *)malloc(strlen((const char *)str1)+100);
strcpy((char *)str,(const char *)str1);

int current_length = strlen((const char *)str);
int original_length = current_length;

str[current_length] = 0x80;
str[current_length + 1] = '';

char ic = str[current_length];

current_length++;
int ib = current_length % 64;

int i, j;

if(ib<56)
ib = 56-ib;
else
ib = 120 - ib;

for(i=0;i < ib;i++)
{
str[current_length]=0x00;
current_length++;
}

str[current_length + 1]='';

for(i=0;i<6;i++)
{
str[current_length]=0x0;
current_length++;
}

str[current_length] = (original_length * 8) / 0x100 ;
current_length++;
str[current_length] = (original_length * 8) % 0x100;
current_length++;
str[current_length+i]='';

int number_of_chunks = current_length/64;
unsigned long int word[80];

for(i=0;i<number_of_chunks;i++)
{
for(j=0;j<16;j++)
{
word[j] =
str[i*64 + j*4 + 0] * 0x1000000 + str[i*64 + j*4 + 1] * 0x10000 +
str[i*64 + j*4 + 2] * 0x100 + str[i*64 + j*4 + 3];
}
for(j=16;j<80;j++)
{
word[j] = rotateleft((word[j-3] ^ word[j-8] ^ word[j-14] ^ word[j-16]),1);
}
a = h0;
b = h1;
c = h2;
d = h3;
e = h4;
for(int m=0;m<80;m++)
{
if(m<=19)
{
f = (b & c) | ((~b) & d);
k = 0x5A827999;
}
else if(m<=39)
{
f = b ^ c ^ d;
k = 0x6ED9EBA1;
}
else if(m<=59)
{
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
}
else
{
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
temp = (rotateleft(a,5) + f + e + k + word[m]) & 0xFFFFFFFF;
e = d;
d = c;
c = rotateleft(b,30);
b = a;
a = temp;

}

h0 = h0 + a;
h1 = h1 + b;
h2 = h2 + c;
h3 = h3 + d;
h4 = h4 + e;

}

h0 = endian_reverse(h0);
h1 = endian_reverse(h1);
h2 = endian_reverse(h2);
h3 = endian_reverse(h3);
h4 = endian_reverse(h4);

printf("nn");
printf("Hash: %x %x %x %x %x",h0, h1, h2, h3, h4);
printf("nn");
}

int main()
{
SHA1((unsigned char *)"abc");
return 0;
}


SHA-1 ("abc"):



Resulting



Hash: f7370736 e388302f 15815610 1ccacd49 e7649bb6


Correct (actual)



Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d


Am I doing my endianness conversion correctly or in the correct spot?










share|improve this question

























  • My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.

    – xornoz
    Nov 23 '18 at 4:47













  • I've clarified the question at the end. But I guess to narrow it down: "Am I doing my endianness conversion correctly?"

    – xornoz
    Nov 23 '18 at 4:55













  • Okay, I hope to have cleared it up the main body now.

    – xornoz
    Nov 23 '18 at 5:00











  • Most implementations I have seen are for both big-endian and little endian. Try this link, it's for little endian github.com/B-Con/crypto-algorithms/blob/master

    – Barmak Shemirani
    Nov 23 '18 at 5:00








  • 1





    By the way endianness comes into play when reinterpreting memory, not for just general arithmetic (including bitwise operations). There is no reinterpretation in this code so it should not matter.

    – harold
    Nov 23 '18 at 6:19














1












1








1








Most implementations of SHA-1 (even on Wikipedia) I came across are coded for big-endian runtimes. So I'm trying to implement my own version for my machine (little-endian).



I've followed the pseudo-code form Wikipedia and have the following code. I found a function that converts the byte ordering but still not getting the correct output.



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

#define rotateleft(x,n) ((x<<n) | (x>>(32-n)))

unsigned int endian_reverse(unsigned int n)
{
unsigned int m = 0;
m |= n << 24;
m |= ((n >> 8) << 24) >> 8;
m |= ((n << 8) >> 24) << 8;
m |= n >> 24;
return m;
}

void SHA1(unsigned char * str1)
{
unsigned long int h0,h1,h2,h3,h4,a,b,c,d,e,f,k,temp;

h0 = 0x67452301;
h1 = 0xEFCDAB89;
h2 = 0x98BADCFE;
h3 = 0x10325476;
h4 = 0xC3D2E1F0;

unsigned char * str;

str = (unsigned char *)malloc(strlen((const char *)str1)+100);
strcpy((char *)str,(const char *)str1);

int current_length = strlen((const char *)str);
int original_length = current_length;

str[current_length] = 0x80;
str[current_length + 1] = '';

char ic = str[current_length];

current_length++;
int ib = current_length % 64;

int i, j;

if(ib<56)
ib = 56-ib;
else
ib = 120 - ib;

for(i=0;i < ib;i++)
{
str[current_length]=0x00;
current_length++;
}

str[current_length + 1]='';

for(i=0;i<6;i++)
{
str[current_length]=0x0;
current_length++;
}

str[current_length] = (original_length * 8) / 0x100 ;
current_length++;
str[current_length] = (original_length * 8) % 0x100;
current_length++;
str[current_length+i]='';

int number_of_chunks = current_length/64;
unsigned long int word[80];

for(i=0;i<number_of_chunks;i++)
{
for(j=0;j<16;j++)
{
word[j] =
str[i*64 + j*4 + 0] * 0x1000000 + str[i*64 + j*4 + 1] * 0x10000 +
str[i*64 + j*4 + 2] * 0x100 + str[i*64 + j*4 + 3];
}
for(j=16;j<80;j++)
{
word[j] = rotateleft((word[j-3] ^ word[j-8] ^ word[j-14] ^ word[j-16]),1);
}
a = h0;
b = h1;
c = h2;
d = h3;
e = h4;
for(int m=0;m<80;m++)
{
if(m<=19)
{
f = (b & c) | ((~b) & d);
k = 0x5A827999;
}
else if(m<=39)
{
f = b ^ c ^ d;
k = 0x6ED9EBA1;
}
else if(m<=59)
{
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
}
else
{
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
temp = (rotateleft(a,5) + f + e + k + word[m]) & 0xFFFFFFFF;
e = d;
d = c;
c = rotateleft(b,30);
b = a;
a = temp;

}

h0 = h0 + a;
h1 = h1 + b;
h2 = h2 + c;
h3 = h3 + d;
h4 = h4 + e;

}

h0 = endian_reverse(h0);
h1 = endian_reverse(h1);
h2 = endian_reverse(h2);
h3 = endian_reverse(h3);
h4 = endian_reverse(h4);

printf("nn");
printf("Hash: %x %x %x %x %x",h0, h1, h2, h3, h4);
printf("nn");
}

int main()
{
SHA1((unsigned char *)"abc");
return 0;
}


SHA-1 ("abc"):



Resulting



Hash: f7370736 e388302f 15815610 1ccacd49 e7649bb6


Correct (actual)



Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d


Am I doing my endianness conversion correctly or in the correct spot?










share|improve this question
















Most implementations of SHA-1 (even on Wikipedia) I came across are coded for big-endian runtimes. So I'm trying to implement my own version for my machine (little-endian).



I've followed the pseudo-code form Wikipedia and have the following code. I found a function that converts the byte ordering but still not getting the correct output.



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

#define rotateleft(x,n) ((x<<n) | (x>>(32-n)))

unsigned int endian_reverse(unsigned int n)
{
unsigned int m = 0;
m |= n << 24;
m |= ((n >> 8) << 24) >> 8;
m |= ((n << 8) >> 24) << 8;
m |= n >> 24;
return m;
}

void SHA1(unsigned char * str1)
{
unsigned long int h0,h1,h2,h3,h4,a,b,c,d,e,f,k,temp;

h0 = 0x67452301;
h1 = 0xEFCDAB89;
h2 = 0x98BADCFE;
h3 = 0x10325476;
h4 = 0xC3D2E1F0;

unsigned char * str;

str = (unsigned char *)malloc(strlen((const char *)str1)+100);
strcpy((char *)str,(const char *)str1);

int current_length = strlen((const char *)str);
int original_length = current_length;

str[current_length] = 0x80;
str[current_length + 1] = '';

char ic = str[current_length];

current_length++;
int ib = current_length % 64;

int i, j;

if(ib<56)
ib = 56-ib;
else
ib = 120 - ib;

for(i=0;i < ib;i++)
{
str[current_length]=0x00;
current_length++;
}

str[current_length + 1]='';

for(i=0;i<6;i++)
{
str[current_length]=0x0;
current_length++;
}

str[current_length] = (original_length * 8) / 0x100 ;
current_length++;
str[current_length] = (original_length * 8) % 0x100;
current_length++;
str[current_length+i]='';

int number_of_chunks = current_length/64;
unsigned long int word[80];

for(i=0;i<number_of_chunks;i++)
{
for(j=0;j<16;j++)
{
word[j] =
str[i*64 + j*4 + 0] * 0x1000000 + str[i*64 + j*4 + 1] * 0x10000 +
str[i*64 + j*4 + 2] * 0x100 + str[i*64 + j*4 + 3];
}
for(j=16;j<80;j++)
{
word[j] = rotateleft((word[j-3] ^ word[j-8] ^ word[j-14] ^ word[j-16]),1);
}
a = h0;
b = h1;
c = h2;
d = h3;
e = h4;
for(int m=0;m<80;m++)
{
if(m<=19)
{
f = (b & c) | ((~b) & d);
k = 0x5A827999;
}
else if(m<=39)
{
f = b ^ c ^ d;
k = 0x6ED9EBA1;
}
else if(m<=59)
{
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
}
else
{
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
temp = (rotateleft(a,5) + f + e + k + word[m]) & 0xFFFFFFFF;
e = d;
d = c;
c = rotateleft(b,30);
b = a;
a = temp;

}

h0 = h0 + a;
h1 = h1 + b;
h2 = h2 + c;
h3 = h3 + d;
h4 = h4 + e;

}

h0 = endian_reverse(h0);
h1 = endian_reverse(h1);
h2 = endian_reverse(h2);
h3 = endian_reverse(h3);
h4 = endian_reverse(h4);

printf("nn");
printf("Hash: %x %x %x %x %x",h0, h1, h2, h3, h4);
printf("nn");
}

int main()
{
SHA1((unsigned char *)"abc");
return 0;
}


SHA-1 ("abc"):



Resulting



Hash: f7370736 e388302f 15815610 1ccacd49 e7649bb6


Correct (actual)



Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d


Am I doing my endianness conversion correctly or in the correct spot?







c endianness sha






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 23 '18 at 7:01









chux

85.4k874158




85.4k874158










asked Nov 23 '18 at 4:34









xornozxornoz

83




83













  • My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.

    – xornoz
    Nov 23 '18 at 4:47













  • I've clarified the question at the end. But I guess to narrow it down: "Am I doing my endianness conversion correctly?"

    – xornoz
    Nov 23 '18 at 4:55













  • Okay, I hope to have cleared it up the main body now.

    – xornoz
    Nov 23 '18 at 5:00











  • Most implementations I have seen are for both big-endian and little endian. Try this link, it's for little endian github.com/B-Con/crypto-algorithms/blob/master

    – Barmak Shemirani
    Nov 23 '18 at 5:00








  • 1





    By the way endianness comes into play when reinterpreting memory, not for just general arithmetic (including bitwise operations). There is no reinterpretation in this code so it should not matter.

    – harold
    Nov 23 '18 at 6:19



















  • My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.

    – xornoz
    Nov 23 '18 at 4:47













  • I've clarified the question at the end. But I guess to narrow it down: "Am I doing my endianness conversion correctly?"

    – xornoz
    Nov 23 '18 at 4:55













  • Okay, I hope to have cleared it up the main body now.

    – xornoz
    Nov 23 '18 at 5:00











  • Most implementations I have seen are for both big-endian and little endian. Try this link, it's for little endian github.com/B-Con/crypto-algorithms/blob/master

    – Barmak Shemirani
    Nov 23 '18 at 5:00








  • 1





    By the way endianness comes into play when reinterpreting memory, not for just general arithmetic (including bitwise operations). There is no reinterpretation in this code so it should not matter.

    – harold
    Nov 23 '18 at 6:19

















My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.

– xornoz
Nov 23 '18 at 4:47







My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.

– xornoz
Nov 23 '18 at 4:47















I've clarified the question at the end. But I guess to narrow it down: "Am I doing my endianness conversion correctly?"

– xornoz
Nov 23 '18 at 4:55







I've clarified the question at the end. But I guess to narrow it down: "Am I doing my endianness conversion correctly?"

– xornoz
Nov 23 '18 at 4:55















Okay, I hope to have cleared it up the main body now.

– xornoz
Nov 23 '18 at 5:00





Okay, I hope to have cleared it up the main body now.

– xornoz
Nov 23 '18 at 5:00













Most implementations I have seen are for both big-endian and little endian. Try this link, it's for little endian github.com/B-Con/crypto-algorithms/blob/master

– Barmak Shemirani
Nov 23 '18 at 5:00







Most implementations I have seen are for both big-endian and little endian. Try this link, it's for little endian github.com/B-Con/crypto-algorithms/blob/master

– Barmak Shemirani
Nov 23 '18 at 5:00






1




1





By the way endianness comes into play when reinterpreting memory, not for just general arithmetic (including bitwise operations). There is no reinterpretation in this code so it should not matter.

– harold
Nov 23 '18 at 6:19





By the way endianness comes into play when reinterpreting memory, not for just general arithmetic (including bitwise operations). There is no reinterpretation in this code so it should not matter.

– harold
Nov 23 '18 at 6:19












1 Answer
1






active

oldest

votes


















1















Am I doing my endianness conversion correctly or in the correct spot?




Endianness conversion endian_reverse(() is incorrect when unsigned is not 32-bit.



Endianness conversion not used in correct spot. Endian conversion not needed.



Other issues exists.





Code is assuming unsigned long int is 32-bit. When unsigned long int is 64-bit, I can get the same answer as OP.



Save yourself time: There is no reason to use loose types here. Use uint32_t, uint8_t. For array sizing and string lengths use size_t. Avoid signed types and constants.





By changing unsigned long --> uint32_t and dropping h0 = endian_reverse(h0); ... h7 = endian_reverse(h7); I came up with



Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d




Other suggestions.



Multiple of 64



size in str = malloc(size) should be a multiple of 64



Stay within multiples of 64



str[current_length+i]=''; can write outside allocation.



Alternate size storing



Works for all size_t values up to 264-3 - 1.



  size_t current_length = ...

// append length in bits
uint64_t current_length_bits = current_length;
current_length_bits *= 8;
for (i = 8; i > 0; ) {
i--;
str[current_length + i] = (unsigned char) current_length_bits;
current_length_bits >>= 8;
}
current_length += 8;





share|improve this answer


























  • Are you compiling on a big-endian machine?

    – xornoz
    Nov 23 '18 at 6:16











  • @xornoz As I see it - machine endian makes no difference in this code. It is the wrong size of the various types that is messing the code. What lines of code do you think make a difference because of machine endian?

    – chux
    Nov 23 '18 at 6:20











  • The constants h0 = 0x67452301;...

    – xornoz
    Nov 23 '18 at 6:22











  • @xornoz How do you see endian of h0 as important here? The constant needs to have the value of 0x67452301 regardless of machine endian.

    – chux
    Nov 23 '18 at 6:24






  • 1





    Actually I was wrong. You can write h0, h1... in to buffer by using >> operator. This doesn't require endian check. Some implementations use memcpy, fwrite etc. to write the memory in &h0 in to a buffer, this needs flipping the byte order for little-endian. The latter method is pointlessly complicated and is also used in many places.

    – Barmak Shemirani
    Nov 24 '18 at 4:35














Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53440696%2fsha-1-in-c-on-little-endian-environment%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1















Am I doing my endianness conversion correctly or in the correct spot?




Endianness conversion endian_reverse(() is incorrect when unsigned is not 32-bit.



Endianness conversion not used in correct spot. Endian conversion not needed.



Other issues exists.





Code is assuming unsigned long int is 32-bit. When unsigned long int is 64-bit, I can get the same answer as OP.



Save yourself time: There is no reason to use loose types here. Use uint32_t, uint8_t. For array sizing and string lengths use size_t. Avoid signed types and constants.





By changing unsigned long --> uint32_t and dropping h0 = endian_reverse(h0); ... h7 = endian_reverse(h7); I came up with



Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d




Other suggestions.



Multiple of 64



size in str = malloc(size) should be a multiple of 64



Stay within multiples of 64



str[current_length+i]=''; can write outside allocation.



Alternate size storing



Works for all size_t values up to 264-3 - 1.



  size_t current_length = ...

// append length in bits
uint64_t current_length_bits = current_length;
current_length_bits *= 8;
for (i = 8; i > 0; ) {
i--;
str[current_length + i] = (unsigned char) current_length_bits;
current_length_bits >>= 8;
}
current_length += 8;





share|improve this answer


























  • Are you compiling on a big-endian machine?

    – xornoz
    Nov 23 '18 at 6:16











  • @xornoz As I see it - machine endian makes no difference in this code. It is the wrong size of the various types that is messing the code. What lines of code do you think make a difference because of machine endian?

    – chux
    Nov 23 '18 at 6:20











  • The constants h0 = 0x67452301;...

    – xornoz
    Nov 23 '18 at 6:22











  • @xornoz How do you see endian of h0 as important here? The constant needs to have the value of 0x67452301 regardless of machine endian.

    – chux
    Nov 23 '18 at 6:24






  • 1





    Actually I was wrong. You can write h0, h1... in to buffer by using >> operator. This doesn't require endian check. Some implementations use memcpy, fwrite etc. to write the memory in &h0 in to a buffer, this needs flipping the byte order for little-endian. The latter method is pointlessly complicated and is also used in many places.

    – Barmak Shemirani
    Nov 24 '18 at 4:35


















1















Am I doing my endianness conversion correctly or in the correct spot?




Endianness conversion endian_reverse(() is incorrect when unsigned is not 32-bit.



Endianness conversion not used in correct spot. Endian conversion not needed.



Other issues exists.





Code is assuming unsigned long int is 32-bit. When unsigned long int is 64-bit, I can get the same answer as OP.



Save yourself time: There is no reason to use loose types here. Use uint32_t, uint8_t. For array sizing and string lengths use size_t. Avoid signed types and constants.





By changing unsigned long --> uint32_t and dropping h0 = endian_reverse(h0); ... h7 = endian_reverse(h7); I came up with



Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d




Other suggestions.



Multiple of 64



size in str = malloc(size) should be a multiple of 64



Stay within multiples of 64



str[current_length+i]=''; can write outside allocation.



Alternate size storing



Works for all size_t values up to 264-3 - 1.



  size_t current_length = ...

// append length in bits
uint64_t current_length_bits = current_length;
current_length_bits *= 8;
for (i = 8; i > 0; ) {
i--;
str[current_length + i] = (unsigned char) current_length_bits;
current_length_bits >>= 8;
}
current_length += 8;





share|improve this answer


























  • Are you compiling on a big-endian machine?

    – xornoz
    Nov 23 '18 at 6:16











  • @xornoz As I see it - machine endian makes no difference in this code. It is the wrong size of the various types that is messing the code. What lines of code do you think make a difference because of machine endian?

    – chux
    Nov 23 '18 at 6:20











  • The constants h0 = 0x67452301;...

    – xornoz
    Nov 23 '18 at 6:22











  • @xornoz How do you see endian of h0 as important here? The constant needs to have the value of 0x67452301 regardless of machine endian.

    – chux
    Nov 23 '18 at 6:24






  • 1





    Actually I was wrong. You can write h0, h1... in to buffer by using >> operator. This doesn't require endian check. Some implementations use memcpy, fwrite etc. to write the memory in &h0 in to a buffer, this needs flipping the byte order for little-endian. The latter method is pointlessly complicated and is also used in many places.

    – Barmak Shemirani
    Nov 24 '18 at 4:35
















1












1








1








Am I doing my endianness conversion correctly or in the correct spot?




Endianness conversion endian_reverse(() is incorrect when unsigned is not 32-bit.



Endianness conversion not used in correct spot. Endian conversion not needed.



Other issues exists.





Code is assuming unsigned long int is 32-bit. When unsigned long int is 64-bit, I can get the same answer as OP.



Save yourself time: There is no reason to use loose types here. Use uint32_t, uint8_t. For array sizing and string lengths use size_t. Avoid signed types and constants.





By changing unsigned long --> uint32_t and dropping h0 = endian_reverse(h0); ... h7 = endian_reverse(h7); I came up with



Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d




Other suggestions.



Multiple of 64



size in str = malloc(size) should be a multiple of 64



Stay within multiples of 64



str[current_length+i]=''; can write outside allocation.



Alternate size storing



Works for all size_t values up to 264-3 - 1.



  size_t current_length = ...

// append length in bits
uint64_t current_length_bits = current_length;
current_length_bits *= 8;
for (i = 8; i > 0; ) {
i--;
str[current_length + i] = (unsigned char) current_length_bits;
current_length_bits >>= 8;
}
current_length += 8;





share|improve this answer
















Am I doing my endianness conversion correctly or in the correct spot?




Endianness conversion endian_reverse(() is incorrect when unsigned is not 32-bit.



Endianness conversion not used in correct spot. Endian conversion not needed.



Other issues exists.





Code is assuming unsigned long int is 32-bit. When unsigned long int is 64-bit, I can get the same answer as OP.



Save yourself time: There is no reason to use loose types here. Use uint32_t, uint8_t. For array sizing and string lengths use size_t. Avoid signed types and constants.





By changing unsigned long --> uint32_t and dropping h0 = endian_reverse(h0); ... h7 = endian_reverse(h7); I came up with



Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d




Other suggestions.



Multiple of 64



size in str = malloc(size) should be a multiple of 64



Stay within multiples of 64



str[current_length+i]=''; can write outside allocation.



Alternate size storing



Works for all size_t values up to 264-3 - 1.



  size_t current_length = ...

// append length in bits
uint64_t current_length_bits = current_length;
current_length_bits *= 8;
for (i = 8; i > 0; ) {
i--;
str[current_length + i] = (unsigned char) current_length_bits;
current_length_bits >>= 8;
}
current_length += 8;






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 23 '18 at 6:38

























answered Nov 23 '18 at 6:05









chuxchux

85.4k874158




85.4k874158













  • Are you compiling on a big-endian machine?

    – xornoz
    Nov 23 '18 at 6:16











  • @xornoz As I see it - machine endian makes no difference in this code. It is the wrong size of the various types that is messing the code. What lines of code do you think make a difference because of machine endian?

    – chux
    Nov 23 '18 at 6:20











  • The constants h0 = 0x67452301;...

    – xornoz
    Nov 23 '18 at 6:22











  • @xornoz How do you see endian of h0 as important here? The constant needs to have the value of 0x67452301 regardless of machine endian.

    – chux
    Nov 23 '18 at 6:24






  • 1





    Actually I was wrong. You can write h0, h1... in to buffer by using >> operator. This doesn't require endian check. Some implementations use memcpy, fwrite etc. to write the memory in &h0 in to a buffer, this needs flipping the byte order for little-endian. The latter method is pointlessly complicated and is also used in many places.

    – Barmak Shemirani
    Nov 24 '18 at 4:35





















  • Are you compiling on a big-endian machine?

    – xornoz
    Nov 23 '18 at 6:16











  • @xornoz As I see it - machine endian makes no difference in this code. It is the wrong size of the various types that is messing the code. What lines of code do you think make a difference because of machine endian?

    – chux
    Nov 23 '18 at 6:20











  • The constants h0 = 0x67452301;...

    – xornoz
    Nov 23 '18 at 6:22











  • @xornoz How do you see endian of h0 as important here? The constant needs to have the value of 0x67452301 regardless of machine endian.

    – chux
    Nov 23 '18 at 6:24






  • 1





    Actually I was wrong. You can write h0, h1... in to buffer by using >> operator. This doesn't require endian check. Some implementations use memcpy, fwrite etc. to write the memory in &h0 in to a buffer, this needs flipping the byte order for little-endian. The latter method is pointlessly complicated and is also used in many places.

    – Barmak Shemirani
    Nov 24 '18 at 4:35



















Are you compiling on a big-endian machine?

– xornoz
Nov 23 '18 at 6:16





Are you compiling on a big-endian machine?

– xornoz
Nov 23 '18 at 6:16













@xornoz As I see it - machine endian makes no difference in this code. It is the wrong size of the various types that is messing the code. What lines of code do you think make a difference because of machine endian?

– chux
Nov 23 '18 at 6:20





@xornoz As I see it - machine endian makes no difference in this code. It is the wrong size of the various types that is messing the code. What lines of code do you think make a difference because of machine endian?

– chux
Nov 23 '18 at 6:20













The constants h0 = 0x67452301;...

– xornoz
Nov 23 '18 at 6:22





The constants h0 = 0x67452301;...

– xornoz
Nov 23 '18 at 6:22













@xornoz How do you see endian of h0 as important here? The constant needs to have the value of 0x67452301 regardless of machine endian.

– chux
Nov 23 '18 at 6:24





@xornoz How do you see endian of h0 as important here? The constant needs to have the value of 0x67452301 regardless of machine endian.

– chux
Nov 23 '18 at 6:24




1




1





Actually I was wrong. You can write h0, h1... in to buffer by using >> operator. This doesn't require endian check. Some implementations use memcpy, fwrite etc. to write the memory in &h0 in to a buffer, this needs flipping the byte order for little-endian. The latter method is pointlessly complicated and is also used in many places.

– Barmak Shemirani
Nov 24 '18 at 4:35







Actually I was wrong. You can write h0, h1... in to buffer by using >> operator. This doesn't require endian check. Some implementations use memcpy, fwrite etc. to write the memory in &h0 in to a buffer, this needs flipping the byte order for little-endian. The latter method is pointlessly complicated and is also used in many places.

– Barmak Shemirani
Nov 24 '18 at 4:35






















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53440696%2fsha-1-in-c-on-little-endian-environment%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

ComboBox Display Member on multiple fields

Is it possible to collect Nectar points via Trainline?