I am working on converting an ASP site to PHP. The site uses a 3rd party API. The 3rd party API requires a UserID which was stored in the database and a password for each user. The ASP site didn't save the passwords in the database, instead they used the following function to derive the password every time based on the UserID:
public static string GetLmsUserPassword(int userId)
{
var hash = userId.ToString().MD5();
return hash.Substring(15, 4) + hash.Substring(4, 4);
}
In PHP, I wrote the following:
function lms_password($user_id) {
$hash = md5((int)$user_id);
$password = substr($hash,15,4).substr($hash,4,4);
return $password;
}
However, it appears the password generated in PHP does not match the password in ASP. I am wondering if ASP does md5 differently?
An example UserID is actually a string, not just a number: 22E21F5D-7979-467E-928D-4EFCC323BDCB
The difference in results between the .NET and PHP versions could be due to the way each casts a string to an int. Try casting your example id in both, and compare.
ASP: var hash = userId.ToString().MD5();
See that ToString() part? That means the ID is probably being interpreted as a string.
Your PHP: $hash = md5((int)$user_id);
explicitly casts it as an int, which will hash to a completely different value.
An example UserID is actually a string, not just a number: 22E21F5D-7979-467E-928D-4EFCC323BDCB
So... why are you casting it as an int? :I
edit: I also like that the password appears to be statically generated from a hash of the userID. Very secure.
Related
I'm trying to compile a software written in VB (I'm using VisualStudio2010, Framework 4) that lets users change their passwords on a website (sadly the website default changepassword form doesn't work, and I can't fix that via PHP).
I don't have much experience with PHP and encrypting, so I looked on the internet for some solutions for VB.Net, but didn't get the expected results after 2 days of trying.
I did some research, and that's what I learned:
Website's PHP code uses the crypt($string,$salt) function to create the hashed password.
The encoding is a MD5 algorithm, as my salt is something like '$1$ad000000$' for every password in website's database.
I tried to replicate it in VB and the issues start on the ComputeHash(buffer() as Byte), as it doesn't support a "Salt" String.
The code on PHP is as simple as that:
$EncryptedPassword = crypt($userPassword, $salt);
The salt is generated to look like, for example, "$1$ad000000$"
The $EncryptedPassword length is 34 (12salt + 22hash), but I guess this is a standard length of the crypt() function, given a specific salt.
This is what I'm currently trying on VB:
Dim Hashata = GetHash("asdkFAofkas", "$1$ad000000$")
Private Function GetHash(ByVal p1 As String, ByVal Salt As String) As Object
Using hasher As MD5 = MD5.Create()
Dim dbytes As Byte() = hasher.ComputeHash(Encoding.UTF8.GetBytes(p1 & Salt))
Dim Conversione = Convert.ToBase64String(dbytes)
Return Conversione
End Using
End Function
The return string is a 24-character string always ending with "==" no matter what "p1" is, and I read on the internet that these last two characters are optional, so when creating the password-hash with Salt, I just do:
Dim StoredPassword = Salt & Hashata.Substring(0,Hashata.Length-2)
The created StoredPassword (VB) doesn't coincide with the password (PHP) in the DataBase when I write the same Password.
I tried this with creating multiple users on the website with the same Password, and they are all hashed in the same way in the Database.
For example, this is what I have in the Database:
-------------------------------------------------
| Username | Password |
-------------------------------------------------
|test1 |$1$ad000000$kcpPLtMxsedGD0d39UnXQg |
-------------------------------------------------
|test2 |$1$ad000000$kcpPLtMxsedGD0d39UnXQg |
-------------------------------------------------
|test3 |$1$ad000000$kcpPLtMxsedGD0d39UnXQg |
-------------------------------------------------
|testVB |$1$ad000000$5u-9pdu3HDnXt5pGdXZNug |
-------------------------------------------------
test1,test2,test3 have passwords made on website
testVB has a password generated by VB's function above
I wrote the exact same password for test1,test2,test3 and testVB.
ALL passwords on the database have a length of 34 characters
I already tried the following (on VB, as I can't modify website's PHP):
Encode only p1, only Salt, both variables mixed (like in the code above)
Convert p1 and Salt to a hex string (first only one, then only the other one, then both, etc...) before encoding them singularly or while mixing them
Use different types of Encoding (UTF-7, UTF-16, UTF-32, "Default" and ASCII)
I'm pretty sure the issue is on the ComputeHash Function, which doesn't have a "Salt" property (it has an offset and count properties, but I didn't use them), and without that, it can't crypt in the way I'd like.
Is there a way to replicate PHP's crypt($string, $salt) function?
I can bet that without the $salt they coincide (I already found some solutions that worked like that, but I need that $salt for crypting because I cannot modify website's PHP code to crypt without $salt).
Thanks a lot, sorry for the long read, I want to make sure I didn't miss anything :)
If there's something else I need to add, let me know!
Bcrypt.NET gives you want you want.
string passwordHash = BCrypt.HashPassword("my password");
if (BCrypt.Verify("my password", passwordHash)) {
// Valid
} else {
// Incorrect password
}
I have been trying for a while now to authenticate a password encrypted in .NET from a PHP API and despite trying different ways I can't seem to get it to match.
The password was encrypted using SHA512 and stored in the database in a binary(64) field, using this exact function (which I do not have control over, it cannot be modified. No salt is used) :
> public byte[] GetHashablePw(string pwByte)
> {
> System.Security.Cryptography.SHA512Managed sm = new System.Security.Cryptography.SHA512Managed();
> System.Text.UnicodeEncoding u = new System.Text.UnicodeEncoding();
> byte[] b = new byte[-1 + 1];
> b = sm.ComputeHash(u.GetBytes(pwByte));
> return b;
> }
When I want to compare the password the user supplies, I tried these different ways :
$pwhash = openssl_digest($_POST['pw'], 'sha512');
$pwhash = bin2hex(pack('H*', hash('SHA512',$_POST['pw'])));
$pwhash = openssl_digest(utf8_decode($_POST['pw']), 'sha512');
$pwhash = bin2hex(hash('sha512', $_POST['pw'], true));
which all return the same result really but none is matching what got stored in the database from .NET.
I get my password hash stored in the database with this :
bin2hex($pwFromDB);
In one particular case, I get this as a hash stored in the database:
4c0dc75a062dd4957f6f91350f6d3f54f910989e6ffe82749cdc580b9eae5dce0ee743cd513d005d0c399e23b0190809767fe1a57f9fecbce0a928296181c14e
while I get this from the PHP functions using the same password :
c3cf6055cbb36e3eace5ca470922de6e754ec93cf80f35459c910f4381899483e2c29565f062476724dad94929527d53eeae5a1cd708c6227574e58748d354aa
I would appreciate any help in understanding what I am missing.
The C# is using UnicodeEncoding, which is UTF-16LE.
You need to get the PHP data into that same representation, since cryptography operates on bytes, not text. http://php.net/manual/en/function.mb-convert-encoding.php might be what you want.
Also, the string is not encrypted. Encryption requires there be an undo operation (decryption). What has been done here is hashing. This password was hashed.
I am creating a PHP-version of a login script that is in ASP.net/VB.net. The database where the usernames and passwords are stored is in MSSQL and that will not change. Passwords are stored as binary data. Here's a part of the code in VB.net that compares the password to the one saved in the database.
Dim sha1 As sha1 = sha1.Create()
Dim password As Byte() = sha1.ComputeHash(Encoding.Unicode.GetBytes(Me.txtPwd.Text))
CustData = .GetCustomerByEmail(Me.txtUser.Text, password)
I found out that it's part of a library.
I am encountering problems after hashing the password in PHP's sha1. I don't know how to convert the hashed string to a binary that I could use to compare it to the database.
As an example, the password "Test100" in the MSSQL database has a value of (after unpack('H*', $binaryPassword)) 7397001ce5259b79c436a369b9d3a8c7bc2a85385fdec57a. I am not sure how to get that string above from the hashed password I am getting using PHP.
Here's what I have in PHP so far and where I am stuck in.
$password = sha1(mb_convert_encoding($_POST['password'], 'utf-16le'), false); // $_POST['password'] = 'Test100'
The output for that is 8415ec8cc9287a10f81db5a77341709d304bfa92.
So I am thinking there's one more step to change $password to $binaryPassword or the hexadecimal representation of the binary password.
From this page, it's saying Byte is an 8-bit unsigned integer, but not really sure how to get that from a PHP string.
Thanks in advance!
What happens if you try to run the sh1 on the static text "Test100"?
ok, so I'm trying to create some password protected web pages using PHP 5.4 script and MySQL. Running a sample produced some unexpected results!
I created the password using:
$salt = "";
$salt.=substr("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",mt_rand(0,63), 1);
$salt .= substr("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", mt_rand(0, 63), 1);
$pw1 = crypt($pw,$salt);
and stored the $pw1 in MySQL database.
then in my authentication pages, I retrieved the db password and used user input from a form to validate the user, checking like this:
get $db_pw from database then...
if (crypt($user_password,$db_pw) == $db_pw) ... proceed
All worked fine, but if I enter a string longer than the password it still passed thru ok. For example: if my password was "stack", if I entered "stackoverflow" it would pass ok. If I entered "stac" it would stop as intended.
I've tried searching on this but could not find anything similar.
What am I doing wrong?
It looks like the crypt function has this little caveat:
The standard DES-based crypt() returns the salt as the first two characters of the output. It also only uses the first eight characters of str, so longer strings that start with the same eight characters will generate the same result (when the same salt is used).
So I presume that what happens does not happen on "stack" and "stackoverflow" but does with e.g. "stackove" and "stackoverflow".
Using crypt() is a really bad idea. Use PBKDF2 or bcrypt instead of crypt of the stone age.
As in php we use $_GET to pass variables in the url , i want to pass variables which include the id of the user which i want to be anonymous, so can something be done which can encrypt the variable before passing it and the the variable once taken on the page can be decrypted to get the original variable value.
for eg:
Before passing variable $id=10;
Passed in the url as $id=dasfgjg;
when taken from the url and decrypted $id=10;
How can this be achieved?
You can use an RC4 cipher if you intend to encrypt/decrypt only on the server-side
http://www.phpkode.com/source/s/rc4-cipher-0-1/rc4-cipher-0-1/RC4.php
$my_secret_key = '3klmsd94mms.saeo44o!!3le';
if( isset($_GET['p']) ) {
$id = RC4::decrypt($my_secret_key, $_GET['p']);
// ....
}
else {
echo 'Go to the page';
}
Just generate random strings (make sure it's unique) for each record in the database and save it there, too. Then use this as an identifier. Note that, of course, this has nothing to do with encryption.
A quick and dirty way to achieve this (for each request)
on the client, create a string like 'xx:10:yy' where xx and yy are strings consisting pf random characetrs
on the client, create a salted hash of the users salted/hashed password
use this hash as a key and the string from the first bullet as cleartext for encryption with e.g. crypt.js
in the request send the encrypted string and the salt
on the server use the transmited salt and the users salted/hashed password to recover the key
on the server use mcrypt or friends to decrypt the string
on the server use standard PHP text processing functions to recover the payload from the decrypted string