Coverage Report

Created: 2025-08-28 06:24

/src/pidgin/libpurple/ciphers/hmac.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * purple
3
 *
4
 * Purple is the legal property of its developers, whose names are too numerous
5
 * to list here.  Please refer to the COPYRIGHT file distributed with this
6
 * source distribution.
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 2 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
21
 */
22
#include <cipher.h>
23
24
#include "glibcompat.h"
25
26
#include <util.h>
27
28
struct HMAC_Context {
29
  PurpleCipherContext *hash;
30
  char *name;
31
  int blocksize;
32
  guchar *opad;
33
};
34
35
  static void
36
hmac_init(PurpleCipherContext *context, gpointer extra)
37
0
{
38
0
  struct HMAC_Context *hctx;
39
0
  hctx = g_new0(struct HMAC_Context, 1);
40
0
  purple_cipher_context_set_data(context, hctx);
41
0
  purple_cipher_context_reset(context, extra);
42
0
}
43
44
  static void
45
hmac_reset(PurpleCipherContext *context, gpointer extra)
46
0
{
47
0
  struct HMAC_Context *hctx;
48
49
0
  hctx = purple_cipher_context_get_data(context);
50
51
0
  g_free(hctx->name);
52
0
  hctx->name = NULL;
53
0
  if (hctx->hash)
54
0
    purple_cipher_context_destroy(hctx->hash);
55
0
  hctx->hash = NULL;
56
0
  hctx->blocksize = 0;
57
0
  g_free(hctx->opad);
58
0
  hctx->opad = NULL;
59
0
}
60
61
  static void
62
hmac_set_opt(PurpleCipherContext *context, const gchar *name, void *value)
63
0
{
64
0
  struct HMAC_Context *hctx;
65
66
0
  hctx = purple_cipher_context_get_data(context);
67
68
0
  if (purple_strequal(name, "hash")) {
69
0
    g_free(hctx->name);
70
0
    if (hctx->hash)
71
0
      purple_cipher_context_destroy(hctx->hash);
72
0
    hctx->name = g_strdup((char*)value);
73
0
    hctx->hash = purple_cipher_context_new_by_name((char *)value, NULL);
74
0
    hctx->blocksize = purple_cipher_context_get_block_size(hctx->hash);
75
0
  }
76
0
}
77
78
  static void *
79
hmac_get_opt(PurpleCipherContext *context, const gchar *name)
80
0
{
81
0
  struct HMAC_Context *hctx;
82
83
0
  hctx = purple_cipher_context_get_data(context);
84
85
0
  if (purple_strequal(name, "hash")) {
86
0
    return hctx->name;
87
0
  }
88
89
0
  return NULL;
90
0
}
91
92
  static void
93
hmac_append(PurpleCipherContext *context, const guchar *data, size_t len)
94
0
{
95
0
  struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
96
97
0
  g_return_if_fail(hctx->hash != NULL);
98
99
0
  purple_cipher_context_append(hctx->hash, data, len);
100
0
}
101
102
  static gboolean
103
hmac_digest(PurpleCipherContext *context, size_t in_len, guchar *out, size_t *out_len)
104
0
{
105
0
  struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
106
0
  PurpleCipherContext *hash = hctx->hash;
107
0
  guchar *inner_hash;
108
0
  size_t hash_len;
109
0
  gboolean result;
110
111
0
  g_return_val_if_fail(hash != NULL, FALSE);
112
113
0
  inner_hash = g_malloc(100); /* TODO: Should be enough for now... */
114
0
  result = purple_cipher_context_digest(hash, 100, inner_hash, &hash_len);
115
116
0
  purple_cipher_context_reset(hash, NULL);
117
118
0
  purple_cipher_context_append(hash, hctx->opad, hctx->blocksize);
119
0
  purple_cipher_context_append(hash, inner_hash, hash_len);
120
121
0
  g_free(inner_hash);
122
123
0
  result = result && purple_cipher_context_digest(hash, in_len, out, out_len);
124
125
0
  return result;
126
0
}
127
128
  static void
129
hmac_uninit(PurpleCipherContext *context)
130
0
{
131
0
  struct HMAC_Context *hctx;
132
133
0
  purple_cipher_context_reset(context, NULL);
134
135
0
  hctx = purple_cipher_context_get_data(context);
136
137
0
  g_free(hctx);
138
0
}
139
140
  static void
141
hmac_set_key_with_len(PurpleCipherContext *context, const guchar * key, size_t key_len)
142
0
{
143
0
  struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
144
0
  int blocksize, i;
145
0
  guchar *ipad;
146
0
  guchar *full_key;
147
148
0
  g_return_if_fail(hctx->hash != NULL);
149
150
0
  g_free(hctx->opad);
151
152
0
  blocksize = hctx->blocksize;
153
0
  ipad = g_malloc(blocksize);
154
0
  hctx->opad = g_malloc(blocksize);
155
156
0
  if (key_len > blocksize) {
157
0
    purple_cipher_context_reset(hctx->hash, NULL);
158
0
    purple_cipher_context_append(hctx->hash, key, key_len);
159
0
    full_key = g_malloc(100); /* TODO: Should be enough for now... */
160
0
    purple_cipher_context_digest(hctx->hash, 100, full_key, &key_len);
161
0
  } else
162
0
    full_key = g_memdup2(key, key_len);
163
164
0
  if (key_len < blocksize) {
165
0
    full_key = g_realloc(full_key, blocksize);
166
0
    memset(full_key + key_len, 0, blocksize - key_len);
167
0
  }
168
169
0
  for(i = 0; i < blocksize; i++) {
170
0
    ipad[i] = 0x36 ^ full_key[i];
171
0
    hctx->opad[i] = 0x5c ^ full_key[i];
172
0
  }
173
174
0
  g_free(full_key);
175
176
0
  purple_cipher_context_reset(hctx->hash, NULL);
177
0
  purple_cipher_context_append(hctx->hash, ipad, blocksize);
178
0
  g_free(ipad);
179
0
}
180
181
  static void
182
hmac_set_key(PurpleCipherContext *context, const guchar * key)
183
0
{
184
0
  hmac_set_key_with_len(context, key, strlen((char *)key));
185
0
}
186
187
  static size_t
188
hmac_get_block_size(PurpleCipherContext *context)
189
0
{
190
0
  struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
191
192
0
  return hctx->blocksize;
193
0
}
194
195
static PurpleCipherOps HMACOps = {
196
  hmac_set_opt,           /* Set option */
197
  hmac_get_opt,           /* Get option */
198
  hmac_init,               /* init */
199
  hmac_reset,              /* reset */
200
  hmac_uninit,             /* uninit */
201
  NULL,                   /* set iv */
202
  hmac_append,             /* append */
203
  hmac_digest,             /* digest */
204
  NULL,                   /* encrypt */
205
  NULL,                   /* decrypt */
206
  NULL,                   /* set salt */
207
  NULL,                   /* get salt size */
208
  hmac_set_key,           /* set key */
209
  NULL,                   /* get key size */
210
  NULL,                   /* set batch mode */
211
  NULL,                   /* get batch mode */
212
  hmac_get_block_size,    /* get block size */
213
  hmac_set_key_with_len   /* set key with len */
214
};
215
216
PurpleCipherOps *
217
0
purple_hmac_cipher_get_ops(void) {
218
0
  return &HMACOps;
219
0
}
220