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
35 typedef void (*hmac_final)(void *ctx, uint8_t *dst);
36 typedef void (*hmac_update)(void *ctx, const uint8_t *src, size_t len);
37 typedef void (*hmac_init)(void *ctx);
38
39 struct 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) \
50 static av_cold void sha ## bits ##_init(void *ctx) \
51 { \
52 av_sha_init(ctx, bits); \
53 }
54
55 #define DEFINE_SHA512(bits) \
56 static av_cold void sha ## bits ##_init(void *ctx) \
57 { \
58 av_sha512_init(ctx, bits); \
59 }
60
61 DEFINE_SHA(160)
62 DEFINE_SHA(224)
63 DEFINE_SHA(256)
64 DEFINE_SHA512(384)
65 DEFINE_SHA512(512)
66
av_hmac_alloc(enum AVHMACType type)67 AVHMAC *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
av_hmac_free(AVHMAC * c)132 void av_hmac_free(AVHMAC *c)
133 {
134 if (!c)
135 return;
136 av_freep(&c->hash);
137 av_free(c);
138 }
139
av_hmac_init(AVHMAC * c,const uint8_t * key,unsigned int keylen)140 void 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
av_hmac_update(AVHMAC * c,const uint8_t * data,unsigned int len)161 void av_hmac_update(AVHMAC *c, const uint8_t *data, unsigned int len)
162 {
163 c->update(c->hash, data, len);
164 }
165
av_hmac_final(AVHMAC * c,uint8_t * out,unsigned int outlen)166 int 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
av_hmac_calc(AVHMAC * c,const uint8_t * data,unsigned int len,const uint8_t * key,unsigned int keylen,uint8_t * out,unsigned int outlen)184 int 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