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