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.
Related
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 use openssl to encrypt a text, then put this into a mysql database.
This works fine, however with long texts, the decrypted text becomes corrupted.
Personally I think this is due to the way mysql saves this text into the database, there are a lot of not alpha numeric characters in the encrypted text. But I am not sure about that.
Also I don't know which collation to use in mysql, right now I set it to *utf8_unicode_ci*, but still there is corruption of data.
A live example can be seen here: http://todolist.x10.mx
Username: example
Password: password
To view the corrupted data, click Download Backup.
Below the code, of course $encrypted is saved into the database. This code works fine without database.
<?php
$source = 'very long text';
$iv = "1234567812345678";
$pass = 'difficultpassphrase';
$method = 'aes-256-ofb';
$encrypted = openssl_encrypt ($source, $method, $pass, true, $iv);
echo $encrypted;
$decrypted = openssl_decrypt ($encrypted, $method, $pass, true, $iv);
echo $decrypted;
?>
Thank you in advance for your time and expertise.
To store encrypted content in binary form, you can't use a character type with encoding since it's very likely that the encoding "breaks" your data.
You should instead use BINARY or VARBINARY datatypes, they're made exactly for the purpose of storing binary data.
The alternative is to base64_encode the data before storing it in the character datatypes, and base64_decode the data when you've fetched it from the database. This will encode the data so that the encrypted data is possible to store in a varchar/char datatype (although it will make the data slightly longer, so beware of that)
I've seen this asked a few times, but not exactly how I'm going to ask it here... Hopefully this is ok with you guys.
Basically I have this script that works fine and will print my result without a hitch:
$algorithm = MCRYPT_BLOWFISH;
$mode = MCRYPT_MODE_CFB;
$iv = mcrypt_create_iv(mcrypt_get_iv_size($algorithm, $mode), MCRYPT_DEV_URANDOM);
$key = 'Wassup';
$data = 'I am a guy';
$enc_data = rtrim(mcrypt_encrypt($algorithm,$key,$data,$mode,$iv));
$plain_text = base64_encode($enc_data);
echo $plain_text . "\n";
// OUTPUTS: 6m3D5qSrfz3w6pKuuybs
$enc_data = base64_decode($plain_text);
$decoded = mcrypt_decrypt($algorithm,$key,$enc_data,$mode,$iv);
echo $decoded;
// OUTPUTS: I am a guy
This is perfect. NOW... instead of just instantly outputting what I put in, I'm trying to store that info in my database to be decrypted later.
I can see the encrypted string fine in my table row: 6m3D5qSrfz3w6pKuuybs. So, I'm sure it's going IN just fine..
and when I query to get it out it looks just the same,
but now when I decode and decrypt I get something like: ÝÄ/$ÍñËt05883700
The table field is set up as a VARCHAR (255) utf8_general_ci. Is this where the problem is?
Are you sure you are using the same initialization vector (IV) on encryption and decryption?
Note that you need to save the IV as well and use it when you are decrypting. Also don't use rtrim() on the ciphertext.
That being said, you could use a BINARY (or VARBINARY) field to store your ciphertext (and the IV), so you don't need to base64 encode it. It will save you 33% of storage.
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.