/src/ffmpeg/libavutil/hmac.c
Line | Count | Source |
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 "error.h" |
27 | | #include "hmac.h" |
28 | | #include "md5.h" |
29 | | #include "sha.h" |
30 | | #include "sha512.h" |
31 | | #include "mem.h" |
32 | | |
33 | | #define MAX_HASHLEN 64 |
34 | | #define MAX_BLOCKLEN 128 |
35 | | |
36 | | typedef void (*hmac_final)(void *ctx, uint8_t *dst); |
37 | | typedef void (*hmac_update)(void *ctx, const uint8_t *src, size_t len); |
38 | | typedef void (*hmac_init)(void *ctx); |
39 | | |
40 | | struct AVHMAC { |
41 | | void *hash; |
42 | | int blocklen, hashlen; |
43 | | hmac_final final; |
44 | | hmac_update update; |
45 | | hmac_init init; |
46 | | uint8_t key[MAX_BLOCKLEN]; |
47 | | int keylen; |
48 | | }; |
49 | | |
50 | | #define DEFINE_ALGO_BITS_INIT(prefix, bits) \ |
51 | 0 | static av_cold void prefix##bits##_init(void *ctx) \ |
52 | 0 | { \ |
53 | 0 | av_##prefix##_init(ctx, bits); \ |
54 | 0 | } Unexecuted instantiation: hmac.c:sha160_init Unexecuted instantiation: hmac.c:sha224_init Unexecuted instantiation: hmac.c:sha256_init Unexecuted instantiation: hmac.c:sha512384_init Unexecuted instantiation: hmac.c:sha512512_init |
55 | | |
56 | | #define DEFINE_ALGO_INIT(prefix) \ |
57 | 0 | static av_cold void prefix##_init(void *ctx) \ |
58 | 0 | { \ |
59 | 0 | av_##prefix##_init(ctx); \ |
60 | 0 | } |
61 | | |
62 | | #define DEFINE_ALGO(prefix) \ |
63 | 0 | static void prefix##_update(void *ctx, const uint8_t *src, size_t len) \ |
64 | 0 | { \ |
65 | 0 | av_##prefix##_update(ctx, src, len); \ |
66 | 0 | } \ Unexecuted instantiation: hmac.c:md5_update Unexecuted instantiation: hmac.c:sha_update Unexecuted instantiation: hmac.c:sha512_update |
67 | 0 | static void prefix##_final(void *ctx, uint8_t *dst) \ |
68 | 0 | { \ |
69 | 0 | av_##prefix##_final(ctx, dst); \ |
70 | 0 | } Unexecuted instantiation: hmac.c:md5_final Unexecuted instantiation: hmac.c:sha_final Unexecuted instantiation: hmac.c:sha512_final |
71 | | |
72 | | DEFINE_ALGO_INIT(md5) |
73 | | DEFINE_ALGO_BITS_INIT(sha, 160) |
74 | | DEFINE_ALGO_BITS_INIT(sha, 224) |
75 | | DEFINE_ALGO_BITS_INIT(sha, 256) |
76 | | DEFINE_ALGO_BITS_INIT(sha512, 384) |
77 | | DEFINE_ALGO_BITS_INIT(sha512, 512) |
78 | | DEFINE_ALGO(md5) |
79 | | DEFINE_ALGO(sha) |
80 | | DEFINE_ALGO(sha512) |
81 | | |
82 | | AVHMAC *av_hmac_alloc(enum AVHMACType type) |
83 | 0 | { |
84 | 0 | AVHMAC *c = av_mallocz(sizeof(*c)); |
85 | 0 | if (!c) |
86 | 0 | return NULL; |
87 | 0 | switch (type) { |
88 | 0 | case AV_HMAC_MD5: |
89 | 0 | c->blocklen = 64; |
90 | 0 | c->hashlen = 16; |
91 | 0 | c->init = md5_init; |
92 | 0 | c->update = md5_update; |
93 | 0 | c->final = md5_final; |
94 | 0 | c->hash = av_md5_alloc(); |
95 | 0 | break; |
96 | 0 | case AV_HMAC_SHA1: |
97 | 0 | c->blocklen = 64; |
98 | 0 | c->hashlen = 20; |
99 | 0 | c->init = sha160_init; |
100 | 0 | c->update = sha_update; |
101 | 0 | c->final = sha_final; |
102 | 0 | c->hash = av_sha_alloc(); |
103 | 0 | break; |
104 | 0 | case AV_HMAC_SHA224: |
105 | 0 | c->blocklen = 64; |
106 | 0 | c->hashlen = 28; |
107 | 0 | c->init = sha224_init; |
108 | 0 | c->update = sha_update; |
109 | 0 | c->final = sha_final; |
110 | 0 | c->hash = av_sha_alloc(); |
111 | 0 | break; |
112 | 0 | case AV_HMAC_SHA256: |
113 | 0 | c->blocklen = 64; |
114 | 0 | c->hashlen = 32; |
115 | 0 | c->init = sha256_init; |
116 | 0 | c->update = sha_update; |
117 | 0 | c->final = sha_final; |
118 | 0 | c->hash = av_sha_alloc(); |
119 | 0 | break; |
120 | 0 | case AV_HMAC_SHA384: |
121 | 0 | c->blocklen = 128; |
122 | 0 | c->hashlen = 48; |
123 | 0 | c->init = sha512384_init; |
124 | 0 | c->update = sha512_update; |
125 | 0 | c->final = sha512_final; |
126 | 0 | c->hash = av_sha512_alloc(); |
127 | 0 | break; |
128 | 0 | case AV_HMAC_SHA512: |
129 | 0 | c->blocklen = 128; |
130 | 0 | c->hashlen = 64; |
131 | 0 | c->init = sha512512_init; |
132 | 0 | c->update = sha512_update; |
133 | 0 | c->final = sha512_final; |
134 | 0 | c->hash = av_sha512_alloc(); |
135 | 0 | break; |
136 | 0 | default: |
137 | 0 | av_free(c); |
138 | 0 | return NULL; |
139 | 0 | } |
140 | 0 | if (!c->hash) { |
141 | 0 | av_free(c); |
142 | 0 | return NULL; |
143 | 0 | } |
144 | 0 | return c; |
145 | 0 | } |
146 | | |
147 | | void av_hmac_free(AVHMAC *c) |
148 | 0 | { |
149 | 0 | if (!c) |
150 | 0 | return; |
151 | 0 | av_freep(&c->hash); |
152 | 0 | av_free(c); |
153 | 0 | } |
154 | | |
155 | | void av_hmac_init(AVHMAC *c, const uint8_t *key, unsigned int keylen) |
156 | 0 | { |
157 | 0 | int i; |
158 | 0 | uint8_t block[MAX_BLOCKLEN]; |
159 | 0 | if (keylen > c->blocklen) { |
160 | 0 | c->init(c->hash); |
161 | 0 | c->update(c->hash, key, keylen); |
162 | 0 | c->final(c->hash, c->key); |
163 | 0 | c->keylen = c->hashlen; |
164 | 0 | } else { |
165 | 0 | memcpy(c->key, key, keylen); |
166 | 0 | c->keylen = keylen; |
167 | 0 | } |
168 | 0 | c->init(c->hash); |
169 | 0 | for (i = 0; i < c->keylen; i++) |
170 | 0 | block[i] = c->key[i] ^ 0x36; |
171 | 0 | for (i = c->keylen; i < c->blocklen; i++) |
172 | 0 | block[i] = 0x36; |
173 | 0 | c->update(c->hash, block, c->blocklen); |
174 | 0 | } |
175 | | |
176 | | void av_hmac_update(AVHMAC *c, const uint8_t *data, unsigned int len) |
177 | 0 | { |
178 | 0 | c->update(c->hash, data, len); |
179 | 0 | } |
180 | | |
181 | | int av_hmac_final(AVHMAC *c, uint8_t *out, unsigned int outlen) |
182 | 0 | { |
183 | 0 | uint8_t block[MAX_BLOCKLEN]; |
184 | 0 | int i; |
185 | 0 | if (outlen < c->hashlen) |
186 | 0 | return AVERROR(EINVAL); |
187 | 0 | c->final(c->hash, out); |
188 | 0 | c->init(c->hash); |
189 | 0 | for (i = 0; i < c->keylen; i++) |
190 | 0 | block[i] = c->key[i] ^ 0x5C; |
191 | 0 | for (i = c->keylen; i < c->blocklen; i++) |
192 | 0 | block[i] = 0x5C; |
193 | 0 | c->update(c->hash, block, c->blocklen); |
194 | 0 | c->update(c->hash, out, c->hashlen); |
195 | 0 | c->final(c->hash, out); |
196 | 0 | return c->hashlen; |
197 | 0 | } |
198 | | |
199 | | int av_hmac_calc(AVHMAC *c, const uint8_t *data, unsigned int len, |
200 | | const uint8_t *key, unsigned int keylen, |
201 | | uint8_t *out, unsigned int outlen) |
202 | 0 | { |
203 | 0 | av_hmac_init(c, key, keylen); |
204 | 0 | av_hmac_update(c, data, len); |
205 | 0 | return av_hmac_final(c, out, outlen); |
206 | 0 | } |