| /* |
| * FIPS-180-2 compliant SHA-256 implementation |
| * |
| * Copyright (C) 2001-2003 Christophe Devine |
| * |
| * SPDX-License-Identifier: GPL-2.0+ |
| */ |
| |
| #ifndef USE_HOSTCC |
| #include <common.h> |
| #endif /* USE_HOSTCC */ |
| #include <watchdog.h> |
| #include <linux/string.h> |
| #include <sha256.h> |
| |
| asmlinkage int neon_en_check(void); |
| asmlinkage void neon_enable(void); |
| asmlinkage void neon_disable(void); |
| asmlinkage void sha256_transform_neon(u32 *digest, const void *data, |
| unsigned int num_blks); |
| |
| /* |
| * 32-bit integer manipulation macros (big endian) |
| */ |
| #ifndef PUT_UINT32_BE |
| #define PUT_UINT32_BE(n,b,i) { \ |
| (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ |
| (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ |
| (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ |
| (b)[(i) + 3] = (unsigned char) ( (n) ); \ |
| } |
| #endif |
| |
| void sha256_starts_neon(sha256_context * ctx) |
| { |
| ctx->total[0] = 0; |
| ctx->total[1] = 0; |
| |
| ctx->state[0] = 0x6A09E667; |
| ctx->state[1] = 0xBB67AE85; |
| ctx->state[2] = 0x3C6EF372; |
| ctx->state[3] = 0xA54FF53A; |
| ctx->state[4] = 0x510E527F; |
| ctx->state[5] = 0x9B05688C; |
| ctx->state[6] = 0x1F83D9AB; |
| ctx->state[7] = 0x5BE0CD19; |
| } |
| |
| static inline void sha256_process(sha256_context *ctx, |
| const uint8_t *data, uint32_t blks) |
| { |
| int neon_en = neon_en_check(); |
| |
| if (!neon_en) |
| neon_enable(); |
| |
| sha256_transform_neon(ctx->state, data, blks); |
| |
| if (!neon_en) |
| neon_disable(); |
| } |
| |
| void sha256_update_neon(sha256_context *ctx, const uint8_t *input, uint32_t length) |
| { |
| uint32_t left, fill; |
| uint32_t blks; |
| |
| if (!length) |
| return; |
| |
| left = ctx->total[0] & 0x3F; |
| fill = 64 - left; |
| |
| ctx->total[0] += length; |
| ctx->total[0] &= 0xFFFFFFFF; |
| |
| if (ctx->total[0] < length) |
| ctx->total[1]++; |
| |
| if (left && length >= fill) { |
| memcpy((void *) (ctx->buffer + left), (void *) input, fill); |
| sha256_process(ctx, ctx->buffer, 1); |
| length -= fill; |
| input += fill; |
| left = 0; |
| } |
| |
| blks = length / 64; |
| while (length >= 64) { |
| sha256_process(ctx, input, blks); |
| length -= 64 * blks; |
| input += 64 * blks; |
| } |
| |
| if (length) |
| memcpy((void *) (ctx->buffer + left), (void *) input, length); |
| } |
| |
| static uint8_t sha256_padding[64] = { |
| 0x80, 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, 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, 0, 0, 0, 0, 0, 0, 0 |
| }; |
| |
| void sha256_finish_neon(sha256_context * ctx, uint8_t digest[32]) |
| { |
| uint32_t last, padn; |
| uint32_t high, low; |
| uint8_t msglen[8]; |
| |
| high = ((ctx->total[0] >> 29) |
| | (ctx->total[1] << 3)); |
| low = (ctx->total[0] << 3); |
| |
| PUT_UINT32_BE(high, msglen, 0); |
| PUT_UINT32_BE(low, msglen, 4); |
| |
| last = ctx->total[0] & 0x3F; |
| padn = (last < 56) ? (56 - last) : (120 - last); |
| |
| sha256_update(ctx, sha256_padding, padn); |
| sha256_update(ctx, msglen, 8); |
| |
| PUT_UINT32_BE(ctx->state[0], digest, 0); |
| PUT_UINT32_BE(ctx->state[1], digest, 4); |
| PUT_UINT32_BE(ctx->state[2], digest, 8); |
| PUT_UINT32_BE(ctx->state[3], digest, 12); |
| PUT_UINT32_BE(ctx->state[4], digest, 16); |
| PUT_UINT32_BE(ctx->state[5], digest, 20); |
| PUT_UINT32_BE(ctx->state[6], digest, 24); |
| PUT_UINT32_BE(ctx->state[7], digest, 28); |
| } |