1263635Sdes/* $OpenBSD: hmac.c,v 1.10 2014/01/31 16:39:19 tedu Exp $ */ 2263635Sdes/* 3263635Sdes * Copyright (c) 2014 Markus Friedl. All rights reserved. 4263635Sdes * 5263635Sdes * Permission to use, copy, modify, and distribute this software for any 6263635Sdes * purpose with or without fee is hereby granted, provided that the above 7263635Sdes * copyright notice and this permission notice appear in all copies. 8263635Sdes * 9263635Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10263635Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11263635Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12263635Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13263635Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14263635Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15263635Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16263635Sdes */ 17263635Sdes 18263635Sdes#include "includes.h" 19263635Sdes 20263635Sdes#include <sys/types.h> 21263635Sdes#include <string.h> 22263635Sdes 23263635Sdes#include "buffer.h" 24263635Sdes#include "digest.h" 25263635Sdes#include "hmac.h" 26263635Sdes 27263635Sdesstruct ssh_hmac_ctx { 28263635Sdes int alg; 29263635Sdes struct ssh_digest_ctx *ictx; 30263635Sdes struct ssh_digest_ctx *octx; 31263635Sdes struct ssh_digest_ctx *digest; 32263635Sdes u_char *buf; 33263635Sdes size_t buf_len; 34263635Sdes}; 35263635Sdes 36263635Sdessize_t 37263635Sdesssh_hmac_bytes(int alg) 38263635Sdes{ 39263635Sdes return ssh_digest_bytes(alg); 40263635Sdes} 41263635Sdes 42263635Sdesstruct ssh_hmac_ctx * 43263635Sdesssh_hmac_start(int alg) 44263635Sdes{ 45263635Sdes struct ssh_hmac_ctx *ret; 46263635Sdes 47263635Sdes if ((ret = calloc(1, sizeof(*ret))) == NULL) 48263635Sdes return NULL; 49263635Sdes ret->alg = alg; 50263635Sdes if ((ret->ictx = ssh_digest_start(alg)) == NULL || 51263635Sdes (ret->octx = ssh_digest_start(alg)) == NULL || 52263635Sdes (ret->digest = ssh_digest_start(alg)) == NULL) 53263635Sdes goto fail; 54263635Sdes ret->buf_len = ssh_digest_blocksize(ret->ictx); 55263635Sdes if ((ret->buf = calloc(1, ret->buf_len)) == NULL) 56263635Sdes goto fail; 57263635Sdes return ret; 58263635Sdesfail: 59263635Sdes ssh_hmac_free(ret); 60263635Sdes return NULL; 61263635Sdes} 62263635Sdes 63263635Sdesint 64263635Sdesssh_hmac_init(struct ssh_hmac_ctx *ctx, const void *key, size_t klen) 65263635Sdes{ 66263635Sdes size_t i; 67263635Sdes 68263635Sdes /* reset ictx and octx if no is key given */ 69263635Sdes if (key != NULL) { 70263635Sdes /* truncate long keys */ 71263635Sdes if (klen <= ctx->buf_len) 72263635Sdes memcpy(ctx->buf, key, klen); 73263635Sdes else if (ssh_digest_memory(ctx->alg, key, klen, ctx->buf, 74263635Sdes ctx->buf_len) < 0) 75263635Sdes return -1; 76263635Sdes for (i = 0; i < ctx->buf_len; i++) 77263635Sdes ctx->buf[i] ^= 0x36; 78263635Sdes if (ssh_digest_update(ctx->ictx, ctx->buf, ctx->buf_len) < 0) 79263635Sdes return -1; 80263635Sdes for (i = 0; i < ctx->buf_len; i++) 81263635Sdes ctx->buf[i] ^= 0x36 ^ 0x5c; 82263635Sdes if (ssh_digest_update(ctx->octx, ctx->buf, ctx->buf_len) < 0) 83263635Sdes return -1; 84263635Sdes explicit_bzero(ctx->buf, ctx->buf_len); 85263635Sdes } 86263635Sdes /* start with ictx */ 87263635Sdes if (ssh_digest_copy_state(ctx->ictx, ctx->digest) < 0) 88263635Sdes return -1; 89263635Sdes return 0; 90263635Sdes} 91263635Sdes 92263635Sdesint 93263635Sdesssh_hmac_update(struct ssh_hmac_ctx *ctx, const void *m, size_t mlen) 94263635Sdes{ 95263635Sdes return ssh_digest_update(ctx->digest, m, mlen); 96263635Sdes} 97263635Sdes 98263635Sdesint 99263635Sdesssh_hmac_update_buffer(struct ssh_hmac_ctx *ctx, const Buffer *b) 100263635Sdes{ 101263635Sdes return ssh_digest_update_buffer(ctx->digest, b); 102263635Sdes} 103263635Sdes 104263635Sdesint 105263635Sdesssh_hmac_final(struct ssh_hmac_ctx *ctx, u_char *d, size_t dlen) 106263635Sdes{ 107263635Sdes size_t len; 108263635Sdes 109263635Sdes len = ssh_digest_bytes(ctx->alg); 110263635Sdes if (dlen < len || 111263635Sdes ssh_digest_final(ctx->digest, ctx->buf, len)) 112263635Sdes return -1; 113263635Sdes /* switch to octx */ 114263635Sdes if (ssh_digest_copy_state(ctx->octx, ctx->digest) < 0 || 115263635Sdes ssh_digest_update(ctx->digest, ctx->buf, len) < 0 || 116263635Sdes ssh_digest_final(ctx->digest, d, dlen) < 0) 117263635Sdes return -1; 118263635Sdes return 0; 119263635Sdes} 120263635Sdes 121263635Sdesvoid 122263635Sdesssh_hmac_free(struct ssh_hmac_ctx *ctx) 123263635Sdes{ 124263635Sdes if (ctx != NULL) { 125263635Sdes ssh_digest_free(ctx->ictx); 126263635Sdes ssh_digest_free(ctx->octx); 127263635Sdes ssh_digest_free(ctx->digest); 128263635Sdes if (ctx->buf) { 129263635Sdes explicit_bzero(ctx->buf, ctx->buf_len); 130263635Sdes free(ctx->buf); 131263635Sdes } 132263635Sdes explicit_bzero(ctx, sizeof(*ctx)); 133263635Sdes free(ctx); 134263635Sdes } 135263635Sdes} 136263635Sdes 137263635Sdes#ifdef TEST 138263635Sdes 139263635Sdes/* cc -DTEST hmac.c digest.c buffer.c cleanup.c fatal.c log.c xmalloc.c -lcrypto */ 140263635Sdesstatic void 141263635Sdeshmac_test(void *key, size_t klen, void *m, size_t mlen, u_char *e, size_t elen) 142263635Sdes{ 143263635Sdes struct ssh_hmac_ctx *ctx; 144263635Sdes size_t i; 145263635Sdes u_char digest[16]; 146263635Sdes 147263635Sdes if ((ctx = ssh_hmac_start(SSH_DIGEST_MD5)) == NULL) 148263635Sdes printf("ssh_hmac_start failed"); 149263635Sdes if (ssh_hmac_init(ctx, key, klen) < 0 || 150263635Sdes ssh_hmac_update(ctx, m, mlen) < 0 || 151263635Sdes ssh_hmac_final(ctx, digest, sizeof(digest)) < 0) 152263635Sdes printf("ssh_hmac_xxx failed"); 153263635Sdes ssh_hmac_free(ctx); 154263635Sdes 155263635Sdes if (memcmp(e, digest, elen)) { 156263635Sdes for (i = 0; i < elen; i++) 157263635Sdes printf("[%zd] %2.2x %2.2x\n", i, e[i], digest[i]); 158263635Sdes printf("mismatch\n"); 159263635Sdes } else 160263635Sdes printf("ok\n"); 161263635Sdes} 162263635Sdes 163263635Sdesint 164263635Sdesmain(int argc, char **argv) 165263635Sdes{ 166263635Sdes /* try test vectors from RFC 2104 */ 167263635Sdes 168263635Sdes u_char key1[16] = { 169263635Sdes 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 170263635Sdes 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb }; 171263635Sdes u_char *data1 = "Hi There"; 172263635Sdes u_char dig1[16] = { 173263635Sdes 0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c, 174263635Sdes 0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d }; 175263635Sdes 176263635Sdes u_char *key2 = "Jefe"; 177263635Sdes u_char *data2 = "what do ya want for nothing?"; 178263635Sdes u_char dig2[16] = { 179263635Sdes 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03, 180263635Sdes 0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38 }; 181263635Sdes 182263635Sdes u_char key3[16]; 183263635Sdes u_char data3[50]; 184263635Sdes u_char dig3[16] = { 185263635Sdes 0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88, 186263635Sdes 0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6 }; 187263635Sdes memset(key3, 0xaa, sizeof(key3)); 188263635Sdes memset(data3, 0xdd, sizeof(data3)); 189263635Sdes 190263635Sdes hmac_test(key1, sizeof(key1), data1, strlen(data1), dig1, sizeof(dig1)); 191263635Sdes hmac_test(key2, strlen(key2), data2, strlen(data2), dig2, sizeof(dig2)); 192263635Sdes hmac_test(key3, sizeof(key3), data3, sizeof(data3), dig3, sizeof(dig3)); 193263635Sdes 194263635Sdes return 0; 195263635Sdes} 196263635Sdes 197263635Sdes#endif 198