On the server side I create a password hash:
public static function salt()
{
return '$1$' . StringUtil::random(6, array('encode' => StringUtil::ENCODE_BASE_64));
}
public static function hash($password, $salt = null)
{
return crypt($password, $salt ?: static::salt());
}
And on client side I want to do the same using CryptoJS.
Is there any analogues in javascript for PHP crypt(), not necessary with CryptoJS?
UPD:
I want to do this on client side because I don't want to send password to server, but something like clientId crypted with hash, decrypt it on the server and get the hash for the next manipulations.
Well, here it is: a CryptoJS implementation of PHP's crypt for MD5-hashes (I guess it's too large to paste). So it's not a complete crypt-like thing but in your code example you are setting up a MD5-based hash (with the $1$ salt prefix).
How to use it:
Store in a file named php-crypt-md5.js
Use it like that ("rollups" is in your CryptoJS directory, just use the correct path):
<script src="rollups/md5.js"></script>
<script src="php-crypt-md5.js"></script>
<script>
function createSalt(len) {
var saltAlpha = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz./-+_"
var salt = '$1$';
for(var i = 0; i < len; ++i) {
salt += saltAlpha.charAt(
Math.floor(Math.random() * saltAlpha.length));
}
return salt;
}
// in your JavaScript code:
var salt = createSalt(8);
var pw = "your password";
var hash = CryptoJS.PHP_CRYPT_MD5(pw, salt);
What's the point of encrypting at the client and then decrypting at the server? This is not security, if all the information for encryption is client side, all someone needs to do is look at the JS source to see what your salt is, there is no security there.
The whole point is to send some data (over a secured channel, like https) to the server, then have the server hash it, and compare that hash to something you already have stored.
The security comes from what happens at the server, not from what you do to the data before you send it. A secure connection will prevent man-in-the-middle listening, but anything you have at the client is out in the open, and in no way contributes to security, unless you're using not-in-the-browser information (like having someone paste in their PGP public key along with whatever you send, with the server already knowing this person's PGP private key for authentication verification) in which case the actual data becomes irrelevant because the public key is now the important part...
So yeah, don't do this. It makes you believe you're being extra secure, when in fact you only made things worse.
Related
I'm trying to build a platform for users who will store confidential data about their clients. The context is quite simple: french laws prohibit me from having access to the data that my users will store (for example medical records of patients).
So when a user submits data which will be stored in the database, he should be the only one having access to that information. For example by encrypting it with his password. That way, if I log into mysql, I would only see encrypted nonsense and no readable data.
My philosophy, which might be wrong, is to learn by doing it. Hope you guys are ok with my approach.
Problem is: I have no idea where to start, how to do that... and actually not even what to search for on google. I even tried to find something suitable on codecanyon.net for example and couldn't fond any relevant scripts.
Thanks in advance :) !
PS: I will actually have the same problem with files (jpg, word, pdf, xls... that should be enough for the users). But that's another story.
Although I'm not familiar with the French data protection laws, I do have some experience with the general EU legislation. Probably you have to encrypt personal data in your system such way, that the person cannot be identified. This means, that technical data, such as a system specific id in a table can stay unencrypted. This is the only reason I believe you can actually make this work. Sort of. You have to work with lawyers to determine what data can stay unencrypted to comply with the laws and still to be able to provide a valuable service to your clients.
However, I believe that you are missing an important point: if you cannot have access to certain data, then that data MUST NOT arrive to your organisation in a plain format. Period. If it does, then you already have access to it. So, php (or any kind of server based encryption) or mysql based encryption solutions are out of the picture.
The only solution I can think of is it to team up with a 3rd party PKI provider, who will provide your clients with certificates ( perhaps on chip cards), and the client side of your application encrypts the sensitive personal data items on the client BEFORE they are sent to your server and also decrypt these data items on the client. This also means that you will have to use some plugins on the client side if you want this system to be web based. Probably you will need some signed java app to manage the card reader and the certificate.
The setup has 2 drawbacks for your clients:
It's not a single provider they deal with, since the PKI provider must be an independent third party. You must not manage the certificates.
In case the stored data gets corrupted, the encrypted data will be lost. So, you will have to implement some crazy backup and restore solution.
So assuming the problem is as follows:
You need to encrypt the data before you store it.
You shouldn't have the keys to decrypt it, only encrypt it.
There's actually a tool for this: It's called a sealing API, and it can be accomplished through OpenSSL or Libsodium.
Sealing/Unsealing Data in PHP with Libsodium
$store_me = \Sodium\crypto_box_seal(
$plaintext,
$recipient_public_key
);
$visible = \Sodium\crypto_box_seal_open(
$store_me,
$recipient_keypair
);
Sealing/Unsealing Data in PHP with OpenSSL
/**
* A human-usable variant of openssl_seal()
*
* #param string $plaintext Your message
* #param string $publickey_string PEM-encoded RSA public key
* #param boolean $encode Hex-encode the output?
*
* #return string
*/
function easy_seal($plaintext, $publickey_string, $encode = false)
{
$pubkey = openssl_get_publickey($publickey_string);
if ($pubkey === false) {
throw new Exception('Could not load public key');
}
$sealed = '';
$ekeys = [];
$result = openssl_seal($plaintext, $sealed, $ekeys, [$pubkey]);
if ($result === false) {
throw new Exception('openssl_seal failed!');
}
if ($encode) {
return json_encode([
bin2hex($sealed),
bin2hex($ekeys[0])
]);
}
return json_encode([$sealed, $ekeys[0]]);
}
/**
* Inverse operation of easy_seal()
*
* #param string $ciphertext (the output of easy_seal())
* #param string $privatekey_string PEM-encoded RSA private key
* #param boolean $encoded Do we need to decode from hex?
*
* #return string
*/
function easy_unseal($ciphertext, $privatekey_string, $encoded = false)
{
list($sealed, $ekey) = json_decode($ciphertext, true);
if ($encoded) {
$sealed = hex2bin($sealed);
$ekey = hex2bin($ekey);
}
$open_data = '';
$privkey = openssl_get_privatekey($privatekey_string);
if ($privkey === false) {
throw new Exception('Could not load public key');
}
$result = openssl_open($sealed, $open_data, $ekey, $privkey);
if ($result === false) {
throw new Exception('openssl_open failed!');
}
return $open_data;
}
Usage Example
$public_key = file_get_contents('/path/to/publickey.pem');
$plaintext = 'Something something dark side';
$store_me = easy_seal($plaintext, $public_key);
// Elsewhere:
$secret_key = file_get_contents('/path/to/secretkey.pem');
$visible = easy_unseal($store_me, $secret_key);
Demo: https://3v4l.org/BNavp
Actually, I'm also on a similar kind of project where I'm trying to build a secure database in MySQL Server that is also useful to run all the valid SQL Queries. It's still in the progress and too many difficulties are there; I accept.
But, for your problem , it seems you only need to encrypt and decrypt the values.and you don't want to store the key also there in the database. For me, there are two ways that comes in my mind:
First way is, that you decide a fixed secret key to encrypt and decrypt the values and use it for every data, that is being stored on the database.
But, that's not practical I guess, since the security gets weak with this approach and a person can identify your key with brute force approach.
Second way is, that you generate a random key for every different user, like, at the time of registration. And data of different user can be viewed by only the user who has the key to decrypt it, which here only the user has. And then you apply the first approach after this. i.e., you decide a key that will be used to encrypt these keys of different users. and then store this encrypted key in the database in a separate table. So that, next time user will try to access his/ her data, his entered key (could be his password), will be encrypted with your decided static key, if this encrypted key is found in the table of your database your will fetch the data of that user, decrypt it with his/ her key and display to him/ her.
All you need is a,
(i) programming platform to select, JAVA is best.
(ii) learn how to use database with this programming language, MySQL Server is a nice choice to work with.
(iii) And a good encryption algorithm to implement.
Hope, I didn't make you angry with this answer :) Cheers.
I'm facing a situation that need to verify password created via PHP password_hash method on nodejs server.
Does nodejs have an available package that equivalent to password_hash and password_verify? Thank you.
In my case i created password in php like below
$data['password'] = password_hash($data['password'],PASSWORD_BCRYPT);
In Node if i want to verify that password than ...
var bcrypt = require('bcrypt');
params.hash = params.hash.replace('$2y$', '$2a$');
bcrypt.compare(params.password, params.hash,async function(err, correct) {
console.log(correct);
});
Hope it will help you .....
No, you will have to make use of one of the many Bcrypt libraries for Node.js.
P.S.: You're basically duplicating another user's question (Verify password hash in nodejs which was generated in php).
I've been asked to enable SHA256 for storing wordpress passwords.
I've searched for plugins with no luck (not working), so I started to develop my own.
I first thoug.. well if I replace the wp_hash_password with my own function, It would encrypt when saving password and loging. But I wasn't that lucky. I'm able to run hash(sha256) though in a basic php file. I'm aware that users wont' be able to login as the stored key would be md5 and the comparation would be SHA, but it isn't a problem.
Code:
if(!function_exists('wp_hash_password')):
function wp_hash_password($password){
return hash('sha256', $password);
}
endif;
So I guess I'll have to make my own "check login" function.
Did someone did something like this?¿
Seems to me that your approach should work if you override the wp_check_password function as well. That'll have to be done in a plugin, I think, as the functions are loaded before the theme's functions.php. Something like this:
<?php
/*
Plugin Name: sh256pass
Version: 1.0
*/
if(!function_exists('wp_hash_password')):
function wp_hash_password($password){
return hash('sha256', $password);
}
endif;
if(!function_exists('wp_check_password')):
function wp_check_password($password, $hash, $user_id = '') {
// You might want to apply the check_password filter here
return wp_hash_password($password) == $hash;
}
endif;
Note that you'll either have to have your users reset their password on their next login (you won't be able to convert the existing passwords automatically), or you'll have to follow WordPress's approach in wp_check_password and compare the password to the old encrypted value (in their case md5), and if that matches, update to the new value.
Keep in mind that the wp_users.user_pass field is only 64 characters long. While that's (just) long enough to store the sha256 value, it isn't long enough to store the sha256 value and a salt. If you don't salt, and two users choose the same password, the wp_users.user_pass field will contain the same value, making it obvious to anyone with access to the database that the passwords are the same. My gut feel is that that is a greater security risk than using the current algorithm. You might be able to get around that by (say) concatenating the user ID and the password before hashing, but there might be edge cases where you don't know the user ID (such as when a user is created).
Personally, I'd question the requirement.
I have read about users being able to manipulate website cookie and use it to exploits security loopholes. I did a search and came across an idea posted online. Here is the code below that is, after the username and password of the user are authenticated;
$Separator = '--';
$uniqueID = 'jhlhgjh12u0#345';
$Data = $userID.' '.md5('65748');
$expire=time()+60*24;
setcookie('verify-user', $Data.$Separator.md5($Data.$uniqueID), $expire);
The code above will set the cookie using a uniqueID, the userID, a MD5 hash numbers and a separator. The uniqueID, md5 hash numbers and separator are set by the developer. The idea is that a user won't be able to manipulate the cookie because the don't know the UniqueID, and the md5 hash numbers. The code below is used to test each cookie if they are manipulated or not
if ($_COOKIE) {
$Separator="--";
$uniqueID = 'jhlhgjh12u0#345';
$Cut = explode($Separator, $_COOKIE['verify-user']);
if (md5($Cut[0].$uniqueID) === $Cut[1]) {
$_COOKIE['verify-user'] = $Cut[0];
} else {
echo "fake cookie";
}
}
else {
echo "fake cookie";
}
I am wondering if this method is security tight or if there are loopholes too. criticism and corrections are welcomed
This is known as message signing. You hash the message together with a secret and attach that "signature" to the message itself. This allows the recipient to verify that the creator/signer of the message is in possession of the secret, without revealing the secret itself.
The problem with your particular implementation is that
the secret is too small
the hashing algorithm is unsuitable for the task
the cookies never change and never expire; if a cookie is stolen there's no recourse
You should use a longer secret, the longer the better. You should also use a hashing algorithm that is suited for the task, namely something like HMAC (hash-based message authentication). E.g.:
hash_hmac('sha512', $data, $secret)
You can see an implementation of a similar thing, including expiration of values, here.
The most important thing though: think thrice about whether a signed plain text message is the best way to go here in the first place. Perhaps you want a session-like system, in which an entirely meaningless random string is used as an id for data that is stored on the server. This completely eliminates the problem of users manipulating the cookie.
I'm trying to create a custom registration component for TYPO3 on an external website where TYPO3 is not installed (i just use its database). Problem is i have no experience using TYPO3. I was wondering if anyone knew how to create the correct password encryption for TYPO3? The passwords looks like this :
$P$CeO/XYcbzRH9nLpCwKdp1HhsJGwJum0
I am looking for a php code to create that same encryption and check the password. I have the encrytion key from the install tools which (i believe) is used for the salting.
Or is there a possibility to save passwords as MD5 only? Not the best option but i could be the only one left.
I have found this url:
http://srv123.typo3.org/TYPO3/Extensions/saltedpasswords/4.6/#compatibility-of-other-extensions-with-salted-user-password-hashes
But i have no clue how to implement that in my own script.
Works on typo3 6.X:
$password = 'XXX'; // plain-text password
$saltedPassword = '';
if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('saltedpasswords')) {
if (\TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility::isUsageEnabled('FE')) {
$objSalt = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance(NULL);
if (is_object($objSalt)) {
$saltedPassword = $objSalt->getHashedPassword($password);
}
}
}
Have a look at the developer guide:
1.5.1 Creating a new salted user password hash from a given plain-text password
You have to use it in the typo3-Frontend:
$password = 'XXX'; // plain-text password
$saltedPassword = '';
if (t3lib_extMgm::isLoaded('saltedpasswords')) {
if (tx_saltedpasswords_div::isUsageEnabled('FE')) {
$objSalt = tx_saltedpasswords_salts_factory::getSaltingInstance(NULL);
if (is_object($objSalt)) {
$saltedPassword = $objSalt->getHashedPassword($password);
}
}
}
But, you should never try to generate salted password outside of typo3 because the encryption depends on your typo3 settings.
By looking at the hash provided I suppose the saltedpasswords extension (responsible for storing salted hashes in the database) in TYPO3 is set to use phpass. You should therefore be able to take this class and use it in your script to create/check passwords the same way as TYPO3 does.
Or is there a possibility to save passwords as MD5 only?
Yes, using salted passwords in TYPO3 is optional and not mandatory. However, if any TYPO3 installation in future would be supposed to use that database, I'm not sure how TYPO3 would handle the mixture of records when some of them would have passwords stored as unsalted hashes and some as salted. My guess is, that it would handle it gracefully, recognising which check to use for each hash.