1263635Sdes/* $OpenBSD: digest-libc.c,v 1.2 2014/02/02 03:44:31 djm Exp $ */ 2263635Sdes/* 3263635Sdes * Copyright (c) 2013 Damien Miller <djm@mindrot.org> 4263635Sdes * Copyright (c) 2014 Markus Friedl. All rights reserved. 5263635Sdes * 6263635Sdes * Permission to use, copy, modify, and distribute this software for any 7263635Sdes * purpose with or without fee is hereby granted, provided that the above 8263635Sdes * copyright notice and this permission notice appear in all copies. 9263635Sdes * 10263635Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11263635Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12263635Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13263635Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14263635Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15263635Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16263635Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17263635Sdes */ 18263635Sdes 19263635Sdes#include "includes.h" 20263635Sdes 21263635Sdes#include <sys/types.h> 22263635Sdes#include <limits.h> 23263635Sdes#include <stdlib.h> 24263635Sdes#include <string.h> 25263635Sdes 26263635Sdes#include <md5.h> 27263635Sdes#include <rmd160.h> 28263635Sdes#include <sha1.h> 29263635Sdes#include <sha2.h> 30263635Sdes 31263635Sdes#include "buffer.h" 32263635Sdes#include "digest.h" 33263635Sdes 34263635Sdestypedef void md_init_fn(void *mdctx); 35263635Sdestypedef void md_update_fn(void *mdctx, const u_int8_t *m, size_t mlen); 36263635Sdestypedef void md_final_fn(u_int8_t[], void *mdctx); 37263635Sdes 38263635Sdesstruct ssh_digest_ctx { 39263635Sdes int alg; 40263635Sdes void *mdctx; 41263635Sdes}; 42263635Sdes 43263635Sdesstruct ssh_digest { 44263635Sdes int id; 45263635Sdes const char *name; 46263635Sdes size_t block_len; 47263635Sdes size_t digest_len; 48263635Sdes size_t ctx_len; 49263635Sdes md_init_fn *md_init; 50263635Sdes md_update_fn *md_update; 51263635Sdes md_final_fn *md_final; 52263635Sdes}; 53263635Sdes 54263635Sdes/* NB. Indexed directly by algorithm number */ 55263635Sdesconst struct ssh_digest digests[SSH_DIGEST_MAX] = { 56263635Sdes { 57263635Sdes SSH_DIGEST_MD5, 58263635Sdes "MD5", 59263635Sdes MD5_BLOCK_LENGTH, 60263635Sdes MD5_DIGEST_LENGTH, 61263635Sdes sizeof(MD5_CTX), 62263635Sdes (md_init_fn *) MD5Init, 63263635Sdes (md_update_fn *) MD5Update, 64263635Sdes (md_final_fn *) MD5Final 65263635Sdes }, 66263635Sdes { 67263635Sdes SSH_DIGEST_RIPEMD160, 68263635Sdes "RIPEMD160", 69263635Sdes RMD160_BLOCK_LENGTH, 70263635Sdes RMD160_DIGEST_LENGTH, 71263635Sdes sizeof(RMD160_CTX), 72263635Sdes (md_init_fn *) RMD160Init, 73263635Sdes (md_update_fn *) RMD160Update, 74263635Sdes (md_final_fn *) RMD160Final 75263635Sdes }, 76263635Sdes { 77263635Sdes SSH_DIGEST_SHA1, 78263635Sdes "SHA1", 79263635Sdes SHA1_BLOCK_LENGTH, 80263635Sdes SHA1_DIGEST_LENGTH, 81263635Sdes sizeof(SHA1_CTX), 82263635Sdes (md_init_fn *) SHA1Init, 83263635Sdes (md_update_fn *) SHA1Update, 84263635Sdes (md_final_fn *) SHA1Final 85263635Sdes }, 86263635Sdes { 87263635Sdes SSH_DIGEST_SHA256, 88263635Sdes "SHA256", 89263635Sdes SHA256_BLOCK_LENGTH, 90263635Sdes SHA256_DIGEST_LENGTH, 91263635Sdes sizeof(SHA2_CTX), 92263635Sdes (md_init_fn *) SHA256Init, 93263635Sdes (md_update_fn *) SHA256Update, 94263635Sdes (md_final_fn *) SHA256Final 95263635Sdes }, 96263635Sdes { 97263635Sdes SSH_DIGEST_SHA384, 98263635Sdes "SHA384", 99263635Sdes SHA384_BLOCK_LENGTH, 100263635Sdes SHA384_DIGEST_LENGTH, 101263635Sdes sizeof(SHA2_CTX), 102263635Sdes (md_init_fn *) SHA384Init, 103263635Sdes (md_update_fn *) SHA384Update, 104263635Sdes (md_final_fn *) SHA384Final 105263635Sdes }, 106263635Sdes { 107263635Sdes SSH_DIGEST_SHA512, 108263635Sdes "SHA512", 109263635Sdes SHA512_BLOCK_LENGTH, 110263635Sdes SHA512_DIGEST_LENGTH, 111263635Sdes sizeof(SHA2_CTX), 112263635Sdes (md_init_fn *) SHA512Init, 113263635Sdes (md_update_fn *) SHA512Update, 114263635Sdes (md_final_fn *) SHA512Final 115263635Sdes } 116263635Sdes}; 117263635Sdes 118263635Sdesstatic const struct ssh_digest * 119263635Sdesssh_digest_by_alg(int alg) 120263635Sdes{ 121263635Sdes if (alg < 0 || alg >= SSH_DIGEST_MAX) 122263635Sdes return NULL; 123263635Sdes if (digests[alg].id != alg) /* sanity */ 124263635Sdes return NULL; 125263635Sdes return &(digests[alg]); 126263635Sdes} 127263635Sdes 128263635Sdessize_t 129263635Sdesssh_digest_bytes(int alg) 130263635Sdes{ 131263635Sdes const struct ssh_digest *digest = ssh_digest_by_alg(alg); 132263635Sdes 133263635Sdes return digest == NULL ? 0 : digest->digest_len; 134263635Sdes} 135263635Sdes 136263635Sdessize_t 137263635Sdesssh_digest_blocksize(struct ssh_digest_ctx *ctx) 138263635Sdes{ 139263635Sdes const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); 140263635Sdes 141263635Sdes return digest == NULL ? 0 : digest->block_len; 142263635Sdes} 143263635Sdes 144263635Sdesstruct ssh_digest_ctx * 145263635Sdesssh_digest_start(int alg) 146263635Sdes{ 147263635Sdes const struct ssh_digest *digest = ssh_digest_by_alg(alg); 148263635Sdes struct ssh_digest_ctx *ret; 149263635Sdes 150263635Sdes if (digest == NULL || (ret = calloc(1, sizeof(ret))) == NULL) 151263635Sdes return NULL; 152263635Sdes if ((ret->mdctx = calloc(1, digest->ctx_len)) == NULL) { 153263635Sdes free(ret); 154263635Sdes return NULL; 155263635Sdes } 156263635Sdes ret->alg = alg; 157263635Sdes digest->md_init(ret->mdctx); 158263635Sdes return ret; 159263635Sdes} 160263635Sdes 161263635Sdesint 162263635Sdesssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to) 163263635Sdes{ 164263635Sdes const struct ssh_digest *digest = ssh_digest_by_alg(from->alg); 165263635Sdes 166263635Sdes if (digest == NULL || from->alg != to->alg) 167263635Sdes return -1; 168263635Sdes memcpy(to->mdctx, from->mdctx, digest->ctx_len); 169263635Sdes return 0; 170263635Sdes} 171263635Sdes 172263635Sdesint 173263635Sdesssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) 174263635Sdes{ 175263635Sdes const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); 176263635Sdes 177263635Sdes if (digest == NULL) 178263635Sdes return -1; 179263635Sdes digest->md_update(ctx->mdctx, m, mlen); 180263635Sdes return 0; 181263635Sdes} 182263635Sdes 183263635Sdesint 184263635Sdesssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b) 185263635Sdes{ 186263635Sdes return ssh_digest_update(ctx, buffer_ptr(b), buffer_len(b)); 187263635Sdes} 188263635Sdes 189263635Sdesint 190263635Sdesssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) 191263635Sdes{ 192263635Sdes const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); 193263635Sdes 194263635Sdes if (digest == NULL) 195263635Sdes return -1; 196263635Sdes if (dlen > UINT_MAX) 197263635Sdes return -1; 198263635Sdes if (dlen < digest->digest_len) /* No truncation allowed */ 199263635Sdes return -1; 200263635Sdes digest->md_final(d, ctx->mdctx); 201263635Sdes return 0; 202263635Sdes} 203263635Sdes 204263635Sdesvoid 205263635Sdesssh_digest_free(struct ssh_digest_ctx *ctx) 206263635Sdes{ 207263635Sdes const struct ssh_digest *digest; 208263635Sdes 209263635Sdes if (ctx != NULL) { 210263635Sdes digest = ssh_digest_by_alg(ctx->alg); 211263635Sdes if (digest) { 212263635Sdes explicit_bzero(ctx->mdctx, digest->ctx_len); 213263635Sdes free(ctx->mdctx); 214263635Sdes explicit_bzero(ctx, sizeof(*ctx)); 215263635Sdes free(ctx); 216263635Sdes } 217263635Sdes } 218263635Sdes} 219263635Sdes 220263635Sdesint 221263635Sdesssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen) 222263635Sdes{ 223263635Sdes struct ssh_digest_ctx *ctx = ssh_digest_start(alg); 224263635Sdes 225263635Sdes if (ctx == NULL) 226263635Sdes return -1; 227263635Sdes if (ssh_digest_update(ctx, m, mlen) != 0 || 228263635Sdes ssh_digest_final(ctx, d, dlen) != 0) 229263635Sdes return -1; 230263635Sdes ssh_digest_free(ctx); 231263635Sdes return 0; 232263635Sdes} 233263635Sdes 234263635Sdesint 235263635Sdesssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen) 236263635Sdes{ 237263635Sdes return ssh_digest_memory(alg, buffer_ptr(b), buffer_len(b), d, dlen); 238263635Sdes} 239