~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to libdrizzle/password.c

  • Committer: Brian Aker
  • Date: 2008-10-06 06:47:29 UTC
  • Revision ID: brian@tangent.org-20081006064729-2i9mhjkzyvow9xsm
RemoveĀ uint.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2006 MySQL AB
2
 
 
3
 
   This program is free software; you can redistribute it and/or modify
4
 
   it under the terms of the GNU General Public License as published by
5
 
   the Free Software Foundation; version 2 of the License.
6
 
 
7
 
   This program is distributed in the hope that it will be useful,
8
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 
   GNU General Public License for more details.
11
 
 
12
 
   You should have received a copy of the GNU General Public License
13
 
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2008 Sun Microsystems, Inc.
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; version 2 of the License.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 */
15
19
 
16
20
/* password checking routines */
17
21
/*****************************************************************************
58
62
 
59
63
*****************************************************************************/
60
64
 
61
 
#include <my_global.h>
62
 
#include <my_sys.h>
63
 
#include <m_string.h>
64
 
#include <sha1.h>
65
 
#include "drizzle.h"
 
65
#include "libdrizzle.h"
 
66
#include "libdrizzle_priv.h"
 
67
#include <stdlib.h>
 
68
#include <string.h>
66
69
 
67
70
/************ MySQL 3.23-4.0 authentication routines: untouched ***********/
68
71
 
77
80
 
78
81
void randominit(struct rand_struct *rand_st, uint32_t seed1, uint32_t seed2)
79
82
{                                               /* For mysql 3.21.# */
80
 
#ifdef HAVE_purify
81
 
  bzero((char*) rand_st,sizeof(*rand_st));      /* Avoid UMC varnings */
82
 
#endif
 
83
  memset(rand_st, 0, sizeof(*rand_st));      /* Avoid UMC varnings */
83
84
  rand_st->max_value= 0x3FFFFFFFL;
84
85
  rand_st->max_value_dbl=(double) rand_st->max_value;
85
86
  rand_st->seed1=seed1%rand_st->max_value ;
116
117
 
117
118
void hash_password(uint32_t *result, const char *password, uint32_t password_len)
118
119
{
119
 
  register ulong nr=1345345333L, add=7, nr2=0x12345671L;
 
120
  register uint32_t nr=1345345333L, add=7, nr2=0x12345671L;
120
121
  uint32_t tmp;
121
122
  const char *password_end= password + password_len;
122
123
  for (; password < password_end; password++)
123
124
  {
124
125
    if (*password == ' ' || *password == '\t')
125
126
      continue;                                 /* skip space in password */
126
 
    tmp= (uint32_t) (uchar) *password;
 
127
    tmp= (uint32_t) (unsigned char) *password;
127
128
    nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
128
129
    nr2+=(nr2 << 8) ^ nr;
129
130
    add+=tmp;
132
133
  result[1]=nr2 & (((uint32_t) 1L << 31) -1L);
133
134
}
134
135
 
135
 
static inline uint8 char_val(uint8 X)
 
136
static inline uint8_t char_val(uint8_t X)
136
137
{
137
 
  return (uint) (X >= '0' && X <= '9' ? X-'0' :
 
138
  return (uint32_t) (X >= '0' && X <= '9' ? X-'0' :
138
139
      X >= 'A' && X <= 'Z' ? X-'A'+10 : X-'a'+10);
139
140
}
140
141
 
153
154
    rand_st  INOUT structure used for number generation
154
155
*/
155
156
 
156
 
void create_random_string(char *to, uint length, struct rand_struct *rand_st)
 
157
void create_random_string(char *to, uint32_t length, struct rand_struct *rand_st)
157
158
{
158
159
  char *end= to + length;
159
160
  /* Use pointer arithmetics as it is faster way to do so. */
180
181
    buf+len*2
181
182
*/
182
183
 
183
 
char *octet2hex(char *to, const char *str, uint len)
 
184
char *octet2hex(char *to, const char *str, uint32_t len)
184
185
{
185
186
  const char *str_end= str + len; 
186
187
  for (; str != str_end; ++str)
187
188
  {
188
 
    *to++= _dig_vec_upper[((uchar) *str) >> 4];
189
 
    *to++= _dig_vec_upper[((uchar) *str) & 0x0F];
 
189
    *to++= _dig_vec_upper[((unsigned char) *str) >> 4];
 
190
    *to++= _dig_vec_upper[((unsigned char) *str) & 0x0F];
190
191
  }
191
192
  *to= '\0';
192
193
  return to;
193
194
}
194
 
 
195
 
 
196
 
/*
197
 
    Convert given asciiz string of hex (0..9 a..f) characters to octet
198
 
    sequence.
199
 
  SYNOPSIS
200
 
    hex2octet()
201
 
    to        OUT buffer to place result; must be at least len/2 bytes
202
 
    str, len  IN  begin, length for character string; str and to may not
203
 
                  overlap; len % 2 == 0
204
 
*/ 
205
 
 
206
 
static void
207
 
hex2octet(uint8 *to, const char *str, uint len)
208
 
{
209
 
  const char *str_end= str + len;
210
 
  while (str < str_end)
211
 
  {
212
 
    register char tmp= char_val(*str++);
213
 
    *to++= (tmp << 4) | char_val(*str++);
214
 
  }
215
 
}
216
 
 
217
 
 
218
 
/*
219
 
    Encrypt/Decrypt function used for password encryption in authentication.
220
 
    Simple XOR is used here but it is OK as we crypt random strings. Note,
221
 
    that XOR(s1, XOR(s1, s2)) == s2, XOR(s1, s2) == XOR(s2, s1)
222
 
  SYNOPSIS
223
 
    my_crypt()
224
 
    to      OUT buffer to hold crypted string; must be at least len bytes
225
 
                long; to and s1 (or s2) may be the same.
226
 
    s1, s2  IN  input strings (of equal length)
227
 
    len     IN  length of s1 and s2
228
 
*/
229
 
 
230
 
static void
231
 
my_crypt(char *to, const uchar *s1, const uchar *s2, uint len)
232
 
{
233
 
  const uint8 *s1_end= s1 + len;
234
 
  while (s1 < s1_end)
235
 
    *to++= *s1++ ^ *s2++;
236
 
}
237
 
 
238
 
 
239
 
/*
240
 
    MySQL 4.1.1 password hashing: SHA conversion (see RFC 2289, 3174) twice
241
 
    applied to the password string, and then produced octet sequence is
242
 
    converted to hex string.
243
 
    The result of this function is used as return value from PASSWORD() and
244
 
    is stored in the database.
245
 
  SYNOPSIS
246
 
    make_scrambled_password()
247
 
    buf       OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string
248
 
    password  IN  NULL-terminated password string
249
 
*/
250
 
 
251
 
void
252
 
make_scrambled_password(char *to, const char *password)
253
 
{
254
 
  SHA1_CONTEXT sha1_context;
255
 
  uint8 hash_stage2[SHA1_HASH_SIZE];
256
 
 
257
 
  mysql_sha1_reset(&sha1_context);
258
 
  /* stage 1: hash password */
259
 
  mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) strlen(password));
260
 
  mysql_sha1_result(&sha1_context, (uint8 *) to);
261
 
  /* stage 2: hash stage1 output */
262
 
  mysql_sha1_reset(&sha1_context);
263
 
  mysql_sha1_input(&sha1_context, (uint8 *) to, SHA1_HASH_SIZE);
264
 
  /* separate buffer is used to pass 'to' in octet2hex */
265
 
  mysql_sha1_result(&sha1_context, hash_stage2);
266
 
  /* convert hash_stage2 to hex string */
267
 
  *to++= PVERSION41_CHAR;
268
 
  octet2hex(to, (const char*) hash_stage2, SHA1_HASH_SIZE);
269
 
}
270
 
  
271
 
 
272
 
/*
273
 
    Produce an obscure octet sequence from password and random
274
 
    string, recieved from the server. This sequence corresponds to the
275
 
    password, but password can not be easily restored from it. The sequence
276
 
    is then sent to the server for validation. Trailing zero is not stored
277
 
    in the buf as it is not needed.
278
 
    This function is used by client to create authenticated reply to the
279
 
    server's greeting.
280
 
  SYNOPSIS
281
 
    scramble()
282
 
    buf       OUT store scrambled string here. The buf must be at least 
283
 
                  SHA1_HASH_SIZE bytes long. 
284
 
    message   IN  random message, must be exactly SCRAMBLE_LENGTH long and 
285
 
                  NULL-terminated.
286
 
    password  IN  users' password 
287
 
*/
288
 
 
289
 
void
290
 
scramble(char *to, const char *message, const char *password)
291
 
{
292
 
  SHA1_CONTEXT sha1_context;
293
 
  uint8 hash_stage1[SHA1_HASH_SIZE];
294
 
  uint8 hash_stage2[SHA1_HASH_SIZE];
295
 
 
296
 
  mysql_sha1_reset(&sha1_context);
297
 
  /* stage 1: hash password */
298
 
  mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) strlen(password));
299
 
  mysql_sha1_result(&sha1_context, hash_stage1);
300
 
  /* stage 2: hash stage 1; note that hash_stage2 is stored in the database */
301
 
  mysql_sha1_reset(&sha1_context);
302
 
  mysql_sha1_input(&sha1_context, hash_stage1, SHA1_HASH_SIZE);
303
 
  mysql_sha1_result(&sha1_context, hash_stage2);
304
 
  /* create crypt string as sha1(message, hash_stage2) */;
305
 
  mysql_sha1_reset(&sha1_context);
306
 
  mysql_sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH);
307
 
  mysql_sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
308
 
  /* xor allows 'from' and 'to' overlap: lets take advantage of it */
309
 
  mysql_sha1_result(&sha1_context, (uint8 *) to);
310
 
  my_crypt(to, (const uchar *) to, hash_stage1, SCRAMBLE_LENGTH);
311
 
}
312
 
 
313
 
 
314
 
/*
315
 
    Check that scrambled message corresponds to the password; the function
316
 
    is used by server to check that recieved reply is authentic.
317
 
    This function does not check lengths of given strings: message must be
318
 
    null-terminated, reply and hash_stage2 must be at least SHA1_HASH_SIZE
319
 
    long (if not, something fishy is going on).
320
 
  SYNOPSIS
321
 
    check_scramble()
322
 
    scramble     clients' reply, presumably produced by scramble()
323
 
    message      original random string, previously sent to client
324
 
                 (presumably second argument of scramble()), must be 
325
 
                 exactly SCRAMBLE_LENGTH long and NULL-terminated.
326
 
    hash_stage2  hex2octet-decoded database entry
327
 
    All params are IN.
328
 
 
329
 
  RETURN VALUE
330
 
    0  password is correct
331
 
    !0  password is invalid
332
 
*/
333
 
 
334
 
my_bool
335
 
check_scramble(const char *scramble_arg, const char *message,
336
 
               const uint8 *hash_stage2)
337
 
{
338
 
  SHA1_CONTEXT sha1_context;
339
 
  uint8 buf[SHA1_HASH_SIZE];
340
 
  uint8 hash_stage2_reassured[SHA1_HASH_SIZE];
341
 
 
342
 
  mysql_sha1_reset(&sha1_context);
343
 
  /* create key to encrypt scramble */
344
 
  mysql_sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH);
345
 
  mysql_sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
346
 
  mysql_sha1_result(&sha1_context, buf);
347
 
  /* encrypt scramble */
348
 
    my_crypt((char *) buf, buf, (const uchar *) scramble_arg, SCRAMBLE_LENGTH);
349
 
  /* now buf supposedly contains hash_stage1: so we can get hash_stage2 */
350
 
  mysql_sha1_reset(&sha1_context);
351
 
  mysql_sha1_input(&sha1_context, buf, SHA1_HASH_SIZE);
352
 
  mysql_sha1_result(&sha1_context, hash_stage2_reassured);
353
 
  return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE);
354
 
}
355
 
 
356
 
 
357
 
/*
358
 
  Convert scrambled password from asciiz hex string to binary form.
359
 
 
360
 
  SYNOPSIS
361
 
    get_salt_from_password()
362
 
    res       OUT buf to hold password. Must be at least SHA1_HASH_SIZE
363
 
                  bytes long.
364
 
    password  IN  4.1.1 version value of user.password
365
 
*/
366
 
    
367
 
void get_salt_from_password(uint8 *hash_stage2, const char *password)
368
 
{
369
 
  hex2octet(hash_stage2, password+1 /* skip '*' */, SHA1_HASH_SIZE * 2);
370
 
}
371
 
 
372
 
/*
373
 
    Convert scrambled password from binary form to asciiz hex string.
374
 
  SYNOPSIS
375
 
    make_password_from_salt()
376
 
    to    OUT store resulting string here, 2*SHA1_HASH_SIZE+2 bytes 
377
 
    salt  IN  password in salt format
378
 
*/
379
 
 
380
 
void make_password_from_salt(char *to, const uint8 *hash_stage2)
381
 
{
382
 
  *to++= PVERSION41_CHAR;
383
 
  octet2hex(to, (const char*) hash_stage2, SHA1_HASH_SIZE);
384
 
}