Line | Count | Source (jump to first uncovered line) |
1 | | /* $OpenBSD: hmac.c,v 1.14 2020/02/26 13:40:09 jsg Exp $ */ |
2 | | /* |
3 | | * Copyright (c) 2014 Markus Friedl. All rights reserved. |
4 | | * |
5 | | * Permission to use, copy, modify, and distribute this software for any |
6 | | * purpose with or without fee is hereby granted, provided that the above |
7 | | * copyright notice and this permission notice appear in all copies. |
8 | | * |
9 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 | | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 | | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 | | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | | */ |
17 | | |
18 | | #include "includes.h" |
19 | | |
20 | | #include <sys/types.h> |
21 | | |
22 | | #include <stdlib.h> |
23 | | #include <string.h> |
24 | | |
25 | | #include "sshbuf.h" |
26 | | #include "digest.h" |
27 | | #include "hmac.h" |
28 | | |
29 | | struct ssh_hmac_ctx { |
30 | | int alg; |
31 | | struct ssh_digest_ctx *ictx; |
32 | | struct ssh_digest_ctx *octx; |
33 | | struct ssh_digest_ctx *digest; |
34 | | u_char *buf; |
35 | | size_t buf_len; |
36 | | }; |
37 | | |
38 | | size_t |
39 | | ssh_hmac_bytes(int alg) |
40 | 39 | { |
41 | 39 | return ssh_digest_bytes(alg); |
42 | 39 | } |
43 | | |
44 | | struct ssh_hmac_ctx * |
45 | | ssh_hmac_start(int alg) |
46 | 39 | { |
47 | 39 | struct ssh_hmac_ctx *ret; |
48 | | |
49 | 39 | if ((ret = calloc(1, sizeof(*ret))) == NULL) |
50 | 0 | return NULL; |
51 | 39 | ret->alg = alg; |
52 | 39 | if ((ret->ictx = ssh_digest_start(alg)) == NULL || |
53 | 39 | (ret->octx = ssh_digest_start(alg)) == NULL || |
54 | 39 | (ret->digest = ssh_digest_start(alg)) == NULL) |
55 | 0 | goto fail; |
56 | 39 | ret->buf_len = ssh_digest_blocksize(ret->ictx); |
57 | 39 | if ((ret->buf = calloc(1, ret->buf_len)) == NULL) |
58 | 0 | goto fail; |
59 | 39 | return ret; |
60 | 0 | fail: |
61 | 0 | ssh_hmac_free(ret); |
62 | 0 | return NULL; |
63 | 39 | } |
64 | | |
65 | | int |
66 | | ssh_hmac_init(struct ssh_hmac_ctx *ctx, const void *key, size_t klen) |
67 | 0 | { |
68 | 0 | size_t i; |
69 | | |
70 | | /* reset ictx and octx if no is key given */ |
71 | 0 | if (key != NULL) { |
72 | | /* truncate long keys */ |
73 | 0 | if (klen <= ctx->buf_len) |
74 | 0 | memcpy(ctx->buf, key, klen); |
75 | 0 | else if (ssh_digest_memory(ctx->alg, key, klen, ctx->buf, |
76 | 0 | ctx->buf_len) < 0) |
77 | 0 | return -1; |
78 | 0 | for (i = 0; i < ctx->buf_len; i++) |
79 | 0 | ctx->buf[i] ^= 0x36; |
80 | 0 | if (ssh_digest_update(ctx->ictx, ctx->buf, ctx->buf_len) < 0) |
81 | 0 | return -1; |
82 | 0 | for (i = 0; i < ctx->buf_len; i++) |
83 | 0 | ctx->buf[i] ^= 0x36 ^ 0x5c; |
84 | 0 | if (ssh_digest_update(ctx->octx, ctx->buf, ctx->buf_len) < 0) |
85 | 0 | return -1; |
86 | 0 | explicit_bzero(ctx->buf, ctx->buf_len); |
87 | 0 | } |
88 | | /* start with ictx */ |
89 | 0 | if (ssh_digest_copy_state(ctx->ictx, ctx->digest) < 0) |
90 | 0 | return -1; |
91 | 0 | return 0; |
92 | 0 | } |
93 | | |
94 | | int |
95 | | ssh_hmac_update(struct ssh_hmac_ctx *ctx, const void *m, size_t mlen) |
96 | 0 | { |
97 | 0 | return ssh_digest_update(ctx->digest, m, mlen); |
98 | 0 | } |
99 | | |
100 | | int |
101 | | ssh_hmac_update_buffer(struct ssh_hmac_ctx *ctx, const struct sshbuf *b) |
102 | 0 | { |
103 | 0 | return ssh_digest_update_buffer(ctx->digest, b); |
104 | 0 | } |
105 | | |
106 | | int |
107 | | ssh_hmac_final(struct ssh_hmac_ctx *ctx, u_char *d, size_t dlen) |
108 | 0 | { |
109 | 0 | size_t len; |
110 | |
|
111 | 0 | len = ssh_digest_bytes(ctx->alg); |
112 | 0 | if (dlen < len || |
113 | 0 | ssh_digest_final(ctx->digest, ctx->buf, len)) |
114 | 0 | return -1; |
115 | | /* switch to octx */ |
116 | 0 | if (ssh_digest_copy_state(ctx->octx, ctx->digest) < 0 || |
117 | 0 | ssh_digest_update(ctx->digest, ctx->buf, len) < 0 || |
118 | 0 | ssh_digest_final(ctx->digest, d, dlen) < 0) |
119 | 0 | return -1; |
120 | 0 | return 0; |
121 | 0 | } |
122 | | |
123 | | void |
124 | | ssh_hmac_free(struct ssh_hmac_ctx *ctx) |
125 | 39 | { |
126 | 39 | if (ctx != NULL) { |
127 | 39 | ssh_digest_free(ctx->ictx); |
128 | 39 | ssh_digest_free(ctx->octx); |
129 | 39 | ssh_digest_free(ctx->digest); |
130 | 39 | if (ctx->buf) { |
131 | 39 | explicit_bzero(ctx->buf, ctx->buf_len); |
132 | 39 | free(ctx->buf); |
133 | 39 | } |
134 | 39 | freezero(ctx, sizeof(*ctx)); |
135 | 39 | } |
136 | 39 | } |
137 | | |
138 | | #ifdef TEST |
139 | | |
140 | | /* cc -DTEST hmac.c digest.c buffer.c cleanup.c fatal.c log.c xmalloc.c -lcrypto */ |
141 | | static void |
142 | | hmac_test(void *key, size_t klen, void *m, size_t mlen, u_char *e, size_t elen) |
143 | | { |
144 | | struct ssh_hmac_ctx *ctx; |
145 | | size_t i; |
146 | | u_char digest[16]; |
147 | | |
148 | | if ((ctx = ssh_hmac_start(SSH_DIGEST_MD5)) == NULL) |
149 | | printf("ssh_hmac_start failed"); |
150 | | if (ssh_hmac_init(ctx, key, klen) < 0 || |
151 | | ssh_hmac_update(ctx, m, mlen) < 0 || |
152 | | ssh_hmac_final(ctx, digest, sizeof(digest)) < 0) |
153 | | printf("ssh_hmac_xxx failed"); |
154 | | ssh_hmac_free(ctx); |
155 | | |
156 | | if (memcmp(e, digest, elen)) { |
157 | | for (i = 0; i < elen; i++) |
158 | | printf("[%zu] %2.2x %2.2x\n", i, e[i], digest[i]); |
159 | | printf("mismatch\n"); |
160 | | } else |
161 | | printf("ok\n"); |
162 | | } |
163 | | |
164 | | int |
165 | | main(int argc, char **argv) |
166 | | { |
167 | | /* try test vectors from RFC 2104 */ |
168 | | |
169 | | u_char key1[16] = { |
170 | | 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, |
171 | | 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb }; |
172 | | u_char *data1 = "Hi There"; |
173 | | u_char dig1[16] = { |
174 | | 0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c, |
175 | | 0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d }; |
176 | | |
177 | | u_char *key2 = "Jefe"; |
178 | | u_char *data2 = "what do ya want for nothing?"; |
179 | | u_char dig2[16] = { |
180 | | 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03, |
181 | | 0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38 }; |
182 | | |
183 | | u_char key3[16]; |
184 | | u_char data3[50]; |
185 | | u_char dig3[16] = { |
186 | | 0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88, |
187 | | 0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6 }; |
188 | | memset(key3, 0xaa, sizeof(key3)); |
189 | | memset(data3, 0xdd, sizeof(data3)); |
190 | | |
191 | | hmac_test(key1, sizeof(key1), data1, strlen(data1), dig1, sizeof(dig1)); |
192 | | hmac_test(key2, strlen(key2), data2, strlen(data2), dig2, sizeof(dig2)); |
193 | | hmac_test(key3, sizeof(key3), data3, sizeof(data3), dig3, sizeof(dig3)); |
194 | | |
195 | | return 0; |
196 | | } |
197 | | |
198 | | #endif |