/*
Copyright ( c ) 2000 , 2011 , Oracle and / or its affiliates .
Copyright ( c ) 2012 , Monty Program Ab
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; version 2 of the License .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
/* password checking routines */
/*****************************************************************************
The main idea is that no password are sent between client & server on
connection and that no password are saved in mysql in a decodable form .
On connection a random string is generated and sent to the client .
The client generates a new string with a random generator inited with
the hash values from the password and the sent string .
This ' check ' string is sent to the server where it is compared with
a string generated from the stored hash_value of the password and the
random string .
The password is saved ( in user . password ) by using the PASSWORD ( ) function in
mysql .
This is . c file because it ' s used in libmysqlclient , which is entirely in C .
( we need it to be portable to a variety of systems ) .
Example :
update user set password = PASSWORD ( " hello " ) where user = " test "
This saves a hashed number as a string in the password field .
The new authentication is performed in following manner :
SERVER : public_seed = thd_create_random_password ( )
send ( public_seed )
CLIENT : recv ( public_seed )
hash_stage1 = sha1 ( " password " )
hash_stage2 = sha1 ( hash_stage1 )
reply = xor ( hash_stage1 , sha1 ( public_seed , hash_stage2 )
// this three steps are done in scramble()
send ( reply )
SERVER : recv ( reply )
hash_stage1 = xor ( reply , sha1 ( public_seed , hash_stage2 ) )
candidate_hash2 = sha1 ( hash_stage1 )
check ( candidate_hash2 = = hash_stage2 )
// this three steps are done in check_scramble()
*****************************************************************************/
#include "mariadb.h"
#include <my_sys.h>
#include <m_string.h>
#include <password.h>
#include <mysql.h>
#include <my_rnd.h>
/************ MySQL 3.23-4.0 authentication routines: untouched ***********/
/*
New ( MySQL 3 . 21 + ) random generation structure initialization
SYNOPSIS
my_rnd_init ( )
rand_st OUT Structure to initialize
seed1 IN First initialization parameter
seed2 IN Second initialization parameter
*/
/*
Generate binary hash from raw text string
Used for Pre - 4 . 1 password handling
SYNOPSIS
hash_password ( )
result OUT store hash in this location
password IN plain text password to build hash
password_len IN password length ( password may be not null - terminated )
*/
void hash_password(ulong *result, const char *password, uint password_len)
{
ulong nr=1345345333 L, add=7 , nr2=0 x12345671L;
ulong tmp;
const char *password_end= password + password_len;
for (; password < password_end; password++)
{
if (*password == ' ' || *password == '\t' )
continue ; /* skip space in password */
tmp= (ulong) (uchar) *password;
nr^= (((nr & 63 )+add)*tmp)+ (nr << 8 );
nr2+=(nr2 << 8 ) ^ nr;
add+=tmp;
}
result[0 ]=nr & (((ulong) 1 L << 31 ) -1 L); /* Don't use sign bit (str2int) */;
result[1 ]=nr2 & (((ulong) 1 L << 31 ) -1 L);
}
/*
Create password to be stored in user database from raw string
Used for pre - 4 . 1 password handling
SYNOPSIS
my_make_scrambled_password_323 ( )
to OUT store scrambled password here
password IN user - supplied password
pass_len IN length of password string
*/
void my_make_scrambled_password_323(char *to, const char *password,
size_t pass_len)
{
ulong hash_res[2 ];
hash_password(hash_res, password, (uint) pass_len);
snprintf(to, SCRAMBLED_PASSWORD_CHAR_LENGTH_323 + 1 ,
"%08lx%08lx" , hash_res[0 ], hash_res[1 ]);
}
/*
Wrapper around my_make_scrambled_password_323 ( ) to maintain client lib ABI
compatibility .
In server code usage of my_make_scrambled_password_323 ( ) is preferred to
avoid strlen ( ) .
SYNOPSIS
make_scrambled_password_323 ( )
to OUT store scrambled password here
password IN NULL - terminated string with user - supplied password
*/
void make_scrambled_password_323(char *to, const char *password)
{
my_make_scrambled_password_323(to, password, strlen(password));
}
/*
Scramble string with password .
Used in pre 4 . 1 authentication phase .
SYNOPSIS
scramble_323 ( )
to OUT Store scrambled message here . Buffer must be at least
SCRAMBLE_LENGTH_323 + 1 bytes long
message IN Message to scramble . Message must be at least
SRAMBLE_LENGTH_323 bytes long .
password IN Password to use while scrambling
*/
void scramble_323(char *to, const char *message, const char *password)
{
struct my_rnd_struct rand_st;
ulong hash_pass[2 ], hash_message[2 ];
if (password && password[0 ])
{
char extra, *to_start=to;
const char *message_end= message + SCRAMBLE_LENGTH_323;
hash_password(hash_pass,password, (uint) strlen(password));
hash_password(hash_message, message, SCRAMBLE_LENGTH_323);
my_rnd_init(&rand_st,hash_pass[0 ] ^ hash_message[0 ],
hash_pass[1 ] ^ hash_message[1 ]);
for (; message < message_end; message++)
*to++= (char ) (floor(my_rnd(&rand_st)*31 )+64 );
extra=(char ) (floor(my_rnd(&rand_st)*31 ));
while (to_start != to)
*(to_start++)^=extra;
}
*to= 0 ;
}
/**
Check scrambled message . Used in pre 4 . 1 password handling .
@ param scrambled Scrambled message to check .
@ param message Original random message which was used for scrambling .
@ param hash_pass Password which should be used for scrambling .
@ remark scrambled and message must be SCRAMBLED_LENGTH_323 bytes long .
@ return FALSE if password is correct , TRUE otherwise .
*/
my_bool
check_scramble_323(const unsigned char *scrambled, const char *message,
ulong *hash_pass)
{
struct my_rnd_struct rand_st;
ulong hash_message[2 ];
/* Big enough for checks. */
uchar buff[16 ], scrambled_buff[SCRAMBLE_LENGTH_323 + 1 ];
uchar *to, extra;
const uchar *pos;
/* Ensure that the scrambled message is null-terminated. */
memcpy(scrambled_buff, scrambled, SCRAMBLE_LENGTH_323);
scrambled_buff[SCRAMBLE_LENGTH_323]= '\0' ;
scrambled= scrambled_buff;
hash_password(hash_message, message, SCRAMBLE_LENGTH_323);
my_rnd_init(&rand_st,hash_pass[0 ] ^ hash_message[0 ],
hash_pass[1 ] ^ hash_message[1 ]);
to=buff;
DBUG_ASSERT(sizeof (buff) > SCRAMBLE_LENGTH_323);
for (pos=scrambled ; *pos && to < buff+sizeof (buff) ; pos++)
*to++=(char ) (floor(my_rnd(&rand_st)*31 )+64 );
if (pos-scrambled != SCRAMBLE_LENGTH_323)
return 1 ;
extra=(char ) (floor(my_rnd(&rand_st)*31 ));
to=buff;
while (*scrambled)
{
if (*scrambled++ != (uchar) (*to++ ^ extra))
return 1 ; /* Wrong password */
}
return 0 ;
}
static inline uint8 char_val(uint8 X)
{
return (uint) (X >= '0' && X <= '9' ? X-'0' :
X >= 'A' && X <= 'Z' ? X-'A' +10 : X-'a' +10 );
}
/*
Convert password from hex string ( as stored in mysql . user ) to binary form .
SYNOPSIS
get_salt_from_password_323 ( )
res OUT store salt here
password IN password string as stored in mysql . user
NOTE
This function does not have length check for passwords . It will just crash
Password hashes in old format must have length divisible by 8
*/
void get_salt_from_password_323(ulong *res, const char *password)
{
res[0 ]= res[1 ]= 0 ;
if (password)
{
while (*password)
{
ulong val=0 ;
uint i;
for (i=0 ; i < 8 ; i++)
val=(val << 4 )+char_val(*password++);
*res++=val;
}
}
}
/*
Convert scrambled password from binary form to asciiz hex string .
SYNOPSIS
make_password_from_salt_323 ( )
to OUT store resulting string password here , at least 17 bytes
salt IN password in salt format , 2 ulongs
*/
void make_password_from_salt_323(char *to, const ulong *salt)
{
snprintf(to, SCRAMBLED_PASSWORD_CHAR_LENGTH_323 + 1 ,
"%08lx%08lx" , salt[0 ], salt[1 ]);
}
/*
* * * * * * * * * * * * * * * * MySQL 4 . 1 . 1 authentication routines * * * * * * * * * * * * *
*/
/* Character to use as version identifier for version 4.1 */
#define PVERSION41_CHAR '*'
/*
Convert given octet sequence to asciiz string of hex characters ;
str . . str + len and ' to ' may not overlap .
SYNOPSIS
octet2hex ( )
buf OUT output buffer . Must be at least 2 * len + 1 bytes
str , len IN the beginning and the length of the input string
RETURN
buf + len * 2
*/
char *octet2hex(char *to, const uchar *str, size_t len)
{
const uchar *str_end= str + len;
for (; str != str_end; ++str)
{
*to++= _dig_vec_upper[*str >> 4 ];
*to++= _dig_vec_upper[*str & 0 x0F];
}
*to= '\0' ;
return to;
}
/*
Convert given asciiz string of hex ( 0 . . 9 a . . f ) characters to octet
sequence .
SYNOPSIS
hex2octet ( )
to OUT buffer to place result ; must be at least len / 2 bytes
str , len IN begin , length for character string ; str and to may not
overlap ; len % 2 = = 0
*/
static void
hex2octet(uint8 *to, const char *str, uint len)
{
const char *str_end= str + len;
while (str < str_end)
{
char tmp= char_val(*str++);
*to++= (tmp << 4 ) | char_val(*str++);
}
}
/*
Encrypt / Decrypt function used for password encryption in authentication .
Simple XOR is used here but it is OK as we crypt random strings . Note ,
that XOR ( s1 , XOR ( s1 , s2 ) ) = = s2 , XOR ( s1 , s2 ) = = XOR ( s2 , s1 )
SYNOPSIS
my_crypt ( )
to OUT buffer to hold crypted string ; must be at least len bytes
long ; to and s1 ( or s2 ) may be the same .
s1 , s2 IN input strings ( of equal length )
len IN length of s1 and s2
*/
static void
my_crypt(char *to, const uchar *s1, const uchar *s2, uint len)
{
const uint8 *s1_end= s1 + len;
while (s1 < s1_end)
*to++= *s1++ ^ *s2++;
}
/**
Compute two stage SHA1 hash of the password :
hash_stage1 = sha1 ( " password " )
hash_stage2 = sha1 ( hash_stage1 )
@ param password [ IN ] Password string .
@ param pass_len [ IN ] Length of the password .
@ param hash_stage1 [ OUT ] sha1 ( password )
@ param hash_stage2 [ OUT ] sha1 ( hash_stage1 )
*/
inline static
void compute_two_stage_sha1_hash(const char *password, size_t pass_len,
uint8 *hash_stage1, uint8 *hash_stage2)
{
/* Stage 1: hash password */
my_sha1(hash_stage1, password, pass_len);
/* Stage 2 : hash first stage's output. */
my_sha1(hash_stage2, (const char *) hash_stage1, MY_SHA1_HASH_SIZE);
}
/*
MySQL 4 . 1 . 1 password hashing : SHA conversion ( see RFC 2289 , 3174 ) twice
applied to the password string , and then produced octet sequence is
converted to hex string .
The result of this function is used as return value from PASSWORD ( ) and
is stored in the database .
SYNOPSIS
my_make_scrambled_password ( )
buf OUT buffer of size 2 * MY_SHA1_HASH_SIZE + 2 to store hex string
password IN password string
pass_len IN length of password string
*/
void my_make_scrambled_password(char *to, const char *password,
size_t pass_len)
{
uint8 hash_stage2[MY_SHA1_HASH_SIZE];
/* Two stage SHA1 hash of the password. */
compute_two_stage_sha1_hash(password, pass_len, (uint8 *) to, hash_stage2);
/* convert hash_stage2 to hex string */
*to++= PVERSION41_CHAR;
octet2hex(to, hash_stage2, MY_SHA1_HASH_SIZE);
}
/*
Wrapper around my_make_scrambled_password ( ) to maintain client lib ABI
compatibility .
In server code usage of my_make_scrambled_password ( ) is preferred to
avoid strlen ( ) .
SYNOPSIS
make_scrambled_password ( )
buf OUT buffer of size 2 * MY_SHA1_HASH_SIZE + 2 to store hex string
password IN NULL - terminated password string
*/
void make_scrambled_password(char *to, const char *password)
{
my_make_scrambled_password(to, password, strlen(password));
}
/*
Produce an obscure octet sequence from password and random
string , received from the server . This sequence corresponds to the
password , but password can not be easily restored from it . The sequence
is then sent to the server for validation . Trailing zero is not stored
in the buf as it is not needed .
This function is used by client to create authenticated reply to the
server ' s greeting .
SYNOPSIS
scramble ( )
buf OUT store scrambled string here . The buf must be at least
MY_SHA1_HASH_SIZE bytes long .
message IN random message , must be exactly SCRAMBLE_LENGTH long and
NULL - terminated .
password IN users ' password
*/
void
scramble(char *to, const char *message, const char *password)
{
uint8 hash_stage1[MY_SHA1_HASH_SIZE];
uint8 hash_stage2[MY_SHA1_HASH_SIZE];
/* Two stage SHA1 hash of the password. */
compute_two_stage_sha1_hash(password, strlen(password), hash_stage1,
hash_stage2);
/* create crypt string as sha1(message, hash_stage2) */;
my_sha1_multi((uint8 *) to, message, SCRAMBLE_LENGTH,
(const char *) hash_stage2, MY_SHA1_HASH_SIZE, NULL);
my_crypt(to, (const uchar *) to, hash_stage1, SCRAMBLE_LENGTH);
}
/*
Check that scrambled message corresponds to the password ; the function
is used by server to check that received reply is authentic .
This function does not check lengths of given strings : message must be
null - terminated , reply and hash_stage2 must be at least MY_SHA1_HASH_SIZE
long ( if not , something fishy is going on ) .
SYNOPSIS
check_scramble ( )
scramble clients ' reply , presumably produced by scramble ( )
message original random string , previously sent to client
( presumably second argument of scramble ( ) ) , must be
exactly SCRAMBLE_LENGTH long and NULL - terminated .
hash_stage2 hex2octet - decoded database entry
All params are IN .
RETURN VALUE
0 password is correct
! 0 password is invalid
*/
my_bool
check_scramble(const uchar *scramble_arg, const char *message,
const uint8 *hash_stage2)
{
uint8 buf[MY_SHA1_HASH_SIZE];
uint8 hash_stage2_reassured[MY_SHA1_HASH_SIZE];
/* create key to encrypt scramble */
my_sha1_multi(buf, message, SCRAMBLE_LENGTH,
(const char *) hash_stage2, MY_SHA1_HASH_SIZE, NULL);
/* encrypt scramble */
my_crypt((char *) buf, buf, scramble_arg, SCRAMBLE_LENGTH);
/* now buf supposedly contains hash_stage1: so we can get hash_stage2 */
my_sha1(hash_stage2_reassured, (const char *) buf, MY_SHA1_HASH_SIZE);
return MY_TEST(memcmp(hash_stage2, hash_stage2_reassured, MY_SHA1_HASH_SIZE));
}
/*
Convert scrambled password from asciiz hex string to binary form .
SYNOPSIS
get_salt_from_password ( )
res OUT buf to hold password . Must be at least MY_SHA1_HASH_SIZE
bytes long .
password IN 4 . 1 . 1 version value of user . password
*/
void get_salt_from_password(uint8 *hash_stage2, const char *password)
{
hex2octet(hash_stage2, password+1 /* skip '*' */, MY_SHA1_HASH_SIZE * 2);
}
/*
Convert scrambled password from binary form to asciiz hex string .
SYNOPSIS
make_password_from_salt ( )
to OUT store resulting string here , 2 * MY_SHA1_HASH_SIZE + 2 bytes
salt IN password in salt format
*/
void make_password_from_salt(char *to, const uint8 *hash_stage2)
{
*to++= PVERSION41_CHAR;
octet2hex(to, hash_stage2, MY_SHA1_HASH_SIZE);
}
Messung V0.5 in Prozent C=93 H=84 G=88
¤ Dauer der Verarbeitung: 0.21 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland