]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - crypto/openssh/digest-libc.c
MFH (r263234, r263691, r266465, r290671, r290672, r290673, r290674,
[FreeBSD/stable/10.git] / crypto / openssh / digest-libc.c
1 /* $OpenBSD: digest-libc.c,v 1.2 2014/02/02 03:44:31 djm Exp $ */
2 /*
3  * Copyright (c) 2013 Damien Miller <djm@mindrot.org>
4  * Copyright (c) 2014 Markus Friedl.  All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 #include "includes.h"
20 __RCSID("$FreeBSD$");
21
22 #include <sys/types.h>
23 #include <limits.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <md5.h>
28 #include <rmd160.h>
29 #include <sha1.h>
30 #include <sha2.h>
31
32 #include "buffer.h"
33 #include "digest.h"
34
35 typedef void md_init_fn(void *mdctx);
36 typedef void md_update_fn(void *mdctx, const u_int8_t *m, size_t mlen);
37 typedef void md_final_fn(u_int8_t[], void *mdctx);
38
39 struct ssh_digest_ctx {
40         int alg;
41         void *mdctx;
42 };
43
44 struct ssh_digest {
45         int id;
46         const char *name;
47         size_t block_len;
48         size_t digest_len;
49         size_t ctx_len;
50         md_init_fn *md_init;
51         md_update_fn *md_update;
52         md_final_fn *md_final;
53 };
54
55 /* NB. Indexed directly by algorithm number */
56 const struct ssh_digest digests[SSH_DIGEST_MAX] = {
57         {
58                 SSH_DIGEST_MD5,
59                 "MD5",
60                 MD5_BLOCK_LENGTH,
61                 MD5_DIGEST_LENGTH,
62                 sizeof(MD5_CTX),
63                 (md_init_fn *) MD5Init,
64                 (md_update_fn *) MD5Update,
65                 (md_final_fn *) MD5Final
66         },
67         {
68                 SSH_DIGEST_RIPEMD160,
69                 "RIPEMD160",
70                 RMD160_BLOCK_LENGTH,
71                 RMD160_DIGEST_LENGTH,
72                 sizeof(RMD160_CTX),
73                 (md_init_fn *) RMD160Init,
74                 (md_update_fn *) RMD160Update,
75                 (md_final_fn *) RMD160Final
76         },
77         {
78                 SSH_DIGEST_SHA1,
79                 "SHA1",
80                 SHA1_BLOCK_LENGTH,
81                 SHA1_DIGEST_LENGTH,
82                 sizeof(SHA1_CTX),
83                 (md_init_fn *) SHA1Init,
84                 (md_update_fn *) SHA1Update,
85                 (md_final_fn *) SHA1Final
86         },
87         {
88                 SSH_DIGEST_SHA256,
89                 "SHA256",
90                 SHA256_BLOCK_LENGTH,
91                 SHA256_DIGEST_LENGTH,
92                 sizeof(SHA2_CTX),
93                 (md_init_fn *) SHA256Init,
94                 (md_update_fn *) SHA256Update,
95                 (md_final_fn *) SHA256Final
96         },
97         {
98                 SSH_DIGEST_SHA384,
99                 "SHA384",
100                 SHA384_BLOCK_LENGTH,
101                 SHA384_DIGEST_LENGTH,
102                 sizeof(SHA2_CTX),
103                 (md_init_fn *) SHA384Init,
104                 (md_update_fn *) SHA384Update,
105                 (md_final_fn *) SHA384Final
106         },
107         {
108                 SSH_DIGEST_SHA512,
109                 "SHA512",
110                 SHA512_BLOCK_LENGTH,
111                 SHA512_DIGEST_LENGTH,
112                 sizeof(SHA2_CTX),
113                 (md_init_fn *) SHA512Init,
114                 (md_update_fn *) SHA512Update,
115                 (md_final_fn *) SHA512Final
116         }
117 };
118
119 static const struct ssh_digest *
120 ssh_digest_by_alg(int alg)
121 {
122         if (alg < 0 || alg >= SSH_DIGEST_MAX)
123                 return NULL;
124         if (digests[alg].id != alg) /* sanity */
125                 return NULL;
126         return &(digests[alg]);
127 }
128
129 size_t
130 ssh_digest_bytes(int alg)
131 {
132         const struct ssh_digest *digest = ssh_digest_by_alg(alg);
133
134         return digest == NULL ? 0 : digest->digest_len;
135 }
136
137 size_t
138 ssh_digest_blocksize(struct ssh_digest_ctx *ctx)
139 {
140         const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
141
142         return digest == NULL ? 0 : digest->block_len;
143 }
144
145 struct ssh_digest_ctx *
146 ssh_digest_start(int alg)
147 {
148         const struct ssh_digest *digest = ssh_digest_by_alg(alg);
149         struct ssh_digest_ctx *ret;
150
151         if (digest == NULL || (ret = calloc(1, sizeof(*ret))) == NULL)
152                 return NULL;
153         if ((ret->mdctx = calloc(1, digest->ctx_len)) == NULL) {
154                 free(ret);
155                 return NULL;
156         }
157         ret->alg = alg;
158         digest->md_init(ret->mdctx);
159         return ret;
160 }
161
162 int
163 ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to)
164 {
165         const struct ssh_digest *digest = ssh_digest_by_alg(from->alg);
166
167         if (digest == NULL || from->alg != to->alg)
168                 return -1;
169         memcpy(to->mdctx, from->mdctx, digest->ctx_len);
170         return 0;
171 }
172
173 int
174 ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen)
175 {
176         const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
177
178         if (digest == NULL)
179                 return -1;
180         digest->md_update(ctx->mdctx, m, mlen);
181         return 0;
182 }
183
184 int
185 ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b)
186 {
187         return ssh_digest_update(ctx, buffer_ptr(b), buffer_len(b));
188 }
189
190 int
191 ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen)
192 {
193         const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
194
195         if (digest == NULL)
196                 return -1;
197         if (dlen > UINT_MAX)
198                 return -1;
199         if (dlen < digest->digest_len) /* No truncation allowed */
200                 return -1;
201         digest->md_final(d, ctx->mdctx);
202         return 0;
203 }
204
205 void
206 ssh_digest_free(struct ssh_digest_ctx *ctx)
207 {
208         const struct ssh_digest *digest;
209
210         if (ctx != NULL) {
211                 digest = ssh_digest_by_alg(ctx->alg);
212                 if (digest) {
213                         explicit_bzero(ctx->mdctx, digest->ctx_len);
214                         free(ctx->mdctx);
215                         explicit_bzero(ctx, sizeof(*ctx));
216                         free(ctx);
217                 }
218         }
219 }
220
221 int
222 ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen)
223 {
224         struct ssh_digest_ctx *ctx = ssh_digest_start(alg);
225
226         if (ctx == NULL)
227                 return -1;
228         if (ssh_digest_update(ctx, m, mlen) != 0 ||
229             ssh_digest_final(ctx, d, dlen) != 0)
230                 return -1;
231         ssh_digest_free(ctx);
232         return 0;
233 }
234
235 int
236 ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen)
237 {
238         return ssh_digest_memory(alg, buffer_ptr(b), buffer_len(b), d, dlen);
239 }