DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
sha1.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file sha1.cpp
6 * @brief SHA-1 implementation.
7 *
8 * On Arduino (ESP32) targets, delegates to mbedtls_sha1() which uses the
9 * hardware SHA accelerator in the ESP32 and is significantly faster than the
10 * software implementation.
11 *
12 * On native (x86) test targets, uses a portable software implementation so
13 * unit tests run without mbedTLS installed.
14 */
15
16#include "sha1.h"
17
18#ifdef ARDUINO
19
20// --- ESP32 / Arduino: use mbedTLS (hardware-accelerated on ESP32) ----------
21#include "mbedtls/sha1.h"
22#include <string.h>
23
24void sha1(const uint8_t *data, size_t len, uint8_t digest[SHA1_DIGEST_LEN])
25{
26 (void)mbedtls_sha1(data, len, digest);
27}
28
29#else
30
31// --- Native / test: software SHA-1, no external dependencies ---------------
32#include <string.h>
33
34// ---------------------------------------------------------------------------
35// Helpers
36// ---------------------------------------------------------------------------
37
38static inline uint32_t rot32(uint32_t x, int n)
39{
40 return (x << n) | (x >> (32 - n));
41}
42
43static inline uint32_t load_be32(const uint8_t *p)
44{
45 return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
46}
47
48static inline void store_be32(uint8_t *p, uint32_t v)
49{
50 p[0] = (uint8_t)(v >> 24);
51 p[1] = (uint8_t)(v >> 16);
52 p[2] = (uint8_t)(v >> 8);
53 p[3] = (uint8_t)(v);
54}
55
56// ---------------------------------------------------------------------------
57// SHA-1 block compression (processes one 64-byte block)
58// ---------------------------------------------------------------------------
59
60static void sha1_block(uint32_t h[5], const uint8_t block[64])
61{
62 // Message schedule: 16 big-endian words from the block, extended to 80 by
63 // XOR-and-rotate (the SHA-1 recurrence; the rotate-by-1 is what SHA-0 lacked).
64 uint32_t w[80];
65 for (int i = 0; i < 16; i++)
66 w[i] = load_be32(block + i * 4);
67 for (int i = 16; i < 80; i++)
68 w[i] = rot32(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
69
70 uint32_t a = h[0];
71 uint32_t b = h[1];
72 uint32_t c = h[2];
73 uint32_t d = h[3];
74 uint32_t e = h[4];
75
76 // 80 rounds in four 20-round regimes, each with its own mixing function f
77 // and constant k (FIPS 180-4 §6.1.2).
78 for (int i = 0; i < 80; i++)
79 {
80 uint32_t f;
81 uint32_t k;
82 if (i < 20)
83 {
84 f = (b & c) | (~b & d); // choice
85 k = 0x5A827999u;
86 }
87 else if (i < 40)
88 {
89 f = b ^ c ^ d; // parity
90 k = 0x6ED9EBA1u;
91 }
92 else if (i < 60)
93 {
94 f = (b & c) | (b & d) | (c & d); // majority
95 k = 0x8F1BBCDCu;
96 }
97 else
98 {
99 f = b ^ c ^ d; // parity
100 k = 0xCA62C1D6u;
101 }
102
103 // Round update; b is rotated 30 as it shifts into c.
104 uint32_t tmp = rot32(a, 5) + f + e + k + w[i];
105 e = d;
106 d = c;
107 c = rot32(b, 30);
108 b = a;
109 a = tmp;
110 }
111
112 h[0] += a;
113 h[1] += b;
114 h[2] += c;
115 h[3] += d;
116 h[4] += e;
117}
118
119// ---------------------------------------------------------------------------
120// Public API
121// ---------------------------------------------------------------------------
122
123void sha1(const uint8_t *data, size_t len, uint8_t digest[SHA1_DIGEST_LEN])
124{
125 uint32_t h[5] = {0x67452301u, 0xEFCDAB89u, 0x98BADCFEu, 0x10325476u, 0xC3D2E1F0u};
126
127 // Process full 64-byte blocks
128 size_t blocks = len / 64;
129 for (size_t i = 0; i < blocks; i++)
130 sha1_block(h, data + i * 64);
131
132 // Build the padded final block(s)
133 uint8_t pad[128] = {};
134 size_t tail = len - blocks * 64;
135 memcpy(pad, data + blocks * 64, tail);
136 pad[tail] = 0x80;
137
138 // Bit-length goes in the last 8 bytes of the final block
139 uint64_t bit_len = (uint64_t)len * 8;
140 uint8_t *bl = (tail < 56) ? pad + 56 : pad + 120;
141 for (int i = 7; i >= 0; i--, bit_len >>= 8)
142 bl[i] = (uint8_t)bit_len;
143
144 sha1_block(h, pad);
145 if (tail >= 56)
146 sha1_block(h, pad + 64);
147
148 for (int i = 0; i < 5; i++)
149 store_be32(digest + i * 4, h[i]);
150}
151
152#endif // ARDUINO
void sha1(const uint8_t *data, size_t len, uint8_t digest[SHA1_DIGEST_LEN])
Compute a SHA-1 digest over an arbitrary byte buffer.
Definition sha1.cpp:24
Software SHA-1 implementation - no platform dependencies.
#define SHA1_DIGEST_LEN
SHA-1 digest length in bytes.
Definition sha1.h:22