Annotation of src/usr.bin/ssh/hmac.c, Revision 1.9
1.9 ! markus 1: /* $OpenBSD: $ */
1.1 markus 2: /*
1.9 ! markus 3: * Copyright (c) 2014 Markus Friedl. All rights reserved.
1.1 markus 4: *
1.9 ! markus 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.
1.1 markus 8: *
1.9 ! markus 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.
1.1 markus 16: */
17:
1.9 ! markus 18: #include <sys/types.h>
! 19: #include <string.h>
1.1 markus 20:
1.9 ! markus 21: #include "buffer.h"
! 22: #include "digest.h"
! 23: #include "hmac.h"
1.1 markus 24:
1.9 ! markus 25: struct ssh_hmac_ctx {
! 26: int alg;
! 27: struct ssh_digest_ctx *ictx;
! 28: struct ssh_digest_ctx *octx;
! 29: struct ssh_digest_ctx *digest;
! 30: u_char *buf;
! 31: size_t buf_len;
! 32: };
1.7 itojun 33:
1.9 ! markus 34: size_t
! 35: ssh_hmac_bytes(int alg)
! 36: {
! 37: return ssh_digest_bytes(alg);
! 38: }
! 39:
! 40: struct ssh_hmac_ctx *
! 41: ssh_hmac_start(int alg)
! 42: {
! 43: struct ssh_hmac_ctx *ret;
! 44:
! 45: if ((ret = calloc(1, sizeof(*ret))) == NULL)
! 46: return NULL;
! 47: ret->alg = alg;
! 48: if ((ret->ictx = ssh_digest_start(alg)) == NULL ||
! 49: (ret->octx = ssh_digest_start(alg)) == NULL ||
! 50: (ret->digest = ssh_digest_start(alg)) == NULL)
! 51: goto fail;
! 52: ret->buf_len = ssh_digest_blocksize(ret->ictx);
! 53: if ((ret->buf = calloc(1, ret->buf_len)) == NULL)
! 54: goto fail;
! 55: return ret;
! 56: fail:
! 57: ssh_hmac_free(ret);
! 58: return NULL;
! 59: }
! 60:
! 61: int
! 62: ssh_hmac_init(struct ssh_hmac_ctx *ctx, const void *key, size_t klen)
! 63: {
! 64: size_t i;
! 65:
! 66: /* reset ictx and octx if no is key given */
! 67: if (key != NULL) {
! 68: /* truncate long keys */
! 69: if (klen <= ctx->buf_len)
! 70: memcpy(ctx->buf, key, klen);
! 71: else if (ssh_digest_memory(ctx->alg, key, klen, ctx->buf,
! 72: ctx->buf_len) < 0)
! 73: return -1;
! 74: for (i = 0; i < ctx->buf_len; i++)
! 75: ctx->buf[i] ^= 0x36;
! 76: if (ssh_digest_update(ctx->ictx, ctx->buf, ctx->buf_len) < 0)
! 77: return -1;
! 78: for (i = 0; i < ctx->buf_len; i++)
! 79: ctx->buf[i] ^= 0x36 ^ 0x5c;
! 80: if (ssh_digest_update(ctx->octx, ctx->buf, ctx->buf_len) < 0)
! 81: return -1;
! 82: bzero(ctx->buf, ctx->buf_len);
! 83: }
! 84: /* start with ictx */
! 85: if (ssh_digest_copy_state(ctx->ictx, ctx->digest) < 0)
! 86: return -1;
! 87: return 0;
! 88: }
! 89:
! 90: int
! 91: ssh_hmac_update(struct ssh_hmac_ctx *ctx, const void *m, size_t mlen)
! 92: {
! 93: return ssh_digest_update(ctx->digest, m, mlen);
! 94: }
! 95:
! 96: int
! 97: ssh_hmac_update_buffer(struct ssh_hmac_ctx *ctx, const Buffer *b)
! 98: {
! 99: return ssh_digest_update_buffer(ctx->digest, b);
! 100: }
! 101:
! 102: int
! 103: ssh_hmac_final(struct ssh_hmac_ctx *ctx, u_char *d, size_t dlen)
! 104: {
! 105: size_t len;
! 106:
! 107: len = ssh_digest_bytes(ctx->alg);
! 108: if (dlen < len ||
! 109: ssh_digest_final(ctx->digest, ctx->buf, len))
! 110: return -1;
! 111: /* switch to octx */
! 112: if (ssh_digest_copy_state(ctx->octx, ctx->digest) < 0 ||
! 113: ssh_digest_update(ctx->digest, ctx->buf, len) < 0 ||
! 114: ssh_digest_final(ctx->digest, d, dlen) < 0)
! 115: return -1;
! 116: return 0;
! 117: }
! 118:
! 119: void
! 120: ssh_hmac_free(struct ssh_hmac_ctx *ctx)
! 121: {
! 122: if (ctx != NULL) {
! 123: ssh_digest_free(ctx->ictx);
! 124: ssh_digest_free(ctx->octx);
! 125: ssh_digest_free(ctx->digest);
! 126: if (ctx->buf) {
! 127: bzero(ctx->buf, ctx->buf_len);
! 128: free(ctx->buf);
! 129: }
! 130: bzero(ctx, sizeof(*ctx));
! 131: free(ctx);
! 132: }
! 133: }
! 134:
! 135: #ifdef TEST
! 136:
! 137: /* cc -DTEST hmac.c digest.c buffer.c cleanup.c fatal.c log.c xmalloc.c -lcrypto */
! 138: static void
! 139: hmac_test(void *key, size_t klen, void *m, size_t mlen, u_char *e, size_t elen)
! 140: {
! 141: struct ssh_hmac_ctx *ctx;
! 142: size_t i;
! 143: u_char digest[16];
! 144:
! 145: if ((ctx = ssh_hmac_start(SSH_DIGEST_MD5)) == NULL)
! 146: printf("ssh_hmac_start failed");
! 147: if (ssh_hmac_init(ctx, key, klen) < 0 ||
! 148: ssh_hmac_update(ctx, m, mlen) < 0 ||
! 149: ssh_hmac_final(ctx, digest, sizeof(digest)) < 0)
! 150: printf("ssh_hmac_xxx failed");
! 151: ssh_hmac_free(ctx);
! 152:
! 153: if (memcmp(e, digest, elen)) {
! 154: for (i = 0; i < elen; i++)
! 155: printf("[%zd] %2.2x %2.2x\n", i, e[i], digest[i]);
! 156: printf("mismatch\n");
! 157: } else
! 158: printf("ok\n");
! 159: }
! 160:
! 161: int
! 162: main(int argc, char **argv)
! 163: {
! 164: /* try test vectors from RFC 2104 */
! 165:
! 166: u_char key1[16] = {
! 167: 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb,
! 168: 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb };
! 169: u_char *data1 = "Hi There";
! 170: u_char dig1[16] = {
! 171: 0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c,
! 172: 0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d };
! 173:
! 174: u_char *key2 = "Jefe";
! 175: u_char *data2 = "what do ya want for nothing?";
! 176: u_char dig2[16] = {
! 177: 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03,
! 178: 0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38 };
! 179:
! 180: u_char key3[16];
! 181: u_char data3[50];
! 182: u_char dig3[16] = {
! 183: 0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88,
! 184: 0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6 };
! 185: memset(key3, 0xaa, sizeof(key3));
! 186: memset(data3, 0xdd, sizeof(data3));
! 187:
! 188: hmac_test(key1, sizeof(key1), data1, strlen(data1), dig1, sizeof(dig1));
! 189: hmac_test(key2, strlen(key2), data2, strlen(data2), dig2, sizeof(dig2));
! 190: hmac_test(key3, sizeof(key3), data3, sizeof(data3), dig3, sizeof(dig3));
1.1 markus 191:
1.9 ! markus 192: return 0;
1.1 markus 193: }
1.9 ! markus 194:
! 195: #endif