]>
Commit | Line | Data |
---|---|---|
1 | // SPDX-License-Identifier: GPL-2.0 OR MIT | |
2 | /* | |
3 | * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. | |
4 | * | |
5 | * This is an implementation of the BLAKE2s hash and PRF functions. | |
6 | * | |
7 | * Information: https://blake2.net/ | |
8 | * | |
9 | */ | |
10 | ||
11 | #include <crypto/internal/blake2s.h> | |
12 | #include <linux/types.h> | |
13 | #include <linux/string.h> | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/module.h> | |
16 | #include <linux/init.h> | |
17 | #include <linux/bug.h> | |
18 | #include <asm/unaligned.h> | |
19 | ||
20 | bool blake2s_selftest(void); | |
21 | ||
22 | void blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen) | |
23 | { | |
24 | const size_t fill = BLAKE2S_BLOCK_SIZE - state->buflen; | |
25 | ||
26 | if (unlikely(!inlen)) | |
27 | return; | |
28 | if (inlen > fill) { | |
29 | memcpy(state->buf + state->buflen, in, fill); | |
30 | if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S)) | |
31 | blake2s_compress_arch(state, state->buf, 1, | |
32 | BLAKE2S_BLOCK_SIZE); | |
33 | else | |
34 | blake2s_compress_generic(state, state->buf, 1, | |
35 | BLAKE2S_BLOCK_SIZE); | |
36 | state->buflen = 0; | |
37 | in += fill; | |
38 | inlen -= fill; | |
39 | } | |
40 | if (inlen > BLAKE2S_BLOCK_SIZE) { | |
41 | const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE); | |
42 | /* Hash one less (full) block than strictly possible */ | |
43 | if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S)) | |
44 | blake2s_compress_arch(state, in, nblocks - 1, | |
45 | BLAKE2S_BLOCK_SIZE); | |
46 | else | |
47 | blake2s_compress_generic(state, in, nblocks - 1, | |
48 | BLAKE2S_BLOCK_SIZE); | |
49 | in += BLAKE2S_BLOCK_SIZE * (nblocks - 1); | |
50 | inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1); | |
51 | } | |
52 | memcpy(state->buf + state->buflen, in, inlen); | |
53 | state->buflen += inlen; | |
54 | } | |
55 | EXPORT_SYMBOL(blake2s_update); | |
56 | ||
57 | void blake2s_final(struct blake2s_state *state, u8 *out) | |
58 | { | |
59 | WARN_ON(IS_ENABLED(DEBUG) && !out); | |
60 | blake2s_set_lastblock(state); | |
61 | memset(state->buf + state->buflen, 0, | |
62 | BLAKE2S_BLOCK_SIZE - state->buflen); /* Padding */ | |
63 | if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S)) | |
64 | blake2s_compress_arch(state, state->buf, 1, state->buflen); | |
65 | else | |
66 | blake2s_compress_generic(state, state->buf, 1, state->buflen); | |
67 | cpu_to_le32_array(state->h, ARRAY_SIZE(state->h)); | |
68 | memcpy(out, state->h, state->outlen); | |
69 | memzero_explicit(state, sizeof(*state)); | |
70 | } | |
71 | EXPORT_SYMBOL(blake2s_final); | |
72 | ||
73 | void blake2s256_hmac(u8 *out, const u8 *in, const u8 *key, const size_t inlen, | |
74 | const size_t keylen) | |
75 | { | |
76 | struct blake2s_state state; | |
77 | u8 x_key[BLAKE2S_BLOCK_SIZE] __aligned(__alignof__(u32)) = { 0 }; | |
78 | u8 i_hash[BLAKE2S_HASH_SIZE] __aligned(__alignof__(u32)); | |
79 | int i; | |
80 | ||
81 | if (keylen > BLAKE2S_BLOCK_SIZE) { | |
82 | blake2s_init(&state, BLAKE2S_HASH_SIZE); | |
83 | blake2s_update(&state, key, keylen); | |
84 | blake2s_final(&state, x_key); | |
85 | } else | |
86 | memcpy(x_key, key, keylen); | |
87 | ||
88 | for (i = 0; i < BLAKE2S_BLOCK_SIZE; ++i) | |
89 | x_key[i] ^= 0x36; | |
90 | ||
91 | blake2s_init(&state, BLAKE2S_HASH_SIZE); | |
92 | blake2s_update(&state, x_key, BLAKE2S_BLOCK_SIZE); | |
93 | blake2s_update(&state, in, inlen); | |
94 | blake2s_final(&state, i_hash); | |
95 | ||
96 | for (i = 0; i < BLAKE2S_BLOCK_SIZE; ++i) | |
97 | x_key[i] ^= 0x5c ^ 0x36; | |
98 | ||
99 | blake2s_init(&state, BLAKE2S_HASH_SIZE); | |
100 | blake2s_update(&state, x_key, BLAKE2S_BLOCK_SIZE); | |
101 | blake2s_update(&state, i_hash, BLAKE2S_HASH_SIZE); | |
102 | blake2s_final(&state, i_hash); | |
103 | ||
104 | memcpy(out, i_hash, BLAKE2S_HASH_SIZE); | |
105 | memzero_explicit(x_key, BLAKE2S_BLOCK_SIZE); | |
106 | memzero_explicit(i_hash, BLAKE2S_HASH_SIZE); | |
107 | } | |
108 | EXPORT_SYMBOL(blake2s256_hmac); | |
109 | ||
110 | static int __init mod_init(void) | |
111 | { | |
112 | if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) && | |
113 | WARN_ON(!blake2s_selftest())) | |
114 | return -ENODEV; | |
115 | return 0; | |
116 | } | |
117 | ||
118 | static void __exit mod_exit(void) | |
119 | { | |
120 | } | |
121 | ||
122 | module_init(mod_init); | |
123 | module_exit(mod_exit); | |
124 | MODULE_LICENSE("GPL v2"); | |
125 | MODULE_DESCRIPTION("BLAKE2s hash function"); | |
126 | MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>"); |