Annotation of src/usr.bin/ssh/digest-libc.c, Revision 1.2
1.2 ! djm 1: /* $OpenBSD: digest-libc.c,v 1.1 2014/01/28 20:13:46 markus Exp $ */
1.1 markus 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 <sys/types.h>
20: #include <limits.h>
21: #include <stdlib.h>
22: #include <string.h>
23:
24: #include <md5.h>
25: #include <rmd160.h>
26: #include <sha1.h>
27: #include <sha2.h>
28:
29: #include "buffer.h"
30: #include "digest.h"
31:
32: typedef void md_init_fn(void *mdctx);
33: typedef void md_update_fn(void *mdctx, const u_int8_t *m, size_t mlen);
34: typedef void md_final_fn(u_int8_t[], void *mdctx);
35:
36: struct ssh_digest_ctx {
37: int alg;
38: void *mdctx;
39: };
40:
41: struct ssh_digest {
42: int id;
43: const char *name;
44: size_t block_len;
45: size_t digest_len;
46: size_t ctx_len;
47: md_init_fn *md_init;
48: md_update_fn *md_update;
49: md_final_fn *md_final;
50: };
51:
52: /* NB. Indexed directly by algorithm number */
53: const struct ssh_digest digests[SSH_DIGEST_MAX] = {
54: {
55: SSH_DIGEST_MD5,
56: "MD5",
57: MD5_BLOCK_LENGTH,
58: MD5_DIGEST_LENGTH,
59: sizeof(MD5_CTX),
60: (md_init_fn *) MD5Init,
61: (md_update_fn *) MD5Update,
62: (md_final_fn *) MD5Final
63: },
64: {
65: SSH_DIGEST_RIPEMD160,
66: "RIPEMD160",
67: RMD160_BLOCK_LENGTH,
68: RMD160_DIGEST_LENGTH,
69: sizeof(RMD160_CTX),
70: (md_init_fn *) RMD160Init,
71: (md_update_fn *) RMD160Update,
72: (md_final_fn *) RMD160Final
73: },
74: {
75: SSH_DIGEST_SHA1,
76: "SHA1",
77: SHA1_BLOCK_LENGTH,
78: SHA1_DIGEST_LENGTH,
79: sizeof(SHA1_CTX),
80: (md_init_fn *) SHA1Init,
81: (md_update_fn *) SHA1Update,
82: (md_final_fn *) SHA1Final
83: },
84: {
85: SSH_DIGEST_SHA256,
86: "SHA256",
87: SHA256_BLOCK_LENGTH,
88: SHA256_DIGEST_LENGTH,
89: sizeof(SHA2_CTX),
90: (md_init_fn *) SHA256Init,
91: (md_update_fn *) SHA256Update,
92: (md_final_fn *) SHA256Final
93: },
94: {
95: SSH_DIGEST_SHA384,
96: "SHA384",
97: SHA384_BLOCK_LENGTH,
98: SHA384_DIGEST_LENGTH,
99: sizeof(SHA2_CTX),
100: (md_init_fn *) SHA384Init,
101: (md_update_fn *) SHA384Update,
102: (md_final_fn *) SHA384Final
103: },
104: {
105: SSH_DIGEST_SHA512,
106: "SHA512",
107: SHA512_BLOCK_LENGTH,
108: SHA512_DIGEST_LENGTH,
109: sizeof(SHA2_CTX),
110: (md_init_fn *) SHA512Init,
111: (md_update_fn *) SHA512Update,
112: (md_final_fn *) SHA512Final
113: }
114: };
115:
116: static const struct ssh_digest *
117: ssh_digest_by_alg(int alg)
118: {
119: if (alg < 0 || alg >= SSH_DIGEST_MAX)
120: return NULL;
121: if (digests[alg].id != alg) /* sanity */
122: return NULL;
123: return &(digests[alg]);
124: }
125:
126: size_t
127: ssh_digest_bytes(int alg)
128: {
129: const struct ssh_digest *digest = ssh_digest_by_alg(alg);
130:
131: return digest == NULL ? 0 : digest->digest_len;
132: }
133:
134: size_t
135: ssh_digest_blocksize(struct ssh_digest_ctx *ctx)
136: {
137: const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
138:
139: return digest == NULL ? 0 : digest->block_len;
140: }
141:
142: struct ssh_digest_ctx *
143: ssh_digest_start(int alg)
144: {
145: const struct ssh_digest *digest = ssh_digest_by_alg(alg);
146: struct ssh_digest_ctx *ret;
147:
148: if (digest == NULL || (ret = calloc(1, sizeof(ret))) == NULL)
149: return NULL;
150: if ((ret->mdctx = calloc(1, digest->ctx_len)) == NULL) {
151: free(ret);
152: return NULL;
153: }
154: ret->alg = alg;
155: digest->md_init(ret->mdctx);
156: return ret;
157: }
158:
159: int
160: ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to)
161: {
162: const struct ssh_digest *digest = ssh_digest_by_alg(from->alg);
163:
164: if (digest == NULL || from->alg != to->alg)
165: return -1;
166: memcpy(to->mdctx, from->mdctx, digest->ctx_len);
167: return 0;
168: }
169:
170: int
171: ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen)
172: {
173: const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
174:
175: if (digest == NULL)
176: return -1;
177: digest->md_update(ctx->mdctx, m, mlen);
178: return 0;
179: }
180:
181: int
182: ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b)
183: {
184: return ssh_digest_update(ctx, buffer_ptr(b), buffer_len(b));
185: }
186:
187: int
188: ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen)
189: {
190: const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
191:
192: if (digest == NULL)
193: return -1;
194: if (dlen > UINT_MAX)
195: return -1;
196: if (dlen < digest->digest_len) /* No truncation allowed */
197: return -1;
198: digest->md_final(d, ctx->mdctx);
199: return 0;
200: }
201:
202: void
203: ssh_digest_free(struct ssh_digest_ctx *ctx)
204: {
205: const struct ssh_digest *digest;
206:
207: if (ctx != NULL) {
208: digest = ssh_digest_by_alg(ctx->alg);
209: if (digest) {
1.2 ! djm 210: explicit_bzero(ctx->mdctx, digest->ctx_len);
1.1 markus 211: free(ctx->mdctx);
1.2 ! djm 212: explicit_bzero(ctx, sizeof(*ctx));
1.1 markus 213: free(ctx);
214: }
215: }
216: }
217:
218: int
219: ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen)
220: {
221: struct ssh_digest_ctx *ctx = ssh_digest_start(alg);
222:
223: if (ctx == NULL)
224: return -1;
225: if (ssh_digest_update(ctx, m, mlen) != 0 ||
226: ssh_digest_final(ctx, d, dlen) != 0)
227: return -1;
228: ssh_digest_free(ctx);
229: return 0;
230: }
231:
232: int
233: ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen)
234: {
235: return ssh_digest_memory(alg, buffer_ptr(b), buffer_len(b), d, dlen);
236: }