Annotation of src/usr.bin/ssh/digest.c, Revision 1.1
1.1 ! djm 1: /* $OpenBSD$ */
! 2: /*
! 3: * Copyright (c) 2013 Damien Miller <djm@mindrot.org>
! 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 <sys/types.h>
! 19: #include <limits.h>
! 20: #include <stdlib.h>
! 21: #include <string.h>
! 22:
! 23: #include <openssl/bn.h> /* for buffer.h */
! 24: #include <openssl/ec.h> /* for buffer.h */
! 25: #include <openssl/evp.h>
! 26:
! 27: #include "buffer.h"
! 28: #include "digest.h"
! 29:
! 30: struct ssh_digest_ctx {
! 31: int alg;
! 32: EVP_MD_CTX mdctx;
! 33: };
! 34:
! 35: struct ssh_digest {
! 36: int id;
! 37: const char *name;
! 38: size_t digest_len;
! 39: const EVP_MD *(*mdfunc)(void);
! 40: };
! 41:
! 42: /* NB. Indexed directly by algorithm number */
! 43: const struct ssh_digest digests[] = {
! 44: { SSH_DIGEST_MD5, "MD5", 16, EVP_md5 },
! 45: { SSH_DIGEST_RIPEMD160, "RIPEMD160", 20, EVP_ripemd160 },
! 46: { SSH_DIGEST_SHA1, "SHA1", 20, EVP_sha1 },
! 47: { SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 },
! 48: { SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 },
! 49: { SSH_DIGEST_SHA512, "SHA512", 64, EVP_sha512 },
! 50: { -1, NULL, 0, NULL },
! 51: };
! 52:
! 53: static const struct ssh_digest *
! 54: ssh_digest_by_alg(int alg)
! 55: {
! 56: if (alg < 0 || alg >= SSH_DIGEST_MAX)
! 57: return NULL;
! 58: if (digests[alg].id != alg) /* sanity */
! 59: return NULL;
! 60: return &(digests[alg]);
! 61: }
! 62:
! 63: size_t
! 64: ssh_digest_bytes(int alg)
! 65: {
! 66: const struct ssh_digest *digest = ssh_digest_by_alg(alg);
! 67:
! 68: return digest == NULL ? 0 : digest->digest_len;
! 69: }
! 70:
! 71: struct ssh_digest_ctx *
! 72: ssh_digest_start(int alg)
! 73: {
! 74: const struct ssh_digest *digest = ssh_digest_by_alg(alg);
! 75: struct ssh_digest_ctx *ret;
! 76:
! 77: if (digest == NULL || ((ret = calloc(1, sizeof(*ret))) == NULL))
! 78: return NULL;
! 79: ret->alg = alg;
! 80: EVP_MD_CTX_init(&ret->mdctx);
! 81: if (EVP_DigestInit_ex(&ret->mdctx, digest->mdfunc(), NULL) != 1) {
! 82: free(ret);
! 83: return NULL;
! 84: }
! 85: return ret;
! 86: }
! 87:
! 88: int
! 89: ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen)
! 90: {
! 91: if (EVP_DigestUpdate(&ctx->mdctx, m, mlen) != 1)
! 92: return -1;
! 93: return 0;
! 94: }
! 95:
! 96: int
! 97: ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b)
! 98: {
! 99: return ssh_digest_update(ctx, buffer_ptr(b), buffer_len(b));
! 100: }
! 101:
! 102: int
! 103: ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen)
! 104: {
! 105: const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
! 106: u_int l = dlen;
! 107:
! 108: if (dlen > UINT_MAX)
! 109: return -1;
! 110: if (dlen < digest->digest_len) /* No truncation allowed */
! 111: return -1;
! 112: if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1)
! 113: return -1;
! 114: if (l != digest->digest_len) /* sanity */
! 115: return -1;
! 116: return 0;
! 117: }
! 118:
! 119: void
! 120: ssh_digest_free(struct ssh_digest_ctx *ctx)
! 121: {
! 122: EVP_MD_CTX_cleanup(&ctx->mdctx);
! 123: memset(ctx, 0, sizeof(*ctx));
! 124: }
! 125:
! 126: int
! 127: ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen)
! 128: {
! 129: struct ssh_digest_ctx *ctx = ssh_digest_start(alg);
! 130:
! 131: if (ctx == NULL)
! 132: return -1;
! 133: if (ssh_digest_update(ctx, m, mlen) != 0 ||
! 134: ssh_digest_final(ctx, d, dlen) != 0)
! 135: return -1;
! 136: ssh_digest_free(ctx);
! 137: return 0;
! 138: }
! 139:
! 140: int
! 141: ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen)
! 142: {
! 143: return ssh_digest_memory(alg, buffer_ptr(b), buffer_len(b), d, dlen);
! 144: }