Is there a programmatic way to build htpasswd files, without depending on OS specific functions (i.e. exec(), passthru())?
.httpasswd files are just text files with a specific format depending on the hash function specified. If you are using MD5 they look like this:
foo:$apr1$y1cXxW5l$3vapv2yyCXaYz8zGoXj241
That's the login, a colon, ,$apr1$, the salt and 1000 times md5 encoded as base64. If you select SHA1 they look like this:
foo:{SHA}BW6v589SIg3i3zaEW47RcMZ+I+M=
That's the login, a colon, the string {SHA} and the SHA1 hash encoded with base64.
If your language has an implementation of either MD5 or SHA1 and base64 you can just create the file like this:
<?php
$login = 'foo';
$pass = 'pass';
$hash = base64_encode(sha1($pass, true));
$contents = $login . ':{SHA}' . $hash;
file_put_contents('.htpasswd', $contents);
?>
Here's more information on the format:
http://httpd.apache.org/docs/2.2/misc/password_encryptions.html
From what it says on the PHP website, you can use crypt() in the following method:
<?php
// Set the password & username
$username = 'user';
$password = 'mypassword';
// Get the hash, letting the salt be automatically generated
$hash = crypt($password);
// write to a file
file_set_contents('.htpasswd', $username ':' . $contents);
?>
Part of this example can be found: http://ca3.php.net/crypt
This will of course overwrite the entire existing file, so you'll want to do some kind of concatination.
I'm not 100% sure this will work, but I'm pretty sure.
Trac ships with a Python replacement for htpasswd, which I'm sure you could port to your language of choice: htpasswd.py.
Related
I know saving passwords in plain text is in a database is bad, but I need to save the password in a way that the users can retrieve and view them.
The Database will be located within our web host and access to it will be restricted to known IP Addresses, the actual scripts that will be accessing the database will be located in a different datacentre which is locked down for all access to our specific known IP Addresses.
What I'm thinking of doing is creating an encryption key based on the unique school name, location and a 64 digit string. This will secure the password which will then be saved into the database.
To decrypt this, the script will have to read the school name and location from the DB and add the 64 digit string and then decrypt the password to display to the user.
When this goes live the 64 digit string won't be saved in the script it will be passed on the URL.
Using this https://stackoverflow.com/a/57249681/2134973 I've managed to get the password to be encrypted and decrypted. But as soon as I save the encrypted password to the database, it fails to decrypt when read back from the Database.
The code I have so far is:
From the initial database read I have :
$school = $db['school'];
$location = $db['location'];
$password = $db['password']; // plain text
I then encrypt using:
define('ENCRYPTION_KEY', "{$school}r$qVsYRk4*&H?=pb9sRdJHLbtERBwGSxezJa5eG?Zb#SrC&q2yzHLE=BjU?Wm9sM{$location}");
$OpensslEncryption = new Openssl_EncryptDecrypt;
$encrypted = $OpensslEncryption->encrypt($password, ENCRYPTION_KEY);
and save $encrypted back to my database.
For decrypting it I'm reading the data from the database and processing it as:
$school = $db['school'];
$location = $db['location'];
$password = $db['password']; // encrypted
define('ENCRYPTION_KEY', "{$school}r$qVsYRk4*&H?=pb9sRdJHLbtERBwGSxezJa5eG?Zb#SrC&q2yzHLE=BjU?Wm9sM{$location}");
$OpensslEncryption = new Openssl_EncryptDecrypt;
$decrypted = $OpensslEncryption->decrypt($password, ENCRYPTION_KEY);
If I var_dump $decrypted I get NULL.
If I dump the $encrypted and $password (after encryption) they are both the same string length.
The field in the database is defined as VARCHAR 1024
Can anyone advise how to do this, or if there is a better more secure way.
Ultimately I need to user to be able to see the passwords as plain text, but store them as securely as possible.
Thanks
UPDATE
The password held in the database don't belong to the users who are logged in. They are passwords to our internal systems which are all IP authenticated as well.
The users need to see these passwords.
When i try to hash all my users password in my website, first i saved all passwords in file then i try to hash them, but I realize its give me wrong hash not the real one.
I've tried 2 function but same results, these PHP codes explain everything.
File password.txt have just 1 line with "password" as a plain-text.
md5() function:
echo md5("password"); #5f4dcc3b5aa765d61d8327deb882cf99
file() function then md5 the line:
$openfile = file("password.txt");
foreach($openfile as $lines){
echo md5($lines); #286755fad04869ca523320acce0dc6a4
}
fopen() function:
if ($file = fopen("password.txt", "r")) {
while(!feof($file)) {
$lines = fgets($file);
echo md5($lines); #286755fad04869ca523320acce0dc6a4
}
fclose($file);
}
I think the line just have some blank spaces or something!?
EDITED
I have read more about the difference between hashing and encryption. And about hashing the password i use this now.
md5(sha1($passwords . $various_salts))
EDITED
These days, i started to use password_hash() with BCrypt hashing algorithm without using MD5 or SHA1, its better now.
The return values from both fgets and file include the line-endings.
You can either run the values through rtrim($line, "\n"); first, or use the following option for file:
$openfile = file("little.txt", FILE_IGNORE_NEW_LINES);
which will remove the line-endings for you.
Edit:
As evidenced by the issues raised in the comments, this is a fairly strange approach to solving a problem. Think about why you need to store all these passwords in a single file (hashed or otherwise).
I have read up on tons of samples and answers (and even more on how cryptography works) but none answers my scenario. I am creating a new user from desktop app in VB.Net. User need to use Android for a small part to update a valuation where a PC is not available (Web app is not an option unfortunately)
I have no problem in desktop app, all works fine. I am using a PHP page to handle the login and other data related actions in Android, also no problem. I did however had to change password to normal strings etc to read the passwords. I need to let PHP read the saved salted string (different salt for each password - all randomly generated, no salt the same for more than 1 user) linked to that particular password.
I have played around with the code for some time now to try and use the same kind of function in PHP but I am totally lost on how to convert the .net part to be used in PHP.
My .net code looks like this -
Imports System.Security.Cryptography
Imports System.Text
Module modSecurity
Public Function GetSaltedHash(pw As String, salt As String) As String
Dim tmp As String = pw & salt
' or SHA512Managed
Using hash As HashAlgorithm = New SHA256Managed()
' convert pw+salt to bytes:
Dim saltyPW = Encoding.UTF8.GetBytes(tmp)
' hash the pw+salt bytes:
Dim hBytes = hash.ComputeHash(saltyPW)
' return a B64 string so it can be saved as text
Return Convert.ToBase64String(hBytes)
End Using
End Function
Public Function CreateNewSalt(size As Integer) As String
' use the crypto random number generator to create
' a new random salt
Using rng As New RNGCryptoServiceProvider
' dont allow very small salt
Dim data(If(size < 7, 7, size)) As Byte
' fill the array
rng.GetBytes(data)
' convert to B64 for saving as text
Return Convert.ToBase64String(data)
End Using
End Function
Within my form I will create the hashed password and salt as follow -
strPasswordNew = txtPassword.Text
Dim NewPWD As String = strPasswordNew ''Actual password
strSaltPWD = CreateNewSalt(SaltSize) ''Salt pwd
Dim SaltPWDHash As String = GetSaltedHash(NewPWD, strSaltPWD) ''New pwd now hashed
The password and the salt is saved to database under their own fields - salt and pwd.
Any pointers will be highly appreciated please.
I'm having a problem where my password doesn't store after encryption even though it stores perfectly when I don't encrypt it. When I go to the database to check whether it's stored or not, I just see a blank under the password column. I want my password's encoding to be UTF-8 (or whatever it's called) since I want to use the Arabic language in my database.
PHP CODE
$password = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $_POST['password'], MCRYPT_MODE_CBC, $iv);
base64_encode($password);
Here's a picture that will show you my table's structure :
http://prntscr.com/91nhyx
You need to store the base64 encoded version before storing it in the database:
$password = base64_encode($password);
I have the following code that creates an encryption in PHP:
$password = "helloworld";
$passwordupper = strtoupper($password);
$passwordencode = mb_convert_encoding($passwordupper, 'UTF-16LE');
$passwordsha1 = hash("SHA1", $passwordencode);
$passwordbase64 = base64_encode($passwordsha1);
The instructions I have from the system I'm trying to connect to states:
The encoding process for passwords is: first convert to uppercase, then Unicode it in little-endian UTF 16, then SHA1 it then base64 encode it.
I think I'm doing something wrong in my code. Any ideas?
Answer solved by Marc B above in comments:
sha1 hash can either be raw binary, or a base64-encoded string to
begin with. e.g. $raw = sha1($string, true) v.s. $encoded =
sha1($string). you'd better try both variants, because you may be
double-base64-encoding.