Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
An implementation of the SHA1 hashing algorithm
[simgrid.git] / src / xbt / xbt_sha.c
1 /* $Id$ */
2 /* xbt_sha.c - SHA1 hash function */
3
4 /* Initial version part of iksemel (XML parser for Jabber)
5  *   Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net>
6  *   This code is free software; you can redistribute it and/or
7  *   modify it under the terms of GNU Lesser General Public License. */
8 /* Adapted to fit into SimGrid by Martin Quinson. */
9
10 #include "xbt/sysdep.h"
11 #include "xbt/hash.h"
12
13 struct s_xbt_sha_ {
14         unsigned int hash[5];
15         unsigned int buf[80];
16         int blen;
17         unsigned int lenhi, lenlo;
18 };
19 static void sha_calculate (xbt_sha_t sha);
20
21 /* ************** */
22 /* User Interface */
23 /* ************** */
24
25 /** @brief constructor */
26 xbt_sha_t xbt_sha_new (void) {
27         xbt_sha_t sha;
28
29         sha = xbt_new(s_xbt_sha_t,1);
30         xbt_sha_reset (sha);
31    
32         return sha;
33 }
34
35 /** @brief destructor */
36 void xbt_sha_free (xbt_sha_t sha) {
37    free (sha);
38 }
39
40 void xbt_sha_reset (xbt_sha_t sha) {
41    memset (sha, 0, sizeof (s_xbt_sha_t));
42    sha->hash[0] = 0x67452301;
43    sha->hash[1] = 0xefcdab89;
44    sha->hash[2] = 0x98badcfe;
45    sha->hash[3] = 0x10325476;
46    sha->hash[4] = 0xc3d2e1f0;
47 }
48
49 /* @brief Add some more data to the buffer */
50 void xbt_sha_feed (xbt_sha_t sha, const unsigned char *data, size_t len) {
51    int i;
52    
53    for (i=0; i<len; i++) {
54       sha->buf[sha->blen / 4] <<= 8;
55       sha->buf[sha->blen / 4] |= (unsigned int)data[i];
56       if ((++sha->blen) % 64 == 0) {
57          sha_calculate (sha);
58          sha->blen = 0;
59       }
60       sha->lenlo += 8;
61       sha->lenhi += (sha->lenlo < 8);
62    }
63 }
64
65 /* finalize computation before displaying the result */
66 static void xbt_sha_finalize (xbt_sha_t sha) {
67         unsigned char pad[8];
68         unsigned char padc;
69    
70         pad[0] = (unsigned char)((sha->lenhi >> 24) & 0xff);
71         pad[1] = (unsigned char)((sha->lenhi >> 16) & 0xff);
72         pad[2] = (unsigned char)((sha->lenhi >> 8) & 0xff);
73         pad[3] = (unsigned char)(sha->lenhi & 0xff);
74         pad[4] = (unsigned char)((sha->lenlo >> 24) & 0xff);
75         pad[5] = (unsigned char)((sha->lenlo >> 16) & 0xff);
76         pad[6] = (unsigned char)((sha->lenlo >> 8) & 0xff);
77         pad[7] = (unsigned char)(sha->lenlo & 255);
78
79         padc = 0x80;
80         xbt_sha_feed (sha, &padc, 1);
81
82         padc = 0x00;
83         while (sha->blen != 56)
84                 xbt_sha_feed (sha, &padc, 1);
85
86         xbt_sha_feed (sha, pad, 8);
87 }
88
89 /** @brief returns the sha hash into a newly allocated buffer (+ reset sha object) */
90 char *xbt_sha_read(xbt_sha_t sha) {
91    char *res = xbt_malloc(40);
92    xbt_sha_print(sha,res);
93    return res;
94 }
95
96 /** @brief copy the content sha hash into the @a hash pre-allocated string (and reset buffer) */
97 void xbt_sha_print (xbt_sha_t sha, char *hash) {
98    int i;
99    
100    xbt_sha_finalize(sha);
101    for (i=0; i<5; i++) {
102       sprintf (hash, "%08x", sha->hash[i]);
103       hash += 8;
104    }        
105 }
106
107
108 /** @brief simply compute a SHA1 hash and copy it to the provided buffer */
109 void xbt_sha (const char *data, char *hash) {
110   s_xbt_sha_t sha;
111
112   xbt_sha_reset (&sha);
113   xbt_sha_feed (&sha, (const unsigned char*)data, strlen (data));
114   
115   xbt_sha_print (&sha, hash);
116 }
117
118 /* ********************* */
119 /* Core of the algorithm */
120 /* ********************* */
121
122 #define SRL(x,y) (((x) << (y)) | ((x) >> (32-(y))))
123 #define SHA(a,b,f,c) \
124         for (i= (a) ; i<= (b) ; i++) { \
125                 TMP = SRL(A,5) + ( (f) ) + E + sha->buf[i] + (c) ; \
126                 E = D; \
127                 D = C; \
128                 C = SRL(B,30); \
129                 B = A; \
130                 A = TMP; \
131         }
132
133 static void sha_calculate (xbt_sha_t sha)
134 {
135         int i;
136         unsigned int A, B, C, D, E, TMP;
137
138         for (i=16; i<80; i++)
139                 sha->buf[i] = SRL (sha->buf[i-3] ^ sha->buf[i-8] ^ sha->buf[i-14] ^ sha->buf[i-16], 1);
140
141         A = sha->hash[0];
142         B = sha->hash[1];
143         C = sha->hash[2];
144         D = sha->hash[3];
145         E = sha->hash[4];
146
147         SHA (0,  19, ((C^D)&B)^D,     0x5a827999);
148         SHA (20, 39, B^C^D,           0x6ed9eba1);
149         SHA (40, 59, (B&C)|(D&(B|C)), 0x8f1bbcdc);
150         SHA (60, 79, B^C^D,           0xca62c1d6);
151
152         sha->hash[0] += A;
153         sha->hash[1] += B;
154         sha->hash[2] += C;
155         sha->hash[3] += D;
156         sha->hash[4] += E;
157 }
158
159 /* ************* */
160 /* Testing stuff */
161 /* ************* */
162 #ifdef SIMGRID_TEST
163 #include "xbt/hash.h"
164 #include "portable.h" /* hexa_str */
165
166 static char* mycmp(const char *p1, const char *p2,size_t n) {
167   int i;
168   
169   for (i=0; i<n; i++) {
170     if (p1[i] != p2[i]) {
171       return bprintf("Differs on %d -- Ox%x",i,p1[i]);
172     }
173   }
174   return xbt_strdup("");
175 }
176
177 static void test_sha(const char *clear,const char *hashed) {
178    char hash[41];
179    xbt_sha(clear,hash);
180    
181    xbt_test_add1("==== Test with '%s'",clear);
182    xbt_test_assert3(!memcmp(hash, hashed, 40), "Wrong sha: %40s!=%40s (%s)",
183                     hash,hashed,mycmp(hash,hashed,40));
184 }
185
186 XBT_TEST_SUITE("hash","Various hash functions");
187
188 XBT_LOG_NEW_DEFAULT_CATEGORY(hash,"Tests of various hash functions ");
189
190
191 XBT_TEST_UNIT("sha",test_crypto_sha,"Test of the sha algorithm") {
192    /* Empty string as test vector */
193    test_sha("",                                            "da39a3ee5e6b4b0d3255bfef95601890afd80709");
194   
195    /* Some pangram as test vector */
196    test_sha("The quick brown fox jumps over the lazy dog", "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12");
197    test_sha("Woven silk pyjamas exchanged for blue quartz","da3aff337c810c6470db4dbf0f205c8afc31c442");
198    test_sha("Pack my box with five dozen liquor jugs",     "373ba8be29d4d95708bf7cd43038f4e409dcb439");
199
200 }
201 #endif /* SIMGRID_TEST */