Coverage Report

Created: 2026-01-13 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pycryptodome/src/RIPEMD160.c
Line
Count
Source
1
/*
2
 *
3
 *  RIPEMD160.c : RIPEMD-160 implementation
4
 *
5
 * Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
6
 *
7
 * ===================================================================
8
 * The contents of this file are dedicated to the public domain.  To
9
 * the extent that dedication to the public domain is not available,
10
 * everyone is granted a worldwide, perpetual, royalty-free,
11
 * non-exclusive license to exercise all rights associated with the
12
 * contents of this file for any purpose whatsoever.
13
 * No rights are reserved.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
 * SOFTWARE.
23
 * ===================================================================
24
 *
25
 * Country of origin: Canada
26
 *
27
 * This implementation (written in C) is based on an implementation the author
28
 * wrote in Python.
29
 *
30
 * This implementation was written with reference to the RIPEMD-160
31
 * specification, which is available at:
32
 * http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/
33
 *
34
 * It is also documented in the _Handbook of Applied Cryptography_, as
35
 * Algorithm 9.55.  It's on page 30 of the following PDF file:
36
 * http://www.cacr.math.uwaterloo.ca/hac/about/chap9.pdf
37
 *
38
 * The RIPEMD-160 specification doesn't really tell us how to do padding, but
39
 * since RIPEMD-160 is inspired by MD4, you can use the padding algorithm from
40
 * RFC 1320.
41
 *
42
 * According to http://www.users.zetnet.co.uk/hopwood/crypto/scan/md.html:
43
 *   "RIPEMD-160 is big-bit-endian, little-byte-endian, and left-justified."
44
 */
45
46
#include "common.h"
47
#include "endianess.h"
48
49
FAKE_INIT(RIPEMD160)
50
51
259
#define RIPEMD160_DIGEST_SIZE 20
52
53
typedef struct {
54
    uint32_t h[5];      /* The current hash state */
55
    uint64_t length;    /* Total number of _bits_ (not bytes) added to the
56
                           hash.  This includes bits that have been buffered
57
                           but not not fed through the compression function yet. */
58
    uint8_t buf[64];
59
    unsigned bufpos;     /* number of bytes currently in the buffer */
60
} hash_state;
61
62
/* cyclic left-shift the 32-bit word n left by s bits */
63
71.2M
#define ROL(s, n) (((n) << (s)) | ((n) >> (32-(s))))
64
65
/* Ordering of message words.  Based on the permutations rho(i) and pi(i), defined as follows:
66
 *
67
 *  rho(i) := { 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8 }[i]  0 <= i <= 15
68
 *
69
 *  pi(i) := 9*i + 5 (mod 16)
70
 *
71
 *  Line  |  Round 1  |  Round 2  |  Round 3  |  Round 4  |  Round 5
72
 * -------+-----------+-----------+-----------+-----------+-----------
73
 *  left  |    id     |    rho    |   rho^2   |   rho^3   |   rho^4
74
 *  right |    pi     |   rho pi  |  rho^2 pi |  rho^3 pi |  rho^4 pi
75
 */
76
77
/* Left line */
78
static const uint8_t RL[5][16] = {
79
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },   /* Round 1: id */
80
    { 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8 },   /* Round 2: rho */
81
    { 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12 },   /* Round 3: rho^2 */
82
    { 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2 },   /* Round 4: rho^3 */
83
    { 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 }    /* Round 5: rho^4 */
84
};
85
86
/* Right line */
87
static const uint8_t RR[5][16] = {
88
    { 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12 },   /* Round 1: pi */
89
    { 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2 },   /* Round 2: rho pi */
90
    { 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13 },   /* Round 3: rho^2 pi */
91
    { 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14 },   /* Round 4: rho^3 pi */
92
    { 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 }    /* Round 5: rho^4 pi */
93
};
94
95
/*
96
 * Shifts - Since we don't actually re-order the message words according to
97
 * the permutations above (we could, but it would be slower), these tables
98
 * come with the permutations pre-applied.
99
 */
100
101
/* Shifts, left line */
102
static const uint8_t SL[5][16] = {
103
    { 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8 }, /* Round 1 */
104
    { 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12 }, /* Round 2 */
105
    { 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5 }, /* Round 3 */
106
    { 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12 }, /* Round 4 */
107
    { 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 }  /* Round 5 */
108
};
109
110
/* Shifts, right line */
111
static const uint8_t SR[5][16] = {
112
    { 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6 }, /* Round 1 */
113
    { 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11 }, /* Round 2 */
114
    { 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5 }, /* Round 3 */
115
    { 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8 }, /* Round 4 */
116
    { 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 }  /* Round 5 */
117
};
118
119
/* Boolean functions */
120
121
#define F1(x, y, z) ((x) ^ (y) ^ (z))
122
#define F2(x, y, z) (((x) & (y)) | (~(x) & (z)))
123
#define F3(x, y, z) (((x) | ~(y)) ^ (z))
124
#define F4(x, y, z) (((x) & (z)) | ((y) & ~(z)))
125
#define F5(x, y, z) ((x) ^ ((y) | ~(z)))
126
127
/* Round constants, left line */
128
static const uint32_t KL[5] = {
129
    0x00000000u,    /* Round 1: 0 */
130
    0x5A827999u,    /* Round 2: floor(2**30 * sqrt(2)) */
131
    0x6ED9EBA1u,    /* Round 3: floor(2**30 * sqrt(3)) */
132
    0x8F1BBCDCu,    /* Round 4: floor(2**30 * sqrt(5)) */
133
    0xA953FD4Eu     /* Round 5: floor(2**30 * sqrt(7)) */
134
};
135
136
/* Round constants, right line */
137
static const uint32_t KR[5] = {
138
    0x50A28BE6u,    /* Round 1: floor(2**30 * cubert(2)) */
139
    0x5C4DD124u,    /* Round 2: floor(2**30 * cubert(3)) */
140
    0x6D703EF3u,    /* Round 3: floor(2**30 * cubert(5)) */
141
    0x7A6D76E9u,    /* Round 4: floor(2**30 * cubert(7)) */
142
    0x00000000u     /* Round 5: 0 */
143
};
144
145
EXPORT_SYM int ripemd160_init(hash_state **ripemd160State)
146
259
{
147
259
    hash_state *hs;
148
    
149
    /* Initial values for the chaining variables.
150
    * This is just 0123456789ABCDEFFEDCBA9876543210F0E1D2C3 in little-endian. */
151
259
    static const uint32_t initial_h[5] = { 0x67452301u, 0xEFCDAB89u, 0x98BADCFEu, 0x10325476u, 0xC3D2E1F0u };
152
153
259
    if (NULL == ripemd160State) {
154
0
        return ERR_NULL;
155
0
    }
156
157
259
    *ripemd160State = hs = (hash_state*) calloc(1, sizeof(hash_state));
158
259
    if (NULL == hs)
159
0
        return ERR_MEMORY;
160
161
259
    memcpy(hs->h, initial_h, RIPEMD160_DIGEST_SIZE);
162
259
    return 0;
163
259
}
164
165
EXPORT_SYM int ripemd160_destroy(hash_state *hs)
166
259
{
167
259
    free(hs);
168
259
    return 0;
169
259
}
170
171
/* The RIPEMD160 compression function.  Operates on self->buf */
172
static void ripemd160_compress(hash_state *self)
173
222k
{
174
222k
    unsigned w, round;
175
222k
    uint32_t T;
176
222k
    uint32_t AL, BL, CL, DL, EL;    /* left line */
177
222k
    uint32_t AR, BR, CR, DR, ER;    /* right line */
178
222k
    uint32_t bufw[16];
179
180
3.78M
    for (w=0; w<16; w++)
181
3.56M
        bufw[w] = LOAD_U32_LITTLE(&self->buf[w*4]);
182
183
    /* Load the left and right lines with the initial state */
184
222k
    AL = AR = self->h[0];
185
222k
    BL = BR = self->h[1];
186
222k
    CL = CR = self->h[2];
187
222k
    DL = DR = self->h[3];
188
222k
    EL = ER = self->h[4];
189
190
    /* Round 1 */
191
222k
    round = 0;
192
3.78M
    for (w = 0; w < 16; w++) { /* left line */
193
3.56M
        T = ROL(SL[round][w], AL + F1(BL, CL, DL) + bufw[RL[round][w]] + KL[round]) + EL;
194
3.56M
        AL = EL; EL = DL; DL = ROL(10, CL); CL = BL; BL = T;
195
3.56M
    }
196
3.78M
    for (w = 0; w < 16; w++) { /* right line */
197
3.56M
        T = ROL(SR[round][w], AR + F5(BR, CR, DR) + bufw[RR[round][w]] + KR[round]) + ER;
198
3.56M
        AR = ER; ER = DR; DR = ROL(10, CR); CR = BR; BR = T;
199
3.56M
    }
200
201
    /* Round 2 */
202
222k
    round++;
203
3.78M
    for (w = 0; w < 16; w++) { /* left line */
204
3.56M
        T = ROL(SL[round][w], AL + F2(BL, CL, DL) + bufw[RL[round][w]] + KL[round]) + EL;
205
3.56M
        AL = EL; EL = DL; DL = ROL(10, CL); CL = BL; BL = T;
206
3.56M
    }
207
3.78M
    for (w = 0; w < 16; w++) { /* right line */
208
3.56M
        T = ROL(SR[round][w], AR + F4(BR, CR, DR) + bufw[RR[round][w]] + KR[round]) + ER;
209
3.56M
        AR = ER; ER = DR; DR = ROL(10, CR); CR = BR; BR = T;
210
3.56M
    }
211
212
    /* Round 3 */
213
222k
    round++;
214
3.78M
    for (w = 0; w < 16; w++) { /* left line */
215
3.56M
        T = ROL(SL[round][w], AL + F3(BL, CL, DL) + bufw[RL[round][w]] + KL[round]) + EL;
216
3.56M
        AL = EL; EL = DL; DL = ROL(10, CL); CL = BL; BL = T;
217
3.56M
    }
218
3.78M
    for (w = 0; w < 16; w++) { /* right line */
219
3.56M
        T = ROL(SR[round][w], AR + F3(BR, CR, DR) + bufw[RR[round][w]] + KR[round]) + ER;
220
3.56M
        AR = ER; ER = DR; DR = ROL(10, CR); CR = BR; BR = T;
221
3.56M
    }
222
223
    /* Round 4 */
224
222k
    round++;
225
3.78M
    for (w = 0; w < 16; w++) { /* left line */
226
3.56M
        T = ROL(SL[round][w], AL + F4(BL, CL, DL) + bufw[RL[round][w]] + KL[round]) + EL;
227
3.56M
        AL = EL; EL = DL; DL = ROL(10, CL); CL = BL; BL = T;
228
3.56M
    }
229
3.78M
    for (w = 0; w < 16; w++) { /* right line */
230
3.56M
        T = ROL(SR[round][w], AR + F2(BR, CR, DR) + bufw[RR[round][w]] + KR[round]) + ER;
231
3.56M
        AR = ER; ER = DR; DR = ROL(10, CR); CR = BR; BR = T;
232
3.56M
    }
233
234
    /* Round 5 */
235
222k
    round++;
236
3.78M
    for (w = 0; w < 16; w++) { /* left line */
237
3.56M
        T = ROL(SL[round][w], AL + F5(BL, CL, DL) + bufw[RL[round][w]] + KL[round]) + EL;
238
3.56M
        AL = EL; EL = DL; DL = ROL(10, CL); CL = BL; BL = T;
239
3.56M
    }
240
3.78M
    for (w = 0; w < 16; w++) { /* right line */
241
3.56M
        T = ROL(SR[round][w], AR + F1(BR, CR, DR) + bufw[RR[round][w]] + KR[round]) + ER;
242
3.56M
        AR = ER; ER = DR; DR = ROL(10, CR); CR = BR; BR = T;
243
3.56M
    }
244
245
    /* Final mixing stage */
246
222k
    T = self->h[1] + CL + DR;
247
222k
    self->h[1] = self->h[2] + DL + ER;
248
222k
    self->h[2] = self->h[3] + EL + AR;
249
222k
    self->h[3] = self->h[4] + AL + BR;
250
222k
    self->h[4] = self->h[0] + BL + CR;
251
222k
    self->h[0] = T;
252
253
    /* Clear the buffer and wipe the temporary variables */
254
222k
    T = AL = BL = CL = DL = EL = AR = BR = CR = DR = ER = 0;
255
222k
    memset(&self->buf, 0, sizeof(self->buf));
256
222k
    self->bufpos = 0;
257
222k
}
258
259
EXPORT_SYM int ripemd160_update(hash_state *hs, const uint8_t *in, size_t len)
260
1.15k
{
261
1.15k
    unsigned int bytes_needed;
262
263
1.15k
    if (NULL==hs || NULL==in)
264
139
        return ERR_NULL;
265
266
223k
    while (len > 0) {
267
        /* Figure out how many bytes we need to fill the internal buffer. */
268
223k
        bytes_needed = 64 - hs->bufpos;
269
270
223k
        if (len >= bytes_needed) {
271
            /* We have enough bytes, so copy them into the internal buffer and run
272
             * the compression function. */
273
222k
            memcpy(&hs->buf[hs->bufpos], in, bytes_needed);
274
222k
            hs->bufpos += bytes_needed;
275
222k
            hs->length += bytes_needed * 8;    /* length is in bits */
276
222k
            in += bytes_needed;
277
222k
            ripemd160_compress(hs);
278
222k
            len -= bytes_needed;
279
222k
            continue;
280
222k
        }
281
282
        /* We do not have enough bytes to fill the internal buffer.
283
         * Copy what's there and return. */
284
801
        memcpy(&hs->buf[hs->bufpos], in, len);
285
801
        hs->bufpos += (unsigned)len;
286
801
        hs->length += (unsigned)(len * 8);    /* length is in bits */
287
801
        return 0;
288
223k
    }
289
290
212
    return 0;
291
1.01k
}
292
293
EXPORT_SYM int ripemd160_copy(const hash_state *src, hash_state *dst)
294
0
{
295
0
    if (NULL == src || NULL == dst) {
296
0
        return ERR_NULL;
297
0
    }
298
299
0
    *dst = *src;
300
0
    return 0;
301
0
}
302
303
EXPORT_SYM int ripemd160_digest(const hash_state *hs, uint8_t digest[RIPEMD160_DIGEST_SIZE])
304
120
{
305
120
    hash_state tmp;
306
120
    unsigned i;
307
308
120
    if (NULL==hs || digest==NULL)
309
0
        return ERR_NULL;
310
311
120
    tmp = *hs;
312
313
    /* Append the padding */
314
120
    tmp.buf[tmp.bufpos++] = 0x80;
315
316
120
    if (tmp.bufpos > 56) {
317
47
        tmp.bufpos = 64;
318
47
        ripemd160_compress(&tmp);
319
47
    }
320
321
    /* Append the length */
322
120
    STORE_U64_LITTLE(&tmp.buf[sizeof tmp.buf - 8], tmp.length);
323
120
    tmp.bufpos = 64;
324
120
    ripemd160_compress(&tmp);
325
326
    /* Copy the final state into the output buffer */
327
120
    assert(RIPEMD160_DIGEST_SIZE == sizeof tmp.h);
328
720
    for (i=0; i<5; i++)
329
600
        STORE_U32_LITTLE(digest + i*sizeof tmp.h[0], tmp.h[i]);
330
331
120
    return 0;
332
120
}