1/*
2 * Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the OpenSSL license (the "License").  You may not use
5 * this file except in compliance with the License.  You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 *
9 * $FreeBSD$
10 */
11
12/*
13 * Derived from include/crypto/md32_common.h
14 *
15 * HASH_UPDATE and HASH_FINAL have been updated to work with the
16 * auth_hash interface.
17 */
18
19#if defined(DATA_ORDER_IS_BIG_ENDIAN)
20
21# define HOST_c2l(c,l)  (l =(((unsigned long)(*((c)++)))<<24),          \
22                         l|=(((unsigned long)(*((c)++)))<<16),          \
23                         l|=(((unsigned long)(*((c)++)))<< 8),          \
24                         l|=(((unsigned long)(*((c)++)))    )           )
25# define HOST_l2c(l,c)  (*((c)++)=(unsigned char)(((l)>>24)&0xff),      \
26                         *((c)++)=(unsigned char)(((l)>>16)&0xff),      \
27                         *((c)++)=(unsigned char)(((l)>> 8)&0xff),      \
28                         *((c)++)=(unsigned char)(((l)    )&0xff),      \
29                         l)
30
31#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
32
33# define HOST_c2l(c,l)  (l =(((unsigned long)(*((c)++)))    ),          \
34                         l|=(((unsigned long)(*((c)++)))<< 8),          \
35                         l|=(((unsigned long)(*((c)++)))<<16),          \
36                         l|=(((unsigned long)(*((c)++)))<<24)           )
37# define HOST_l2c(l,c)  (*((c)++)=(unsigned char)(((l)    )&0xff),      \
38                         *((c)++)=(unsigned char)(((l)>> 8)&0xff),      \
39                         *((c)++)=(unsigned char)(((l)>>16)&0xff),      \
40                         *((c)++)=(unsigned char)(((l)>>24)&0xff),      \
41                         l)
42
43#endif
44
45/*
46 * Time for some action :-)
47 */
48
49static int
50HASH_UPDATE(void *c_, const void *data_, unsigned int len)
51{
52    HASH_CTX *c = c_;
53    const unsigned char *data = data_;
54    unsigned char *p;
55    HASH_LONG l;
56    size_t n;
57
58    if (len == 0)
59        return 0;
60
61    l = (c->Nl + (((HASH_LONG) len) << 3)) & 0xffffffffUL;
62    if (l < c->Nl)              /* overflow */
63        c->Nh++;
64    c->Nh += (HASH_LONG) (len >> 29); /* might cause compiler warning on
65                                       * 16-bit */
66    c->Nl = l;
67
68    n = c->num;
69    if (n != 0) {
70        p = (unsigned char *)c->data;
71
72        if (len >= HASH_CBLOCK || len + n >= HASH_CBLOCK) {
73            memcpy(p + n, data, HASH_CBLOCK - n);
74            HASH_BLOCK_DATA_ORDER(c, p, 1);
75            n = HASH_CBLOCK - n;
76            data += n;
77            len -= n;
78            c->num = 0;
79            /*
80             * We use memset rather than OPENSSL_cleanse() here deliberately.
81             * Using OPENSSL_cleanse() here could be a performance issue. It
82             * will get properly cleansed on finalisation so this isn't a
83             * security problem.
84             */
85            memset(p, 0, HASH_CBLOCK); /* keep it zeroed */
86        } else {
87            memcpy(p + n, data, len);
88            c->num += (unsigned int)len;
89            return 0;
90        }
91    }
92
93    n = len / HASH_CBLOCK;
94    if (n > 0) {
95        HASH_BLOCK_DATA_ORDER(c, data, n);
96        n *= HASH_CBLOCK;
97        data += n;
98        len -= n;
99    }
100
101    if (len != 0) {
102        p = (unsigned char *)c->data;
103        c->num = (unsigned int)len;
104        memcpy(p, data, len);
105    }
106    return 0;
107}
108
109static void
110HASH_FINAL(uint8_t *md, void *c_)
111{
112    HASH_CTX *c = c_;
113    unsigned char *p = (unsigned char *)c->data;
114    size_t n = c->num;
115
116    p[n] = 0x80;                /* there is always room for one */
117    n++;
118
119    if (n > (HASH_CBLOCK - 8)) {
120        memset(p + n, 0, HASH_CBLOCK - n);
121        n = 0;
122        HASH_BLOCK_DATA_ORDER(c, p, 1);
123    }
124    memset(p + n, 0, HASH_CBLOCK - 8 - n);
125
126    p += HASH_CBLOCK - 8;
127#if   defined(DATA_ORDER_IS_BIG_ENDIAN)
128    (void)HOST_l2c(c->Nh, p);
129    (void)HOST_l2c(c->Nl, p);
130#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
131    (void)HOST_l2c(c->Nl, p);
132    (void)HOST_l2c(c->Nh, p);
133#endif
134    p -= HASH_CBLOCK;
135    HASH_BLOCK_DATA_ORDER(c, p, 1);
136    c->num = 0;
137    OPENSSL_cleanse(p, HASH_CBLOCK);
138
139#ifndef HASH_MAKE_STRING
140# error "HASH_MAKE_STRING must be defined!"
141#else
142    HASH_MAKE_STRING(c, md);
143#endif
144
145    return;
146}
147