1 /******************************************************************************
2  *
3  * Project:  CPL - Common Portability Library
4  * Purpose:  Implement SHA1
5  * Author:   Even Rouault, even.rouault at spatialys.com
6  *
7  * SHA1 computation coming from Public Domain code at:
8  * https://github.com/B-Con/crypto-algorithms/blob/master/sha1.c
9  * by Brad Conte (brad AT bradconte.com)
10  *
11  ******************************************************************************
12  * Copyright (c) 2017, Even Rouault <even.rouault at spatialys.com>
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the "Software"),
16  * to deal in the Software without restriction, including without limitation
17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  * and/or sell copies of the Software, and to permit persons to whom the
19  * Software is furnished to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice shall be included
22  * in all copies or substantial portions of the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30  * DEALINGS IN THE SOFTWARE.
31  ****************************************************************************/
32 
33 #include <string.h>
34 #include "cpl_sha1.h"
35 
36 CPL_CVSID("$Id: cpl_sha1.cpp ff8146d84de7cba8e09d212d5481ea7d2ede3e98 2017-06-27 20:47:31Z Even Rouault $")
37 
38 
39 typedef struct {
40     GByte data[64];
41     GUInt32 datalen;
42     GUIntBig bitlen;
43     GUInt32 state[5];
44 } CPL_SHA1Context;
45 
46 #define ROTLEFT(a, b) ((a << b) | (a >> (32 - b)))
47 
48 /************************************************************************/
49 /*                         sha1_transform()                             */
50 /************************************************************************/
51 
52 CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
53 static
sha1_transform(CPL_SHA1Context * ctx,const GByte data[])54 void sha1_transform(CPL_SHA1Context *ctx, const GByte data[])
55 {
56     GUInt32 a, b, c, d, e, i, j, t, m[80];
57 
58     for (i = 0, j = 0; i < 16; ++i, j += 4)
59         m[i] = (data[j] << 24) + (data[j + 1] << 16) +
60                (data[j + 2] << 8) + (data[j + 3]);
61     for ( ; i < 80; ++i) {
62         m[i] = (m[i - 3] ^ m[i - 8] ^ m[i - 14] ^ m[i - 16]);
63         m[i] = (m[i] << 1) | (m[i] >> 31);
64     }
65 
66     a = ctx->state[0];
67     b = ctx->state[1];
68     c = ctx->state[2];
69     d = ctx->state[3];
70     e = ctx->state[4];
71 
72     for (i = 0; i < 20; ++i) {
73         t = ROTLEFT(a, 5) + ((b & c) ^ (~b & d)) + e + 0x5a827999U + m[i];
74         e = d;
75         d = c;
76         c = ROTLEFT(b, 30);
77         b = a;
78         a = t;
79     }
80     for ( ; i < 40; ++i) {
81         t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + 0x6ed9eba1U + m[i];
82         e = d;
83         d = c;
84         c = ROTLEFT(b, 30);
85         b = a;
86         a = t;
87     }
88     for ( ; i < 60; ++i) {
89         t = ROTLEFT(a, 5) + ((b & c) ^ (b & d) ^ (c & d))  + e +
90             0x8f1bbcdcU + m[i];
91         e = d;
92         d = c;
93         c = ROTLEFT(b, 30);
94         b = a;
95         a = t;
96     }
97     for ( ; i < 80; ++i) {
98         t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + 0xca62c1d6U + m[i];
99         e = d;
100         d = c;
101         c = ROTLEFT(b, 30);
102         b = a;
103         a = t;
104     }
105 
106     ctx->state[0] += a;
107     ctx->state[1] += b;
108     ctx->state[2] += c;
109     ctx->state[3] += d;
110     ctx->state[4] += e;
111 }
112 
113 /************************************************************************/
114 /*                           CPL_SHA1Init()                             */
115 /************************************************************************/
116 
117 static
CPL_SHA1Init(CPL_SHA1Context * ctx)118 void CPL_SHA1Init(CPL_SHA1Context *ctx)
119 {
120     ctx->datalen = 0;
121     ctx->bitlen = 0;
122     ctx->state[0] = 0x67452301U;
123     ctx->state[1] = 0xEFCDAB89U;
124     ctx->state[2] = 0x98BADCFEU;
125     ctx->state[3] = 0x10325476U;
126     ctx->state[4] = 0xc3d2e1f0U;
127 }
128 
129 /************************************************************************/
130 /*                          CPL_SHA1Update()                            */
131 /************************************************************************/
132 
133 static
CPL_SHA1Update(CPL_SHA1Context * ctx,const GByte data[],size_t len)134 void CPL_SHA1Update(CPL_SHA1Context *ctx, const GByte data[], size_t len)
135 {
136     size_t i;
137 
138     for (i = 0; i < len; ++i) {
139         ctx->data[ctx->datalen] = data[i];
140         ctx->datalen++;
141         if (ctx->datalen == 64) {
142                 sha1_transform(ctx, ctx->data);
143                 ctx->bitlen += 512;
144                 ctx->datalen = 0;
145         }
146     }
147 }
148 
149 /************************************************************************/
150 /*                           CPL_SHA1Final()                            */
151 /************************************************************************/
152 
153 static
CPL_SHA1Final(CPL_SHA1Context * ctx,GByte hash[CPL_SHA1_HASH_SIZE])154 void CPL_SHA1Final(CPL_SHA1Context *ctx, GByte hash[CPL_SHA1_HASH_SIZE])
155 {
156     GUInt32 i;
157 
158     i = ctx->datalen;
159 
160     // Pad whatever data is left in the buffer.
161     if (ctx->datalen < 56) {
162         ctx->data[i++] = 0x80;
163         while (i < 56)
164             ctx->data[i++] = 0x00;
165     }
166     else {
167         ctx->data[i++] = 0x80;
168         while (i < 64)
169             ctx->data[i++] = 0x00;
170         sha1_transform(ctx, ctx->data);
171         memset(ctx->data, 0, 56);
172     }
173 
174     // Append to the padding the total message's length in bits and transform.
175     ctx->bitlen += ctx->datalen * 8;
176     ctx->data[63] = static_cast<GByte>((ctx->bitlen) & 0xFFU);
177     ctx->data[62] = static_cast<GByte>((ctx->bitlen >> 8) & 0xFFU);
178     ctx->data[61] = static_cast<GByte>((ctx->bitlen >> 16) & 0xFFU);
179     ctx->data[60] = static_cast<GByte>((ctx->bitlen >> 24) & 0xFFU);
180     ctx->data[59] = static_cast<GByte>((ctx->bitlen >> 32) & 0xFFU);
181     ctx->data[58] = static_cast<GByte>((ctx->bitlen >> 40) & 0xFFU);
182     ctx->data[57] = static_cast<GByte>((ctx->bitlen >> 48) & 0xFFU);
183     ctx->data[56] = static_cast<GByte>((ctx->bitlen >> 56) & 0xFFU);
184     sha1_transform(ctx, ctx->data);
185 
186     // Since this implementation uses little endian byte ordering and MD uses big endian,
187     // reverse all the bytes when copying the final state to the output hash.
188     for (i = 0; i < 4; ++i) {
189         hash[i]      = static_cast<GByte>((ctx->state[0] >> (24 - i * 8)) & 0x000000ffU);
190         hash[i + 4]  = static_cast<GByte>((ctx->state[1] >> (24 - i * 8)) & 0x000000ffU);
191         hash[i + 8]  = static_cast<GByte>((ctx->state[2] >> (24 - i * 8)) & 0x000000ffU);
192         hash[i + 12] = static_cast<GByte>((ctx->state[3] >> (24 - i * 8)) & 0x000000ffU);
193         hash[i + 16] = static_cast<GByte>((ctx->state[4] >> (24 - i * 8)) & 0x000000ffU);
194     }
195 }
196 
197 /************************************************************************/
198 /*                              CPL_SHA1()                              */
199 /************************************************************************/
200 
201 static
CPL_SHA1(const void * data,size_t len,GByte hash[CPL_SHA1_HASH_SIZE])202 void CPL_SHA1( const void *data, size_t len, GByte hash[CPL_SHA1_HASH_SIZE] )
203 {
204     CPL_SHA1Context sSHA1Ctxt;
205     CPL_SHA1Init(&sSHA1Ctxt);
206     CPL_SHA1Update(&sSHA1Ctxt, static_cast<const GByte*>(data), len);
207     CPL_SHA1Final(&sSHA1Ctxt, hash);
208     memset(&sSHA1Ctxt, 0, sizeof(sSHA1Ctxt));
209 }
210 
211 /************************************************************************/
212 /*                           CPL_HMAC_SHA1()                            */
213 /************************************************************************/
214 
215 #define CPL_HMAC_SHA1_BLOCKSIZE 64U
216 
217 // See https://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Implementation
CPL_HMAC_SHA1(const void * pKey,size_t nKeyLen,const void * pabyMessage,size_t nMessageLen,GByte abyDigest[CPL_SHA1_HASH_SIZE])218 void CPL_HMAC_SHA1(const void *pKey, size_t nKeyLen,
219                              const void *pabyMessage, size_t nMessageLen,
220                              GByte abyDigest[CPL_SHA1_HASH_SIZE])
221 {
222     GByte abyPad[CPL_HMAC_SHA1_BLOCKSIZE] = {};
223     if( nKeyLen > CPL_HMAC_SHA1_BLOCKSIZE )
224     {
225         CPL_SHA1(pKey, nKeyLen, abyPad);
226     }
227     else
228     {
229         memcpy(abyPad, pKey, nKeyLen);
230     }
231 
232     // Compute ipad.
233     for( size_t i = 0; i < CPL_HMAC_SHA1_BLOCKSIZE; i++ )
234         abyPad[i] = 0x36 ^ abyPad[i];
235 
236     CPL_SHA1Context sSHA1Ctxt;
237     CPL_SHA1Init(&sSHA1Ctxt);
238     CPL_SHA1Update(&sSHA1Ctxt, abyPad, CPL_HMAC_SHA1_BLOCKSIZE);
239     CPL_SHA1Update(&sSHA1Ctxt, static_cast<const GByte*>(pabyMessage),
240                    nMessageLen);
241     CPL_SHA1Final(&sSHA1Ctxt, abyDigest);
242 
243     // Compute opad.
244     for( size_t i = 0; i < CPL_HMAC_SHA1_BLOCKSIZE; i++ )
245         abyPad[i] = (0x36 ^ 0x5C) ^ abyPad[i];
246 
247     CPL_SHA1Init(&sSHA1Ctxt);
248     CPL_SHA1Update(&sSHA1Ctxt, abyPad, CPL_HMAC_SHA1_BLOCKSIZE);
249     CPL_SHA1Update(&sSHA1Ctxt, abyDigest, CPL_SHA1_HASH_SIZE);
250     CPL_SHA1Final(&sSHA1Ctxt, abyDigest);
251 
252     memset(&sSHA1Ctxt, 0, sizeof(sSHA1Ctxt));
253     memset(abyPad, 0, CPL_HMAC_SHA1_BLOCKSIZE);
254 }
255