/* Copyright 2021 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "dcrypto.h" #include "endian.h" #include "internal.h" static void SHA1_transform(struct sha1_ctx *const ctx) { uint32_t W[80]; uint32_t A, B, C, D, E; size_t t; static const uint32_t K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; for (t = 0; t < 16; ++t) W[t] = be32toh(ctx->b32[t]); for (; t < 80; t++) W[t] = rol(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); A = ctx->state[0]; B = ctx->state[1]; C = ctx->state[2]; D = ctx->state[3]; E = ctx->state[4]; for (t = 0; t < 80; t++) { uint32_t tmp = rol(A, 5) + E + W[t]; if (t < 20) tmp += (D ^ (B & (C ^ D))) + K[0]; else if (t < 40) tmp += (B ^ C ^ D) + K[1]; else if (t < 60) tmp += ((B & C) | (D & (B | C))) + K[2]; else tmp += (B ^ C ^ D) + K[3]; E = D; D = C; C = rol(B, 30); B = A; A = tmp; } ctx->state[0] += A; ctx->state[1] += B; ctx->state[2] += C; ctx->state[3] += D; ctx->state[4] += E; } /** * Define aliases taking union type as parameter. This is safe * as union type has header in same place and is not less than original type. * Equal to: * void SHA1_init_as_hash(hash_ctx_t *const ctx) {SHA1_init(&ctx.sha1);} * but save some space for embedded uses. */ BUILD_ASSERT(sizeof(union hash_ctx) >= sizeof(struct sha1_ctx)); static void SHA1_init_as_hash(union hash_ctx *const ctx) __alias(SHA1_sw_init); static void SHA1_update_as_hash(union hash_ctx *const ctx, const void *data, size_t len) __alias(SHA1_sw_update); static const union sha_digests *SHA1_final_as_hash(union hash_ctx *const ctx) __alias(SHA1_sw_final); void SHA1_sw_init(struct sha1_ctx *const ctx) { static const struct hash_vtable sha1_vtab = { SHA1_init_as_hash, SHA1_update_as_hash, SHA1_final_as_hash, HMAC_sw_final, SHA1_DIGEST_SIZE, SHA1_BLOCK_SIZE, sizeof(struct sha1_ctx) }; static const uint32_t sha1_init[SHA1_DIGEST_WORDS] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; ctx->f = &sha1_vtab; memcpy(ctx->state, sha1_init, sizeof(ctx->state)); ctx->count = 0; } void SHA1_sw_update(struct sha1_ctx *const ctx, const void *data, size_t len) { size_t i = ctx->count & (SHA1_BLOCK_SIZE - 1); const uint8_t *p = (const uint8_t *)data; ctx->count += len; while (len--) { ctx->b8[i++] = *p++; if (i == SHA1_BLOCK_SIZE) { SHA1_transform(ctx); i = 0; } } } const struct sha1_digest *SHA1_sw_final(struct sha1_ctx *const ctx) { uint64_t cnt = (uint64_t)ctx->count * CHAR_BIT; size_t i = ctx->count & (SHA1_BLOCK_SIZE - 1); /** * append the bit '1' to the message which would be 0x80 if message * length is a multiple of 8 bits. */ ctx->b8[i++] = 0x80; /** * append 0 ≤ k < 512 bits '0', such that the resulting message length * in bits is congruent to −64 ≡ 448 (mod 512) */ if (i > (SHA1_BLOCK_SIZE - sizeof(cnt))) { /* current block won't fit length, so move to next */ while (i < SHA1_BLOCK_SIZE) ctx->b8[i++] = 0; SHA1_transform(ctx); i = 0; } /* pad rest of zeros */ while (i < (SHA1_BLOCK_SIZE - sizeof(cnt))) ctx->b8[i++] = 0; /* place big-endian 64-bit bit counter at the end of block */ ctx->b64[SHA1_BLOCK_DWORDS - 1] = htobe64(cnt); SHA1_transform(ctx); for (i = 0; i < 5; i++) ctx->b32[i] = htobe32(ctx->state[i]); return &ctx->digest; } /* One shot SHA1 calculation */ const struct sha1_digest *SHA1_sw_hash(const void *data, size_t len, struct sha1_digest *digest) { struct sha1_ctx ctx; SHA1_sw_init(&ctx); SHA1_sw_update(&ctx, data, len); memcpy(digest->b8, SHA1_sw_final(&ctx)->b8, SHA1_DIGEST_SIZE); return digest; }