Python is Garbling a Salt Generated from PHP and Stored in Mysql
Question: I am exporting, by scraping it with http requests since the host won't give me
database access, a forum and importing it into a mysql database for vbulletin.

In vbulletin users have unique password salts, and it generates password
hashes using this algorithm:

    
    
    $hash = md5(md5($plaintext) . $salt);
    

I'm using a python script to read stored data from my sqlite database of user
information to generate a new password and salt for users, then storing that
data into the mysql database so vbulletin can use it.

My problem is that python is changing the value of strings in unexpected ways.
I'm testing my script using a known password and salt to compare the hashes.
However, the salt that I'm using is this:

    
    
    D(A\3*w/lo6Coo\Mc,H!0!2Z3d@O&R
    

When I try to store that in python, when I retrieve the string I get this:

    
    
    D(A\x03*w/lo6Coo\\Mc,H!0!2Z3d@O&R
    

This is the python code I'm using to mimic the vbulletin hashing algorithm:

    
    
    salt = 'D(A\3*w/lo6Coo\Mc,H!0!2Z3d@O&R'
    
    password = hashlib.md5()
    password.update('*snipped password*')
    password = password.hexdigest()
    
    password_hash = hashlib.md5()
    password_hash.update(password + salt)
    password_hash = password_hash.hexdigest()
    

For comparison, this PHP matches what vbulletin stores as the password hash in
the database:

    
    
    $plaintext = '*snipped password*';
    $salt = 'D(A\3*w/lo6Coo\Mc,H!0!2Z3d@O&R';
    
    $hash = md5(md5($plaintext) . $salt);
    

$hash matches what vbulletin stores and password_hash does not. What am I
doing wrong to cause the difference?


Answer: The way you're defining `salt` is the problem. You have to either make it a
raw string:

    
    
    salt = r'D(A\3*w/lo6Coo\Mc,H!0!2Z3d@O&R'
    

Or escape the backslashes:

    
    
    salt = 'D(A\\3*w/lo6Coo\\Mc,H!0!2Z3d@O&R'
    

Otherwise, `\3` is interpreted as the escape sequence for the character with a
character code of `3`.

Also, for readability, you may want to make an `md5` function:

    
    
    def md5(text):
        return hashlib.md5(text).hexdigest()
    
    hash = md5(md5(plaintext) + salt)
    

