1 /* $OpenBSD: digest-libc.c,v 1.7 2020/02/26 13:40:09 jsg Exp $ */
3 * Copyright (c) 2013 Damien Miller <djm@mindrot.org>
4 * Copyright (c) 2014 Markus Friedl. All rights reserved.
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.
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.
23 #include <sys/types.h>
39 #if !defined(SHA256_BLOCK_LENGTH) && defined(SHA256_HMAC_BLOCK_SIZE)
40 #define SHA256_BLOCK_LENGTH SHA256_HMAC_BLOCK_SIZE
42 #if !defined(SHA384_BLOCK_LENGTH) && defined(SHA512_HMAC_BLOCK_SIZE)
43 #define SHA384_BLOCK_LENGTH SHA512_HMAC_BLOCK_SIZE
45 #if !defined(SHA512_BLOCK_LENGTH) && defined(SHA512_HMAC_BLOCK_SIZE)
46 #define SHA512_BLOCK_LENGTH SHA512_HMAC_BLOCK_SIZE
53 typedef void md_init_fn(void *mdctx
);
54 typedef void md_update_fn(void *mdctx
, const u_int8_t
*m
, size_t mlen
);
55 typedef void md_final_fn(u_int8_t
[], void *mdctx
);
57 struct ssh_digest_ctx
{
69 md_update_fn
*md_update
;
70 md_final_fn
*md_final
;
73 /* NB. Indexed directly by algorithm number */
74 const struct ssh_digest digests
[SSH_DIGEST_MAX
] = {
81 (md_init_fn
*) MD5Init
,
82 (md_update_fn
*) MD5Update
,
83 (md_final_fn
*) MD5Final
91 (md_init_fn
*) SHA1Init
,
92 (md_update_fn
*) SHA1Update
,
93 (md_final_fn
*) SHA1Final
101 (md_init_fn
*) SHA256Init
,
102 (md_update_fn
*) SHA256Update
,
103 (md_final_fn
*) SHA256Final
109 SHA384_DIGEST_LENGTH
,
111 (md_init_fn
*) SHA384Init
,
112 (md_update_fn
*) SHA384Update
,
113 (md_final_fn
*) SHA384Final
119 SHA512_DIGEST_LENGTH
,
121 (md_init_fn
*) SHA512Init
,
122 (md_update_fn
*) SHA512Update
,
123 (md_final_fn
*) SHA512Final
127 static const struct ssh_digest
*
128 ssh_digest_by_alg(int alg
)
130 if (alg
< 0 || alg
>= SSH_DIGEST_MAX
)
132 if (digests
[alg
].id
!= alg
) /* sanity */
134 return &(digests
[alg
]);
138 ssh_digest_alg_by_name(const char *name
)
142 for (alg
= 0; alg
< SSH_DIGEST_MAX
; alg
++) {
143 if (strcasecmp(name
, digests
[alg
].name
) == 0)
144 return digests
[alg
].id
;
150 ssh_digest_alg_name(int alg
)
152 const struct ssh_digest
*digest
= ssh_digest_by_alg(alg
);
154 return digest
== NULL
? NULL
: digest
->name
;
158 ssh_digest_bytes(int alg
)
160 const struct ssh_digest
*digest
= ssh_digest_by_alg(alg
);
162 return digest
== NULL
? 0 : digest
->digest_len
;
166 ssh_digest_blocksize(struct ssh_digest_ctx
*ctx
)
168 const struct ssh_digest
*digest
= ssh_digest_by_alg(ctx
->alg
);
170 return digest
== NULL
? 0 : digest
->block_len
;
173 struct ssh_digest_ctx
*
174 ssh_digest_start(int alg
)
176 const struct ssh_digest
*digest
= ssh_digest_by_alg(alg
);
177 struct ssh_digest_ctx
*ret
;
179 if (digest
== NULL
|| (ret
= calloc(1, sizeof(*ret
))) == NULL
)
181 if ((ret
->mdctx
= calloc(1, digest
->ctx_len
)) == NULL
) {
186 digest
->md_init(ret
->mdctx
);
191 ssh_digest_copy_state(struct ssh_digest_ctx
*from
, struct ssh_digest_ctx
*to
)
193 const struct ssh_digest
*digest
= ssh_digest_by_alg(from
->alg
);
195 if (digest
== NULL
|| from
->alg
!= to
->alg
)
196 return SSH_ERR_INVALID_ARGUMENT
;
197 memcpy(to
->mdctx
, from
->mdctx
, digest
->ctx_len
);
202 ssh_digest_update(struct ssh_digest_ctx
*ctx
, const void *m
, size_t mlen
)
204 const struct ssh_digest
*digest
= ssh_digest_by_alg(ctx
->alg
);
207 return SSH_ERR_INVALID_ARGUMENT
;
208 digest
->md_update(ctx
->mdctx
, m
, mlen
);
213 ssh_digest_update_buffer(struct ssh_digest_ctx
*ctx
, const struct sshbuf
*b
)
215 return ssh_digest_update(ctx
, sshbuf_ptr(b
), sshbuf_len(b
));
219 ssh_digest_final(struct ssh_digest_ctx
*ctx
, u_char
*d
, size_t dlen
)
221 const struct ssh_digest
*digest
= ssh_digest_by_alg(ctx
->alg
);
224 return SSH_ERR_INVALID_ARGUMENT
;
226 return SSH_ERR_INVALID_ARGUMENT
;
227 if (dlen
< digest
->digest_len
) /* No truncation allowed */
228 return SSH_ERR_INVALID_ARGUMENT
;
229 digest
->md_final(d
, ctx
->mdctx
);
234 ssh_digest_free(struct ssh_digest_ctx
*ctx
)
236 const struct ssh_digest
*digest
;
239 digest
= ssh_digest_by_alg(ctx
->alg
);
241 explicit_bzero(ctx
->mdctx
, digest
->ctx_len
);
243 freezero(ctx
, sizeof(*ctx
));
249 ssh_digest_memory(int alg
, const void *m
, size_t mlen
, u_char
*d
, size_t dlen
)
251 struct ssh_digest_ctx
*ctx
= ssh_digest_start(alg
);
254 return SSH_ERR_INVALID_ARGUMENT
;
255 if (ssh_digest_update(ctx
, m
, mlen
) != 0 ||
256 ssh_digest_final(ctx
, d
, dlen
) != 0)
257 return SSH_ERR_INVALID_ARGUMENT
;
258 ssh_digest_free(ctx
);
263 ssh_digest_buffer(int alg
, const struct sshbuf
*b
, u_char
*d
, size_t dlen
)
265 return ssh_digest_memory(alg
, sshbuf_ptr(b
), sshbuf_len(b
), d
, dlen
);
267 #endif /* !WITH_OPENSSL */