source: trunk/libtransmission/crypto-utils.c

Last change on this file was 14618, checked in by mikedld, 5 years ago

Reserve a few more bytes for base64 operations to prevent heap corruption

  • Property svn:keywords set to Date Rev Author Id
File size: 6.3 KB
Line 
1/*
2 * This file Copyright (C) 2007-2014 Mnemosyne LLC
3 *
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
6 *
7 * $Id: crypto-utils.c 14618 2015-12-13 01:29:39Z mikedld $
8 */
9
10#include <assert.h>
11#include <stdarg.h>
12#include <stdlib.h> /* abs (), srand (), rand () */
13#include <string.h> /* memcpy (), memmove (), memset (), strcmp (), strlen () */
14
15#include <b64/cdecode.h>
16#include <b64/cencode.h>
17
18#include "transmission.h"
19#include "crypto-utils.h"
20#include "utils.h"
21
22/***
23****
24***/
25
26void
27tr_dh_align_key (uint8_t * key_buffer,
28                 size_t    key_size,
29                 size_t    buffer_size)
30{
31  assert (key_size <= buffer_size);
32
33  /* DH can generate key sizes that are smaller than the size of
34     key buffer with exponentially decreasing probability, in which case
35     the msb's of key buffer need to be zeroed appropriately. */
36  if (key_size < buffer_size)
37    {
38      const size_t offset = buffer_size - key_size;
39      memmove (key_buffer + offset, key_buffer, key_size);
40      memset (key_buffer, 0, offset);
41    }
42}
43
44/***
45****
46***/
47
48bool
49tr_sha1 (uint8_t    * hash,
50         const void * data1,
51         int          data1_length,
52                      ...)
53{
54  tr_sha1_ctx_t sha;
55
56  if ((sha = tr_sha1_init ()) == NULL)
57    return false;
58
59  if (tr_sha1_update (sha, data1, data1_length))
60    {
61      va_list vl;
62      const void * data;
63
64      va_start (vl, data1_length);
65      while ((data = va_arg (vl, const void *)) != NULL)
66        {
67          const int data_length = va_arg (vl, int);
68          assert (data_length >= 0);
69          if (!tr_sha1_update (sha, data, data_length))
70            break;
71        }
72      va_end (vl);
73
74      /* did we reach the end of argument list? */
75      if (data == NULL)
76        return tr_sha1_final (sha, hash);
77    }
78
79  tr_sha1_final (sha, NULL);
80  return false;
81}
82
83/***
84****
85***/
86
87int
88tr_rand_int (int upper_bound)
89{
90  int noise;
91
92  assert (upper_bound > 0);
93
94  while (tr_rand_buffer (&noise, sizeof (noise)))
95    {
96      noise = abs(noise) % upper_bound;
97      /* abs(INT_MIN) is undefined and could return negative value */
98      if (noise >= 0)
99        return noise;
100    }
101
102  /* fall back to a weaker implementation... */
103  return tr_rand_int_weak (upper_bound);
104}
105
106int
107tr_rand_int_weak (int upper_bound)
108{
109  static bool init = false;
110
111  assert (upper_bound > 0);
112
113  if (!init)
114    {
115      srand (tr_time_msec ());
116      init = true;
117    }
118
119  return rand () % upper_bound;
120}
121
122/***
123****
124***/
125
126char *
127tr_ssha1 (const char * plain_text)
128{
129  enum { saltval_len = 8,
130         salter_len  = 64 };
131  static const char * salter = "0123456789"
132                               "abcdefghijklmnopqrstuvwxyz"
133                               "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
134                               "./";
135
136  size_t i;
137  unsigned char salt[saltval_len];
138  uint8_t sha[SHA_DIGEST_LENGTH];
139  char buf[2 * SHA_DIGEST_LENGTH + saltval_len + 2];
140
141  tr_rand_buffer (salt, saltval_len);
142  for (i = 0; i < saltval_len; ++i)
143    salt[i] = salter[salt[i] % salter_len];
144
145  tr_sha1 (sha, plain_text, strlen (plain_text), salt, (size_t) saltval_len, NULL);
146  tr_sha1_to_hex (&buf[1], sha);
147  memcpy (&buf[1 + 2 * SHA_DIGEST_LENGTH], &salt, saltval_len);
148  buf[1 + 2 * SHA_DIGEST_LENGTH + saltval_len] = '\0';
149  buf[0] = '{'; /* signal that this is a hash. this makes saving/restoring easier */
150
151  return tr_strdup (buf);
152}
153
154bool
155tr_ssha1_matches (const char * ssha1,
156                  const char * plain_text)
157{
158  char * salt;
159  size_t saltlen;
160  char * my_ssha1;
161  uint8_t buf[SHA_DIGEST_LENGTH];
162  bool result;
163  const size_t sourcelen = strlen (ssha1);
164
165  /* extract the salt */
166  if (sourcelen < 2 * SHA_DIGEST_LENGTH - 1)
167    return false;
168  saltlen = sourcelen - 2 * SHA_DIGEST_LENGTH - 1;
169  salt = tr_malloc (saltlen);
170  memcpy (salt, ssha1 + 2 * SHA_DIGEST_LENGTH + 1, saltlen);
171
172  /* hash pass + salt */
173  my_ssha1 = tr_malloc (2 * SHA_DIGEST_LENGTH + saltlen + 2);
174  tr_sha1 (buf, plain_text, strlen (plain_text), salt, saltlen, NULL);
175  tr_sha1_to_hex (&my_ssha1[1], buf);
176  memcpy (my_ssha1 + 1 + 2 * SHA_DIGEST_LENGTH, salt, saltlen);
177  my_ssha1[1 + 2 * SHA_DIGEST_LENGTH + saltlen] = '\0';
178  my_ssha1[0] = '{';
179
180  result = strcmp (ssha1, my_ssha1) == 0;
181
182  tr_free (my_ssha1);
183  tr_free (salt);
184
185  return result;
186}
187
188/***
189****
190***/
191
192void *
193tr_base64_encode (const void * input,
194                  size_t       input_length,
195                  size_t     * output_length)
196{
197  char * ret;
198
199  if (input != NULL)
200    {
201      if (input_length != 0)
202        {
203          size_t ret_length = 4 * ((input_length + 2) / 3);
204          base64_encodestate state;
205
206#ifdef USE_SYSTEM_B64
207          /* Additional space is needed for newlines if we're using unpatched libb64 */
208          ret_length += ret_length / 72 + 1;
209#endif
210
211          ret = tr_new (char, ret_length + 8);
212
213          base64_init_encodestate (&state);
214          ret_length = base64_encode_block (input, input_length, ret, &state);
215          ret_length += base64_encode_blockend (ret + ret_length, &state);
216
217          if (output_length != NULL)
218            *output_length = ret_length;
219
220          ret[ret_length] = '\0';
221
222          return ret;
223        }
224      else
225        ret = tr_strdup ("");
226    }
227  else
228    {
229      ret = NULL;
230    }
231
232  if (output_length != NULL)
233    *output_length = 0;
234
235  return ret;
236}
237
238void *
239tr_base64_encode_str (const char * input,
240                      size_t     * output_length)
241{
242  return tr_base64_encode (input, input == NULL ? 0 : strlen (input), output_length);
243}
244
245void *
246tr_base64_decode (const void * input,
247                  size_t       input_length,
248                  size_t     * output_length)
249{
250  char * ret;
251
252  if (input != NULL)
253    {
254      if (input_length != 0)
255        {
256          size_t ret_length = input_length / 4 * 3;
257          base64_decodestate state;
258
259          ret = tr_new (char, ret_length + 8);
260
261          base64_init_decodestate (&state);
262          ret_length = base64_decode_block (input, input_length, ret, &state);
263
264          if (output_length != NULL)
265            *output_length = ret_length;
266
267          ret[ret_length] = '\0';
268
269          return ret;
270        }
271      else
272        ret = tr_strdup ("");
273    }
274  else
275    {
276      ret = NULL;
277    }
278
279  if (output_length != NULL)
280    *output_length = 0;
281
282  return ret;
283}
284
285void *
286tr_base64_decode_str (const char * input,
287                      size_t     * output_length)
288{
289  return tr_base64_decode (input, input == NULL ? 0 : strlen (input), output_length);
290}
Note: See TracBrowser for help on using the repository browser.