1/* 2 * Copyright (C) 2012 Martin Storsjo 3 * 4 * This file is part of FFmpeg. 5 * 6 * FFmpeg is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * FFmpeg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with FFmpeg; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21#include <stddef.h> 22#include <stdint.h> 23#include <string.h> 24 25#include "attributes.h" 26#include "hmac.h" 27#include "md5.h" 28#include "sha.h" 29#include "sha512.h" 30#include "mem.h" 31 32#define MAX_HASHLEN 64 33#define MAX_BLOCKLEN 128 34 35typedef void (*hmac_final)(void *ctx, uint8_t *dst); 36typedef void (*hmac_update)(void *ctx, const uint8_t *src, size_t len); 37typedef void (*hmac_init)(void *ctx); 38 39struct AVHMAC { 40 void *hash; 41 int blocklen, hashlen; 42 hmac_final final; 43 hmac_update update; 44 hmac_init init; 45 uint8_t key[MAX_BLOCKLEN]; 46 int keylen; 47}; 48 49#define DEFINE_SHA(bits) \ 50static av_cold void sha ## bits ##_init(void *ctx) \ 51{ \ 52 av_sha_init(ctx, bits); \ 53} 54 55#define DEFINE_SHA512(bits) \ 56static av_cold void sha ## bits ##_init(void *ctx) \ 57{ \ 58 av_sha512_init(ctx, bits); \ 59} 60 61DEFINE_SHA(160) 62DEFINE_SHA(224) 63DEFINE_SHA(256) 64DEFINE_SHA512(384) 65DEFINE_SHA512(512) 66 67AVHMAC *av_hmac_alloc(enum AVHMACType type) 68{ 69 AVHMAC *c = av_mallocz(sizeof(*c)); 70 if (!c) 71 return NULL; 72 switch (type) { 73 case AV_HMAC_MD5: 74 c->blocklen = 64; 75 c->hashlen = 16; 76 c->init = (hmac_init) av_md5_init; 77 c->update = (hmac_update) av_md5_update; 78 c->final = (hmac_final) av_md5_final; 79 c->hash = av_md5_alloc(); 80 break; 81 case AV_HMAC_SHA1: 82 c->blocklen = 64; 83 c->hashlen = 20; 84 c->init = sha160_init; 85 c->update = (hmac_update) av_sha_update; 86 c->final = (hmac_final) av_sha_final; 87 c->hash = av_sha_alloc(); 88 break; 89 case AV_HMAC_SHA224: 90 c->blocklen = 64; 91 c->hashlen = 28; 92 c->init = sha224_init; 93 c->update = (hmac_update) av_sha_update; 94 c->final = (hmac_final) av_sha_final; 95 c->hash = av_sha_alloc(); 96 break; 97 case AV_HMAC_SHA256: 98 c->blocklen = 64; 99 c->hashlen = 32; 100 c->init = sha256_init; 101 c->update = (hmac_update) av_sha_update; 102 c->final = (hmac_final) av_sha_final; 103 c->hash = av_sha_alloc(); 104 break; 105 case AV_HMAC_SHA384: 106 c->blocklen = 128; 107 c->hashlen = 48; 108 c->init = sha384_init; 109 c->update = (hmac_update) av_sha512_update; 110 c->final = (hmac_final) av_sha512_final; 111 c->hash = av_sha512_alloc(); 112 break; 113 case AV_HMAC_SHA512: 114 c->blocklen = 128; 115 c->hashlen = 64; 116 c->init = sha512_init; 117 c->update = (hmac_update) av_sha512_update; 118 c->final = (hmac_final) av_sha512_final; 119 c->hash = av_sha512_alloc(); 120 break; 121 default: 122 av_free(c); 123 return NULL; 124 } 125 if (!c->hash) { 126 av_free(c); 127 return NULL; 128 } 129 return c; 130} 131 132void av_hmac_free(AVHMAC *c) 133{ 134 if (!c) 135 return; 136 av_freep(&c->hash); 137 av_free(c); 138} 139 140void av_hmac_init(AVHMAC *c, const uint8_t *key, unsigned int keylen) 141{ 142 int i; 143 uint8_t block[MAX_BLOCKLEN]; 144 if (keylen > c->blocklen) { 145 c->init(c->hash); 146 c->update(c->hash, key, keylen); 147 c->final(c->hash, c->key); 148 c->keylen = c->hashlen; 149 } else { 150 memcpy(c->key, key, keylen); 151 c->keylen = keylen; 152 } 153 c->init(c->hash); 154 for (i = 0; i < c->keylen; i++) 155 block[i] = c->key[i] ^ 0x36; 156 for (i = c->keylen; i < c->blocklen; i++) 157 block[i] = 0x36; 158 c->update(c->hash, block, c->blocklen); 159} 160 161void av_hmac_update(AVHMAC *c, const uint8_t *data, unsigned int len) 162{ 163 c->update(c->hash, data, len); 164} 165 166int av_hmac_final(AVHMAC *c, uint8_t *out, unsigned int outlen) 167{ 168 uint8_t block[MAX_BLOCKLEN]; 169 int i; 170 if (outlen < c->hashlen) 171 return AVERROR(EINVAL); 172 c->final(c->hash, out); 173 c->init(c->hash); 174 for (i = 0; i < c->keylen; i++) 175 block[i] = c->key[i] ^ 0x5C; 176 for (i = c->keylen; i < c->blocklen; i++) 177 block[i] = 0x5C; 178 c->update(c->hash, block, c->blocklen); 179 c->update(c->hash, out, c->hashlen); 180 c->final(c->hash, out); 181 return c->hashlen; 182} 183 184int av_hmac_calc(AVHMAC *c, const uint8_t *data, unsigned int len, 185 const uint8_t *key, unsigned int keylen, 186 uint8_t *out, unsigned int outlen) 187{ 188 av_hmac_init(c, key, keylen); 189 av_hmac_update(c, data, len); 190 return av_hmac_final(c, out, outlen); 191} 192