Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/mfbt/SHA1.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "mozilla/Assertions.h"
8
#include "mozilla/EndianUtils.h"
9
#include "mozilla/SHA1.h"
10
11
#include <string.h>
12
13
using mozilla::NativeEndian;
14
using mozilla::SHA1Sum;
15
16
static inline uint32_t
17
SHA_ROTL(uint32_t aT, uint32_t aN)
18
0
{
19
0
  MOZ_ASSERT(aN < 32);
20
0
  return (aT << aN) | (aT >> (32 - aN));
21
0
}
22
23
static void
24
shaCompress(volatile unsigned* aX, const uint32_t* aBuf);
25
26
0
#define SHA_F1(X, Y, Z) ((((Y) ^ (Z)) & (X)) ^ (Z))
27
0
#define SHA_F2(X, Y, Z) ((X) ^ (Y) ^ (Z))
28
0
#define SHA_F3(X, Y, Z) (((X) & (Y)) | ((Z) & ((X) | (Y))))
29
0
#define SHA_F4(X, Y, Z) ((X) ^ (Y) ^ (Z))
30
31
0
#define SHA_MIX(n, a, b, c)    XW(n) = SHA_ROTL(XW(a) ^ XW(b) ^ XW(c) ^XW(n), 1)
32
33
SHA1Sum::SHA1Sum()
34
  : mSize(0), mDone(false)
35
0
{
36
0
  // Initialize H with constants from FIPS180-1.
37
0
  mH[0] = 0x67452301L;
38
0
  mH[1] = 0xefcdab89L;
39
0
  mH[2] = 0x98badcfeL;
40
0
  mH[3] = 0x10325476L;
41
0
  mH[4] = 0xc3d2e1f0L;
42
0
}
43
44
/*
45
 * Explanation of H array and index values:
46
 *
47
 * The context's H array is actually the concatenation of two arrays
48
 * defined by SHA1, the H array of state variables (5 elements),
49
 * and the W array of intermediate values, of which there are 16 elements.
50
 * The W array starts at H[5], that is W[0] is H[5].
51
 * Although these values are defined as 32-bit values, we use 64-bit
52
 * variables to hold them because the AMD64 stores 64 bit values in
53
 * memory MUCH faster than it stores any smaller values.
54
 *
55
 * Rather than passing the context structure to shaCompress, we pass
56
 * this combined array of H and W values.  We do not pass the address
57
 * of the first element of this array, but rather pass the address of an
58
 * element in the middle of the array, element X.  Presently X[0] is H[11].
59
 * So we pass the address of H[11] as the address of array X to shaCompress.
60
 * Then shaCompress accesses the members of the array using positive AND
61
 * negative indexes.
62
 *
63
 * Pictorially: (each element is 8 bytes)
64
 * H | H0 H1 H2 H3 H4 W0 W1 W2 W3 W4 W5 W6 W7 W8 W9 Wa Wb Wc Wd We Wf |
65
 * X |-11-10 -9 -8 -7 -6 -5 -4 -3 -2 -1 X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 |
66
 *
67
 * The byte offset from X[0] to any member of H and W is always
68
 * representable in a signed 8-bit value, which will be encoded
69
 * as a single byte offset in the X86-64 instruction set.
70
 * If we didn't pass the address of H[11], and instead passed the
71
 * address of H[0], the offsets to elements H[16] and above would be
72
 * greater than 127, not representable in a signed 8-bit value, and the
73
 * x86-64 instruction set would encode every such offset as a 32-bit
74
 * signed number in each instruction that accessed element H[16] or
75
 * higher.  This results in much bigger and slower code.
76
 */
77
0
#define H2X 11 /* X[0] is H[11], and H[0] is X[-11] */
78
0
#define W2X  6 /* X[0] is W[6],  and W[0] is X[-6]  */
79
80
/*
81
 *  SHA: Add data to context.
82
 */
83
void
84
SHA1Sum::update(const void* aData, uint32_t aLen)
85
0
{
86
0
  MOZ_ASSERT(!mDone, "SHA1Sum can only be used to compute a single hash.");
87
0
88
0
  const uint8_t* data = static_cast<const uint8_t*>(aData);
89
0
90
0
  if (aLen == 0) {
91
0
    return;
92
0
  }
93
0
94
0
  /* Accumulate the byte count. */
95
0
  unsigned int lenB = static_cast<unsigned int>(mSize) & 63U;
96
0
97
0
  mSize += aLen;
98
0
99
0
  /* Read the data into W and process blocks as they get full. */
100
0
  unsigned int togo;
101
0
  if (lenB > 0) {
102
0
    togo = 64U - lenB;
103
0
    if (aLen < togo) {
104
0
      togo = aLen;
105
0
    }
106
0
    memcpy(mU.mB + lenB, data, togo);
107
0
    aLen -= togo;
108
0
    data += togo;
109
0
    lenB = (lenB + togo) & 63U;
110
0
    if (!lenB) {
111
0
      shaCompress(&mH[H2X], mU.mW);
112
0
    }
113
0
  }
114
0
115
0
  while (aLen >= 64U) {
116
0
    aLen -= 64U;
117
0
    shaCompress(&mH[H2X], reinterpret_cast<const uint32_t*>(data));
118
0
    data += 64U;
119
0
  }
120
0
121
0
  if (aLen > 0) {
122
0
    memcpy(mU.mB, data, aLen);
123
0
  }
124
0
}
125
126
127
/*
128
 *  SHA: Generate hash value
129
 */
130
void
131
SHA1Sum::finish(SHA1Sum::Hash& aHashOut)
132
0
{
133
0
  MOZ_ASSERT(!mDone, "SHA1Sum can only be used to compute a single hash.");
134
0
135
0
  uint64_t size = mSize;
136
0
  uint32_t lenB = uint32_t(size) & 63;
137
0
138
0
  static const uint8_t bulk_pad[64] =
139
0
    { 0x80,0,0,0,0,0,0,0,0,0,
140
0
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
141
0
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
142
0
143
0
  /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length in bits. */
144
0
  update(bulk_pad, (((55 + 64) - lenB) & 63) + 1);
145
0
  MOZ_ASSERT((uint32_t(mSize) & 63) == 56);
146
0
147
0
  /* Convert size from bytes to bits. */
148
0
  size <<= 3;
149
0
  mU.mW[14] = NativeEndian::swapToBigEndian(uint32_t(size >> 32));
150
0
  mU.mW[15] = NativeEndian::swapToBigEndian(uint32_t(size));
151
0
  shaCompress(&mH[H2X], mU.mW);
152
0
153
0
  /* Output hash. */
154
0
  mU.mW[0] = NativeEndian::swapToBigEndian(mH[0]);
155
0
  mU.mW[1] = NativeEndian::swapToBigEndian(mH[1]);
156
0
  mU.mW[2] = NativeEndian::swapToBigEndian(mH[2]);
157
0
  mU.mW[3] = NativeEndian::swapToBigEndian(mH[3]);
158
0
  mU.mW[4] = NativeEndian::swapToBigEndian(mH[4]);
159
0
  memcpy(aHashOut, mU.mW, 20);
160
0
  mDone = true;
161
0
}
162
163
/*
164
 *  SHA: Compression function, unrolled.
165
 *
166
 * Some operations in shaCompress are done as 5 groups of 16 operations.
167
 * Others are done as 4 groups of 20 operations.
168
 * The code below shows that structure.
169
 *
170
 * The functions that compute the new values of the 5 state variables
171
 * A-E are done in 4 groups of 20 operations (or you may also think
172
 * of them as being done in 16 groups of 5 operations).  They are
173
 * done by the SHA_RNDx macros below, in the right column.
174
 *
175
 * The functions that set the 16 values of the W array are done in
176
 * 5 groups of 16 operations.  The first group is done by the
177
 * LOAD macros below, the latter 4 groups are done by SHA_MIX below,
178
 * in the left column.
179
 *
180
 * gcc's optimizer observes that each member of the W array is assigned
181
 * a value 5 times in this code.  It reduces the number of store
182
 * operations done to the W array in the context (that is, in the X array)
183
 * by creating a W array on the stack, and storing the W values there for
184
 * the first 4 groups of operations on W, and storing the values in the
185
 * context's W array only in the fifth group.  This is undesirable.
186
 * It is MUCH bigger code than simply using the context's W array, because
187
 * all the offsets to the W array in the stack are 32-bit signed offsets,
188
 * and it is no faster than storing the values in the context's W array.
189
 *
190
 * The original code for sha_fast.c prevented this creation of a separate
191
 * W array in the stack by creating a W array of 80 members, each of
192
 * whose elements is assigned only once. It also separated the computations
193
 * of the W array values and the computations of the values for the 5
194
 * state variables into two separate passes, W's, then A-E's so that the
195
 * second pass could be done all in registers (except for accessing the W
196
 * array) on machines with fewer registers.  The method is suboptimal
197
 * for machines with enough registers to do it all in one pass, and it
198
 * necessitates using many instructions with 32-bit offsets.
199
 *
200
 * This code eliminates the separate W array on the stack by a completely
201
 * different means: by declaring the X array volatile.  This prevents
202
 * the optimizer from trying to reduce the use of the X array by the
203
 * creation of a MORE expensive W array on the stack. The result is
204
 * that all instructions use signed 8-bit offsets and not 32-bit offsets.
205
 *
206
 * The combination of this code and the -O3 optimizer flag on GCC 3.4.3
207
 * results in code that is 3 times faster than the previous NSS sha_fast
208
 * code on AMD64.
209
 */
210
static void
211
shaCompress(volatile unsigned* aX, const uint32_t* aBuf)
212
0
{
213
0
  unsigned A, B, C, D, E;
214
0
215
0
#define XH(n) aX[n - H2X]
216
0
#define XW(n) aX[n - W2X]
217
0
218
0
#define K0 0x5a827999L
219
0
#define K1 0x6ed9eba1L
220
0
#define K2 0x8f1bbcdcL
221
0
#define K3 0xca62c1d6L
222
0
223
0
#define SHA_RND1(a, b, c, d, e, n) \
224
0
  a = SHA_ROTL(b, 5) + SHA_F1(c, d, e) + a + XW(n) + K0; c = SHA_ROTL(c, 30)
225
0
#define SHA_RND2(a, b, c, d, e, n) \
226
0
  a = SHA_ROTL(b, 5) + SHA_F2(c, d, e) + a + XW(n) + K1; c = SHA_ROTL(c, 30)
227
0
#define SHA_RND3(a, b, c, d, e, n) \
228
0
  a = SHA_ROTL(b, 5) + SHA_F3(c, d, e) + a + XW(n) + K2; c = SHA_ROTL(c, 30)
229
0
#define SHA_RND4(a, b, c, d, e, n) \
230
0
  a = SHA_ROTL(b ,5) + SHA_F4(c, d, e) + a + XW(n) + K3; c = SHA_ROTL(c, 30)
231
0
232
0
#define LOAD(n) XW(n) = NativeEndian::swapToBigEndian(aBuf[n])
233
0
234
0
  A = XH(0);
235
0
  B = XH(1);
236
0
  C = XH(2);
237
0
  D = XH(3);
238
0
  E = XH(4);
239
0
240
0
  LOAD(0);       SHA_RND1(E,A,B,C,D, 0);
241
0
  LOAD(1);       SHA_RND1(D,E,A,B,C, 1);
242
0
  LOAD(2);       SHA_RND1(C,D,E,A,B, 2);
243
0
  LOAD(3);       SHA_RND1(B,C,D,E,A, 3);
244
0
  LOAD(4);       SHA_RND1(A,B,C,D,E, 4);
245
0
  LOAD(5);       SHA_RND1(E,A,B,C,D, 5);
246
0
  LOAD(6);       SHA_RND1(D,E,A,B,C, 6);
247
0
  LOAD(7);       SHA_RND1(C,D,E,A,B, 7);
248
0
  LOAD(8);       SHA_RND1(B,C,D,E,A, 8);
249
0
  LOAD(9);       SHA_RND1(A,B,C,D,E, 9);
250
0
  LOAD(10);      SHA_RND1(E,A,B,C,D,10);
251
0
  LOAD(11);      SHA_RND1(D,E,A,B,C,11);
252
0
  LOAD(12);      SHA_RND1(C,D,E,A,B,12);
253
0
  LOAD(13);      SHA_RND1(B,C,D,E,A,13);
254
0
  LOAD(14);      SHA_RND1(A,B,C,D,E,14);
255
0
  LOAD(15);      SHA_RND1(E,A,B,C,D,15);
256
0
257
0
  SHA_MIX( 0, 13,  8,  2); SHA_RND1(D,E,A,B,C, 0);
258
0
  SHA_MIX( 1, 14,  9,  3); SHA_RND1(C,D,E,A,B, 1);
259
0
  SHA_MIX( 2, 15, 10,  4); SHA_RND1(B,C,D,E,A, 2);
260
0
  SHA_MIX( 3,  0, 11,  5); SHA_RND1(A,B,C,D,E, 3);
261
0
262
0
  SHA_MIX( 4,  1, 12,  6); SHA_RND2(E,A,B,C,D, 4);
263
0
  SHA_MIX( 5,  2, 13,  7); SHA_RND2(D,E,A,B,C, 5);
264
0
  SHA_MIX( 6,  3, 14,  8); SHA_RND2(C,D,E,A,B, 6);
265
0
  SHA_MIX( 7,  4, 15,  9); SHA_RND2(B,C,D,E,A, 7);
266
0
  SHA_MIX( 8,  5,  0, 10); SHA_RND2(A,B,C,D,E, 8);
267
0
  SHA_MIX( 9,  6,  1, 11); SHA_RND2(E,A,B,C,D, 9);
268
0
  SHA_MIX(10,  7,  2, 12); SHA_RND2(D,E,A,B,C,10);
269
0
  SHA_MIX(11,  8,  3, 13); SHA_RND2(C,D,E,A,B,11);
270
0
  SHA_MIX(12,  9,  4, 14); SHA_RND2(B,C,D,E,A,12);
271
0
  SHA_MIX(13, 10,  5, 15); SHA_RND2(A,B,C,D,E,13);
272
0
  SHA_MIX(14, 11,  6,  0); SHA_RND2(E,A,B,C,D,14);
273
0
  SHA_MIX(15, 12,  7,  1); SHA_RND2(D,E,A,B,C,15);
274
0
275
0
  SHA_MIX( 0, 13,  8,  2); SHA_RND2(C,D,E,A,B, 0);
276
0
  SHA_MIX( 1, 14,  9,  3); SHA_RND2(B,C,D,E,A, 1);
277
0
  SHA_MIX( 2, 15, 10,  4); SHA_RND2(A,B,C,D,E, 2);
278
0
  SHA_MIX( 3,  0, 11,  5); SHA_RND2(E,A,B,C,D, 3);
279
0
  SHA_MIX( 4,  1, 12,  6); SHA_RND2(D,E,A,B,C, 4);
280
0
  SHA_MIX( 5,  2, 13,  7); SHA_RND2(C,D,E,A,B, 5);
281
0
  SHA_MIX( 6,  3, 14,  8); SHA_RND2(B,C,D,E,A, 6);
282
0
  SHA_MIX( 7,  4, 15,  9); SHA_RND2(A,B,C,D,E, 7);
283
0
284
0
  SHA_MIX( 8,  5,  0, 10); SHA_RND3(E,A,B,C,D, 8);
285
0
  SHA_MIX( 9,  6,  1, 11); SHA_RND3(D,E,A,B,C, 9);
286
0
  SHA_MIX(10,  7,  2, 12); SHA_RND3(C,D,E,A,B,10);
287
0
  SHA_MIX(11,  8,  3, 13); SHA_RND3(B,C,D,E,A,11);
288
0
  SHA_MIX(12,  9,  4, 14); SHA_RND3(A,B,C,D,E,12);
289
0
  SHA_MIX(13, 10,  5, 15); SHA_RND3(E,A,B,C,D,13);
290
0
  SHA_MIX(14, 11,  6,  0); SHA_RND3(D,E,A,B,C,14);
291
0
  SHA_MIX(15, 12,  7,  1); SHA_RND3(C,D,E,A,B,15);
292
0
293
0
  SHA_MIX( 0, 13,  8,  2); SHA_RND3(B,C,D,E,A, 0);
294
0
  SHA_MIX( 1, 14,  9,  3); SHA_RND3(A,B,C,D,E, 1);
295
0
  SHA_MIX( 2, 15, 10,  4); SHA_RND3(E,A,B,C,D, 2);
296
0
  SHA_MIX( 3,  0, 11,  5); SHA_RND3(D,E,A,B,C, 3);
297
0
  SHA_MIX( 4,  1, 12,  6); SHA_RND3(C,D,E,A,B, 4);
298
0
  SHA_MIX( 5,  2, 13,  7); SHA_RND3(B,C,D,E,A, 5);
299
0
  SHA_MIX( 6,  3, 14,  8); SHA_RND3(A,B,C,D,E, 6);
300
0
  SHA_MIX( 7,  4, 15,  9); SHA_RND3(E,A,B,C,D, 7);
301
0
  SHA_MIX( 8,  5,  0, 10); SHA_RND3(D,E,A,B,C, 8);
302
0
  SHA_MIX( 9,  6,  1, 11); SHA_RND3(C,D,E,A,B, 9);
303
0
  SHA_MIX(10,  7,  2, 12); SHA_RND3(B,C,D,E,A,10);
304
0
  SHA_MIX(11,  8,  3, 13); SHA_RND3(A,B,C,D,E,11);
305
0
306
0
  SHA_MIX(12,  9,  4, 14); SHA_RND4(E,A,B,C,D,12);
307
0
  SHA_MIX(13, 10,  5, 15); SHA_RND4(D,E,A,B,C,13);
308
0
  SHA_MIX(14, 11,  6,  0); SHA_RND4(C,D,E,A,B,14);
309
0
  SHA_MIX(15, 12,  7,  1); SHA_RND4(B,C,D,E,A,15);
310
0
311
0
  SHA_MIX( 0, 13,  8,  2); SHA_RND4(A,B,C,D,E, 0);
312
0
  SHA_MIX( 1, 14,  9,  3); SHA_RND4(E,A,B,C,D, 1);
313
0
  SHA_MIX( 2, 15, 10,  4); SHA_RND4(D,E,A,B,C, 2);
314
0
  SHA_MIX( 3,  0, 11,  5); SHA_RND4(C,D,E,A,B, 3);
315
0
  SHA_MIX( 4,  1, 12,  6); SHA_RND4(B,C,D,E,A, 4);
316
0
  SHA_MIX( 5,  2, 13,  7); SHA_RND4(A,B,C,D,E, 5);
317
0
  SHA_MIX( 6,  3, 14,  8); SHA_RND4(E,A,B,C,D, 6);
318
0
  SHA_MIX( 7,  4, 15,  9); SHA_RND4(D,E,A,B,C, 7);
319
0
  SHA_MIX( 8,  5,  0, 10); SHA_RND4(C,D,E,A,B, 8);
320
0
  SHA_MIX( 9,  6,  1, 11); SHA_RND4(B,C,D,E,A, 9);
321
0
  SHA_MIX(10,  7,  2, 12); SHA_RND4(A,B,C,D,E,10);
322
0
  SHA_MIX(11,  8,  3, 13); SHA_RND4(E,A,B,C,D,11);
323
0
  SHA_MIX(12,  9,  4, 14); SHA_RND4(D,E,A,B,C,12);
324
0
  SHA_MIX(13, 10,  5, 15); SHA_RND4(C,D,E,A,B,13);
325
0
  SHA_MIX(14, 11,  6,  0); SHA_RND4(B,C,D,E,A,14);
326
0
  SHA_MIX(15, 12,  7,  1); SHA_RND4(A,B,C,D,E,15);
327
0
328
0
  XH(0) += A;
329
0
  XH(1) += B;
330
0
  XH(2) += C;
331
0
  XH(3) += D;
332
0
  XH(4) += E;
333
0
}