xref: /third_party/ffmpeg/libavutil/hmac.c (revision cabdff1a)
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