Coverage Report

Created: 2025-12-31 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pidgin/libpurple/ciphers/md4.c
Line
Count
Source
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
 * Original md4 taken from linux kernel
9
 * MD4 Message Digest Algorithm (RFC1320).
10
 *
11
 * Implementation derived from Andrew Tridgell and Steve French's
12
 * CIFS MD4 implementation, and the cryptoapi implementation
13
 * originally based on the public domain implementation written
14
 * by Colin Plumb in 1993.
15
 *
16
 * Copyright (c) Andrew Tridgell 1997-1998.
17
 * Modified by Steve French (sfrench@us.ibm.com) 2002
18
 * Copyright (c) Cryptoapi developers.
19
 * Copyright (c) 2002 David S. Miller (davem@redhat.com)
20
 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
21
 *
22
 * This program is free software; you can redistribute it and/or modify
23
 * it under the terms of the GNU General Public License as published by
24
 * the Free Software Foundation; either version 2 of the License, or
25
 * (at your option) any later version.
26
 *
27
 * This program is distributed in the hope that it will be useful,
28
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30
 * GNU General Public License for more details.
31
 *
32
 * You should have received a copy of the GNU General Public License
33
 * along with this program; if not, write to the Free Software
34
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
35
 */
36
#include <cipher.h>
37
38
#define MD4_DIGEST_SIZE     16
39
0
#define MD4_HMAC_BLOCK_SIZE 64
40
#define MD4_BLOCK_WORDS     16
41
#define MD4_HASH_WORDS      4
42
43
struct MD4_Context {
44
  guint32 hash[MD4_HASH_WORDS];
45
  guint32 block[MD4_BLOCK_WORDS];
46
  guint64 byte_count;
47
};
48
49
static inline guint32 lshift(guint32 x, unsigned int s)
50
0
{
51
0
  x &= 0xFFFFFFFF;
52
0
  return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
53
0
}
54
55
static inline guint32 F(guint32 x, guint32 y, guint32 z)
56
0
{
57
0
  return (x & y) | ((~x) & z);
58
0
}
59
60
static inline guint32 G(guint32 x, guint32 y, guint32 z)
61
0
{
62
0
  return (x & y) | (x & z) | (y & z);
63
0
}
64
65
static inline guint32 H(guint32 x, guint32 y, guint32 z)
66
0
{
67
0
  return x ^ y ^ z;
68
0
}
69
70
0
#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
71
0
#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (guint32)0x5A827999,s))
72
0
#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (guint32)0x6ED9EBA1,s))
73
74
static inline void le32_to_cpu_array(guint32 *buf, unsigned int words)
75
0
{
76
0
  while (words--) {
77
0
    *buf=GUINT_FROM_LE(*buf);
78
0
    buf++;
79
0
  }
80
0
}
81
82
static inline void cpu_to_le32_array(guint32 *buf, unsigned int words)
83
0
{
84
0
  while (words--) {
85
0
    *buf=GUINT_TO_LE(*buf);
86
0
    buf++;
87
0
  }
88
0
}
89
90
static void md4_transform(guint32 *hash, guint32 const *in)
91
0
{
92
0
  guint32 a, b, c, d;
93
94
0
  a = hash[0];
95
0
  b = hash[1];
96
0
  c = hash[2];
97
0
  d = hash[3];
98
99
0
  ROUND1(a, b, c, d, in[0], 3);
100
0
  ROUND1(d, a, b, c, in[1], 7);
101
0
  ROUND1(c, d, a, b, in[2], 11);
102
0
  ROUND1(b, c, d, a, in[3], 19);
103
0
  ROUND1(a, b, c, d, in[4], 3);
104
0
  ROUND1(d, a, b, c, in[5], 7);
105
0
  ROUND1(c, d, a, b, in[6], 11);
106
0
  ROUND1(b, c, d, a, in[7], 19);
107
0
  ROUND1(a, b, c, d, in[8], 3);
108
0
  ROUND1(d, a, b, c, in[9], 7);
109
0
  ROUND1(c, d, a, b, in[10], 11);
110
0
  ROUND1(b, c, d, a, in[11], 19);
111
0
  ROUND1(a, b, c, d, in[12], 3);
112
0
  ROUND1(d, a, b, c, in[13], 7);
113
0
  ROUND1(c, d, a, b, in[14], 11);
114
0
  ROUND1(b, c, d, a, in[15], 19);
115
116
0
  ROUND2(a, b, c, d,in[ 0], 3);
117
0
  ROUND2(d, a, b, c, in[4], 5);
118
0
  ROUND2(c, d, a, b, in[8], 9);
119
0
  ROUND2(b, c, d, a, in[12], 13);
120
0
  ROUND2(a, b, c, d, in[1], 3);
121
0
  ROUND2(d, a, b, c, in[5], 5);
122
0
  ROUND2(c, d, a, b, in[9], 9);
123
0
  ROUND2(b, c, d, a, in[13], 13);
124
0
  ROUND2(a, b, c, d, in[2], 3);
125
0
  ROUND2(d, a, b, c, in[6], 5);
126
0
  ROUND2(c, d, a, b, in[10], 9);
127
0
  ROUND2(b, c, d, a, in[14], 13);
128
0
  ROUND2(a, b, c, d, in[3], 3);
129
0
  ROUND2(d, a, b, c, in[7], 5);
130
0
  ROUND2(c, d, a, b, in[11], 9);
131
0
  ROUND2(b, c, d, a, in[15], 13);
132
133
0
  ROUND3(a, b, c, d,in[ 0], 3);
134
0
  ROUND3(d, a, b, c, in[8], 9);
135
0
  ROUND3(c, d, a, b, in[4], 11);
136
0
  ROUND3(b, c, d, a, in[12], 15);
137
0
  ROUND3(a, b, c, d, in[2], 3);
138
0
  ROUND3(d, a, b, c, in[10], 9);
139
0
  ROUND3(c, d, a, b, in[6], 11);
140
0
  ROUND3(b, c, d, a, in[14], 15);
141
0
  ROUND3(a, b, c, d, in[1], 3);
142
0
  ROUND3(d, a, b, c, in[9], 9);
143
0
  ROUND3(c, d, a, b, in[5], 11);
144
0
  ROUND3(b, c, d, a, in[13], 15);
145
0
  ROUND3(a, b, c, d, in[3], 3);
146
0
  ROUND3(d, a, b, c, in[11], 9);
147
0
  ROUND3(c, d, a, b, in[7], 11);
148
0
  ROUND3(b, c, d, a, in[15], 15);
149
150
0
  hash[0] += a;
151
0
  hash[1] += b;
152
0
  hash[2] += c;
153
0
  hash[3] += d;
154
0
}
155
156
static inline void md4_transform_helper(struct MD4_Context *ctx)
157
0
{
158
0
  le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(guint32));
159
0
  md4_transform(ctx->hash, ctx->block);
160
0
}
161
162
static void
163
0
md4_init(PurpleCipherContext *context, gpointer extra) {
164
0
  struct MD4_Context *mctx;
165
0
  mctx = g_new0(struct MD4_Context, 1);
166
0
  purple_cipher_context_set_data(context, mctx);
167
0
  purple_cipher_context_reset(context, extra);
168
169
0
  mctx->hash[0] = 0x67452301;
170
0
  mctx->hash[1] = 0xefcdab89;
171
0
  mctx->hash[2] = 0x98badcfe;
172
0
  mctx->hash[3] = 0x10325476;
173
0
  mctx->byte_count = 0;
174
0
}
175
176
static void
177
0
md4_reset(PurpleCipherContext *context, gpointer extra) {
178
0
  struct MD4_Context *mctx;
179
180
0
  mctx = purple_cipher_context_get_data(context);
181
182
0
  mctx->hash[0] = 0x67452301;
183
0
  mctx->hash[1] = 0xefcdab89;
184
0
  mctx->hash[2] = 0x98badcfe;
185
0
  mctx->hash[3] = 0x10325476;
186
0
  mctx->byte_count = 0;
187
0
}
188
189
  static void
190
md4_append(PurpleCipherContext *context, const guchar *data, size_t len)
191
0
{
192
0
  struct MD4_Context *mctx = purple_cipher_context_get_data(context);
193
0
  const guint32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
194
195
0
  mctx->byte_count += len;
196
197
0
  if (avail > len) {
198
0
    memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
199
0
        data, len);
200
0
    return;
201
0
  }
202
203
0
  memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
204
0
      data, avail);
205
206
0
  md4_transform_helper(mctx);
207
0
  data += avail;
208
0
  len -= avail;
209
210
0
  while (len >= sizeof(mctx->block)) {
211
0
    memcpy(mctx->block, data, sizeof(mctx->block));
212
0
    md4_transform_helper(mctx);
213
0
    data += sizeof(mctx->block);
214
0
    len -= sizeof(mctx->block);
215
0
  }
216
217
0
  memcpy(mctx->block, data, len);
218
0
}
219
220
  static gboolean
221
md4_digest(PurpleCipherContext *context, size_t in_len, guchar *out,
222
    size_t *out_len)
223
0
{
224
0
  struct MD4_Context *mctx = purple_cipher_context_get_data(context);
225
0
  const unsigned int offset = mctx->byte_count & 0x3f;
226
0
  char *p = (char *)mctx->block + offset;
227
0
  int padding = 56 - (offset + 1);
228
229
230
0
  if(in_len<16) return FALSE;
231
0
  if(out_len) *out_len = 16;
232
0
  *p++ = 0x80;
233
0
  if (padding < 0) {
234
0
    memset(p, 0x00, padding + sizeof (guint64));
235
0
    md4_transform_helper(mctx);
236
0
    p = (char *)mctx->block;
237
0
    padding = 56;
238
0
  }
239
240
0
  memset(p, 0, padding);
241
0
  mctx->block[14] = mctx->byte_count << 3;
242
0
  mctx->block[15] = mctx->byte_count >> 29;
243
0
  le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
244
0
        sizeof(guint64)) / sizeof(guint32));
245
0
  md4_transform(mctx->hash, mctx->block);
246
0
  cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(guint32));
247
0
  memcpy(out, mctx->hash, sizeof(mctx->hash));
248
0
  memset(mctx, 0, sizeof(*mctx));
249
0
  return TRUE;
250
0
}
251
252
static void
253
0
md4_uninit(PurpleCipherContext *context) {
254
0
  struct MD4_Context *md4_context;
255
256
0
  purple_cipher_context_reset(context, NULL);
257
258
0
  md4_context = purple_cipher_context_get_data(context);
259
0
  memset(md4_context, 0, sizeof(*md4_context));
260
261
0
  g_free(md4_context);
262
0
  md4_context = NULL;
263
0
}
264
265
  static size_t
266
md4_get_block_size(PurpleCipherContext *context)
267
0
{
268
  /* This does not change (in this case) */
269
0
  return MD4_HMAC_BLOCK_SIZE;
270
0
}
271
272
static PurpleCipherOps MD4Ops = {
273
  NULL,                   /* Set option */
274
  NULL,                   /* Get option */
275
  md4_init,               /* init */
276
  md4_reset,              /* reset */
277
  md4_uninit,             /* uninit */
278
  NULL,                   /* set iv */
279
  md4_append,             /* append */
280
  md4_digest,             /* digest */
281
  NULL,                   /* encrypt */
282
  NULL,                   /* decrypt */
283
  NULL,                   /* set salt */
284
  NULL,                   /* get salt size */
285
  NULL,                   /* set key */
286
  NULL,                   /* get key size */
287
  NULL,                   /* set batch mode */
288
  NULL,                   /* get batch mode */
289
  md4_get_block_size,     /* get block size */
290
  NULL                    /* set key with len */
291
};
292
293
PurpleCipherOps *
294
0
purple_md4_cipher_get_ops(void) {
295
0
  return &MD4Ops;
296
0
}
297