Changeset 6e1fed7 for storage_xml.c


Ignore:
Timestamp:
2006-06-25T17:07:25Z (13 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
88086db
Parents:
7ed3199
Message:

Using salted MD5 checksums for the user's BitlBee password and salted RC4
encryption for the IM account passwords, plus some calls to srand() to keep
the salts secure and unique.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • storage_xml.c

    r7ed3199 r6e1fed7  
    2626#define BITLBEE_CORE
    2727#include "bitlbee.h"
     28#include "base64.h"
     29#include "rc4.h"
    2830#include "md5.h"
    2931
     
    7880                char *nick = xml_attr( attr_names, attr_values, "nick" );
    7981                char *pass = xml_attr( attr_names, attr_values, "password" );
     82                md5_byte_t *pass_dec = NULL;
    8083               
    8184                if( !nick || !pass )
     
    8487                                     "Missing attributes for %s element", element_name );
    8588                }
     89                else if( base64_decode( pass, &pass_dec ) != 21 )
     90                {
     91                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
     92                                     "Error while decoding password attribute" );
     93                }
    8694                else
    8795                {
    8896                        md5_byte_t pass_md5[16];
    8997                        md5_state_t md5_state;
    90                         int i, j;
     98                        int i;
    9199                       
    92100                        md5_init( &md5_state );
    93101                        md5_append( &md5_state, (md5_byte_t*) xd->given_pass, strlen( xd->given_pass ) );
     102                        md5_append( &md5_state, (md5_byte_t*) pass_dec + 16, 5 ); /* Hmmm, salt! */
    94103                        md5_finish( &md5_state, pass_md5 );
    95104                       
    96105                        for( i = 0; i < 16; i ++ )
    97106                        {
    98                                 if( !isxdigit( pass[i*2] ) || !isxdigit( pass[i*2+1] ) ||
    99                                      sscanf( pass + i * 2, "%2x", &j ) != 1 )
    100                                 {
    101                                         g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
    102                                                      "Incorrect password MD5-hash" );
    103                                         break;
    104                                 }
    105                                 if( j != pass_md5[i] )
     107                                if( pass_dec[i] != pass_md5[i] )
    106108                                {
    107109                                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
     
    118120                        }
    119121                }
     122               
     123                g_free( pass_dec );
    120124        }
    121125        else if( xd->pass_st < XML_PASS_OK )
     
    127131        {
    128132                char *protocol, *handle, *server, *password, *autoconnect;
     133                char *pass_b64 = NULL, *pass_rc4 = NULL;
     134                int pass_len;
    129135                struct prpl *prpl = NULL;
    130136               
    131137                handle = xml_attr( attr_names, attr_values, "handle" );
    132                 password = xml_attr( attr_names, attr_values, "password" );
     138                pass_b64 = xml_attr( attr_names, attr_values, "password" );
    133139                server = xml_attr( attr_names, attr_values, "server" );
    134140                autoconnect = xml_attr( attr_names, attr_values, "autoconnect" );
     
    138144                        prpl = find_protocol( protocol );
    139145               
    140                 if( !handle || !password || !protocol )
     146                if( !handle || !pass_b64 || !protocol )
    141147                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
    142148                                     "Missing attributes for %s element", element_name );
     
    144150                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
    145151                                     "Unknown protocol: %s", protocol );
    146                 else
     152                else if( ( pass_len = base64_decode( pass_b64, (unsigned char**) &pass_rc4 ) ) &&
     153                                rc4_decode( (unsigned char*) pass_rc4, pass_len,
     154                                            (unsigned char**) &password, xd->given_pass ) )
    147155                {
    148156                        xd->current_account = account_add( irc, prpl, handle, password );
     
    154162                                sscanf( autoconnect, "%d", &xd->current_account->auto_connect );
    155163                }
     164                else
     165                {
     166                        /* Actually the _decode functions don't even return error codes,
     167                           but maybe they will later... */
     168                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
     169                                     "Error while decrypting account password" );
     170                }
     171               
     172                g_free( pass_rc4 );
     173                g_free( password );
    156174        }
    157175        else if( g_strcasecmp( element_name, "setting" ) == 0 )
     
    354372static storage_status_t xml_save( irc_t *irc, int overwrite )
    355373{
    356         char path[512], *path2, md5_buf[33];
     374        char path[512], *path2, *pass_buf = NULL;
    357375        set_t *set;
    358376        nick_t *nick;
    359377        account_t *acc;
    360378        int fd, i;
    361         md5_byte_t pass_md5[16];
     379        md5_byte_t pass_md5[21];
    362380        md5_state_t md5_state;
    363381       
     
    380398        }
    381399       
     400        /* Generate a salted md5sum of the password. Use 5 bytes for the salt
     401           (to prevent dictionary lookups of passwords) to end up with a 21-
     402           byte password hash, more convenient for base64 encoding. */
     403        for( i = 0; i < 5; i ++ )
     404                pass_md5[16+i] = rand() & 0xff;
    382405        md5_init( &md5_state );
    383406        md5_append( &md5_state, (md5_byte_t*) irc->password, strlen( irc->password ) );
     407        md5_append( &md5_state, pass_md5 + 16, 5 ); /* Add the salt. */
    384408        md5_finish( &md5_state, pass_md5 );
    385         for( i = 0; i < 16; i ++ )
    386                 g_snprintf( md5_buf + i * 2, 3, "%02x", pass_md5[i] );
    387        
    388         if( !xml_printf( fd, "<user nick=\"%s\" password=\"%s\">\n", irc->nick, md5_buf ) )
     409        /* Save the hash in base64-encoded form. */
     410        pass_buf = base64_encode( (char*) pass_md5, 21 );
     411       
     412        if( !xml_printf( fd, "<user nick=\"%s\" password=\"%s\">\n", irc->nick, pass_buf ) )
    389413                goto write_error;
     414       
     415        g_free( pass_buf );
    390416       
    391417        for( set = irc->set; set; set = set->next )
     
    396422        for( acc = irc->accounts; acc; acc = acc->next )
    397423        {
    398                 if( !xml_printf( fd, "\t<account protocol=\"%s\" handle=\"%s\" password=\"%s\" autoconnect=\"%d\"", acc->prpl->name, acc->user, acc->pass, acc->auto_connect ) )
     424                char *pass_rc4, *pass_b64;
     425                int pass_len;
     426               
     427                pass_len = rc4_encode( (unsigned char*) acc->pass, strlen( acc->pass ), (unsigned char**) &pass_rc4, irc->password );
     428                pass_b64 = base64_encode( pass_rc4, pass_len );
     429               
     430                if( !xml_printf( fd, "\t<account protocol=\"%s\" handle=\"%s\" password=\"%s\" autoconnect=\"%d\"", acc->prpl->name, acc->user, pass_b64, acc->auto_connect ) )
     431                {
     432                        g_free( pass_rc4 );
     433                        g_free( pass_b64 );
    399434                        goto write_error;
     435                }
     436                g_free( pass_rc4 );
     437                g_free( pass_b64 );
     438               
    400439                if( acc->server && acc->server[0] && !xml_printf( fd, " server=\"%s\"", acc->server ) )
    401440                        goto write_error;
     
    433472
    434473write_error:
     474        g_free( pass_buf );
     475       
    435476        irc_usermsg( irc, "Write error. Disk full?" );
    436477        close( fd );
Note: See TracChangeset for help on using the changeset viewer.