PHP crypt() function in .Net? - php

I'm rewriting a PHP web site in ASP.NET MVC. I'd like to maintain the same user base but the passwords are hashed using the PHP crypt() function. I need the same function in .Net so that I can hash a password on login and check it against the hashed password in the user database.
crypt in this case is using the CRYPT_MD5 implementation - the hashes all start with $1$
I've tried Phalanger but it doesn't have an MD5 implementation of the crypt function.
Does anyone know of one in .Net? The C# example of crypt() on CodeProject uses DES, not MD5.
I've tried the following code in C#, with different permutations of salt+password, password+salt and salt with and without $1$ prefix and $ suffix. None gives same result as PHP:
static void Main(string[] args)
{
const string salt = "somesalt";
const string password = "fubar";
const string plaintextString = password + salt;
byte[] plaintext = GetBytes(plaintextString);
var md5 = MD5.Create("MD5");
byte[] hash = md5.ComputeHash(plaintext);
string s = System.Convert.ToBase64String(hash);
Console.WriteLine("Hash of " + password + " is " + s);
Console.ReadKey();
}
private static byte[] GetBytes(string s)
{
var result = new byte[s.Length];
for (int i = 0; i < s.Length; i++)
result[i] = (byte)s[i];
return result;
}

There are a few .NET methods for md5 hashing, System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(password, format) is the easiest to use, even though it's a mouthful. Just pass "md5" through as the format.
Depending on how PHP is doing this, it may be as simple as chopping the $1$ off the beginning of the hash when you import it. It may be more complex. If you can post an example password/hash, I'll see if I can come up with some C# that generates the same hash from that password for you.

Have you taken a look at the .NET MD5 class? $1$ is part of a 12 character salt.

These look promising, at least.
unix md5crypt for CRYPT_MD5 with $1$ salts.
(A C# implementation of Unix crypt() for DES)

The only solution I found was to call a trivial PHP script that simply performs a hash of the input string and returns it :-(

I am currently working on exactly the same issue. The solution I came up with was to call the php function directly via an extern call:
[DllImport( "php5ts.dll", EntryPoint = "crypt", CharSet = CharSet.Ansi )]
private static extern string crypt( string str, string salt );
This works well for php version 5.2.10 when running the local WebDev server, IIS5 and IIS6 but if you use II7 the ASP.Net worker process crashes with an unhandled exception. (I will update my answer as soon as I find a resolution)
We are also including a password type flag to allow us to use the .Net MD5 implementation for all new users and seamlessly convert existing users over as they update their details.
Update: The issue with referencing php5ts.dll directly from IIS7 seems to most likely be down to using 64 bit windows, so this solution might work on a 32 bit Windows 7 or Server 2008 installation, however I am unable to verify this. As it turned out our existing site was using DES so we were able to use the crypt implementation from CodeProject, thanks for the reference Mike.

Related

Encryption with Node Crypto - Decryption with PHP openssl_decrypt fails

I'm trying to create a JWT (JSON web token) in a node service which then needs to be checked in a PHP service.
I'm creating the token as per the spec as far as I can tell, and I'm encrypting the signature with the Node crypto library. I've read that the only algorithm that'll work reliably between these technologies is aes-128-cbc so that's the one I'm using.
I had some luck using mcrypt_decrypt, but it was still not 100% correct which is still a fail. Also because that library is deprecated I'd rather use openssl_decrypt, which I cannot get to work at all, it simply returns false.
The secret and init vector are both stored in a database in fields of type varchar(16), so they are the same in both bits of code. I'm using a 16byte blocksize so matching that with 16byte secret and iv.
I've tried different combinations of binary, hex and base64 formats but cannot get the openssl_decrypt function to return anything but false.
This question comes down to how can I encrypt a string in node and decrypt it in PHP? Or what is wrong with my current usage of these methods?
Node v7.4.0
var crypto = require('crypto');
var secret = crypto.randomBytes(16);
var iv = crypto.randomBytes(16);
var header = { type:'JWT', alg: 'aes-128-cbc' };
var payload = { iss: 'auth-token', exp: Date.now() + 86400, token: <some uuid> };
var data = new Buffer(JSON.stringify(header)).toString('base64') + '.' + new Buffer(JSON.stringify(payload)).toString('base64');
var cipher = crypto.createCipheriv('aes-128-cbc', secret, iv);
var encrypted = cipher.update(data, 'utf8', 'base64') + cipher.final('base64');
var JWT = data + '.'+ encrypted;
PHP v7.0.13 (also tried v7.1.1)
list($header64, $payload64, $sigEnc) = explode('.', $_POST['jwt']);
$header = base64_decode ($header64);
$payload = base64_decode ($payload64);
$signature = openssl_decrypt($sigEnc, 'aes-128-cbc', $secret, null, $iv); // secret and iv are both straight out of the database
Update
I've changed my objective here now and used a hash, which is possibly the correct way. So in the Node service I create a SHA256 hash of the base64 header and payload using a random key stored in the database. Then in the PHP service I do the same and compare the hashes. This is a better approach, which I should have taken before.
But there is still the question of how can you reliably encrypt a string in Node and decrypt it in PHP?
There are libraries but they seem a little overkill for what should be fairly straightforward.
It should be fairly straightforward but apparently it isn't.
With cryptography you either understand it well enough to implement the algorithms yourself from scratch, or you don't try because it's too risky to get it wrong. It's bad enough when you make a mistake like you did when nothing works, but it is way worse when it seems to work but is weak and vulnerable to some attack that you didn't think about.
If you're serious about security then use the right tool for the job. In Node you have:
https://www.npmjs.com/package/jwt
https://www.npmjs.com/package/jsonwebtoken
https://www.npmjs.com/package/jwt-simple
https://www.npmjs.com/package/express-jwt
and many more.
For PHP you have:
https://github.com/firebase/php-jwt
https://github.com/namshi/jose
https://github.com/lcobucci/jwt
https://github.com/emarref/jwt
https://github.com/Spomky-Labs/jose
https://github.com/nov/jose-php
See https://jwt.io/ for more info, more tools and more tutorials.
If you want to learn how to do it correctly yourself without using a library, then read the source code of those libraries - they are all open source, free software.

Converting RSA encryption code from php to python

I'm trying to connect to a api in my python app .
so the api documentations comes with php and asp sample code but no python
I'm pretty good with php but have no experience with encryption ... I'm trying to re-write python code for the api using php sample .
They use this class for RSA
https://github.com/AlaFalaki/Pclass/blob/master/libraries/rsa.class.php
(Since its a RSA lib im guessing python RSA lib would take care of this part ) :
static function rsa_sign($message, $private_key, $modulus, $keylength) {
$padded = RSA::add_PKCS1_padding($message, false, $keylength / 8);
$number = RSA::binary_to_number($padded);
$signed = RSA::pow_mod($number, $private_key, $modulus);
$result = RSA::number_to_binary($signed, $keylength / 8);
return $result;
}
Here is the problem php sign function takes 4 arguments uses some internal functions ... But python rsa has 3 and one of them is just the hash method !
rsa.sign(message, priv_key, hash)
Parameters:
message – the message to sign. Can be an 8-bit string or a file-like object. If message has a read() method, it is assumed to be a file-like object.
priv_key – the rsa.PrivateKey to sign with
hash – the hash method used on the message. Use ‘MD5’, ‘SHA-1’, ‘SHA-256’, ‘SHA-384’ or ‘SHA-512’.
i've tried little experiment to see if i get same output
so i've singed a simple text string in php
echo base64_encode(RSA::rsa_sign(sha1("test"),$private_key,$modulus,$key_length));
i got
something like
dKt+4CocMNdIrtYCUr8aZykR8CpfmYUEEVONMuAPlM5mR70AoyzMhGjcEGB9fKLVC4rr5xt66w2ZmHqWO+p834rJmo9Fj57udRSY5wFs0VokMF2S2SMFn5WTYYmMBuWciRzZybWnfXcSIyp9Ibi28cdwl5hXJOMpXEJrNQLFy2s=
next i extracted private_key , public_key , modulus from a xml file that they gave me with api containing my keys ( using the same RSA class ) like
$xmlObj = simplexml_load_string($xmlRsakey);
$this->modulus = RSA::binary_to_number(base64_decode($xmlObj->Modulus));
$this->public_key = RSA::binary_to_number(base64_decode($xmlObj->Exponent));
$this->private_key = RSA::binary_to_number(base64_decode($xmlObj->D));
$this->key_length = strlen(base64_decode($xmlObj->Modulus))*8;
i made a python dictionary with them
def keys():
obj = {
'modulus' : "14417185111734127374105962730273......." ,
'public_key' : "61111" ,
'private_key' : "3739752306322843055980611965983321761993....." ,
'key_length' : 1024 ,
}
return obj
and i've tried to sign a string in python
def sign(request):
api = keys()
message = 'test'
crypto = rsa.sign(message.encode('utf-8'), api['private_key'] , 'SHA-1')
b64 = base64.b64encode(crypto)
return HttpResponse(b64)
but i get :
'str' object has no attribute 'n'
and that was my failed experiment
As i said i dont have any experience with encryption or rsa .... i want some advice from someone who worked with this stuff .
Should i give up and use php to encrypt/decrypt ?
They use this class for RSA
https://github.com/AlaFalaki/Pclass/blob/master/libraries/rsa.class.php
My advice: Run away screaming.
RSA is a mine field of security issues. There are a lot of things that you can screw up. So when someone implements the primitives in PHP using the BC extension, that's the security equivalent of standing naked in front of a firing squad and expecting to have no holes.
Encrypting with PKCS1 padding allows near-trivial message decryption
Screwing up your parameters can completely remove all security from your crypto
Home-grown RSA is ripe with side-channel attacks
Recommendation: Use Libsodium Instead
There are both PHP and Python bindings available for libsodium.
If RSA is Unavoidable...
If you really want RSA and not modern cryptography, check out phpseclib.
<?php
use
$rsa = new RSA();
// HIGHLY RECOMMENDED FOR SECURITY:
$rsa->setEncryptionMode(RSA::ENCRYPTION_OAEP);
$rsa->setMGFHash('sha256');
$rsa->loadKey($yourPEMencodedRSAPublicKey);
$ciphertext = $rsa->encrypt($plaintext);
If you're going to encrypt with RSA, you must follow these cryptography rules. If your library doesn't let you follow these rules, it's time to switch to libsodium.
Also note that encrypting large messages with RSA is both slow and dangerous: There's usually nothing preventing messages from being reordered, which can be really bad.
The solution here is: Use symmetric-key authenticated encryption and use RSA to encrypt the public key. That's what EasyRSA does, although I'm not aware of any Python equivalents, so I can't recommend that as a solution.
Of course, if you use libsodium's crypto_box API you don't have to worry about that!

Hashing a string in PHP in the same way as in VB.NET

I have following encryption function and don't know in which language this code is written. as per my knowledge this function is encrypting string in SHA256.
Use Namespace: Imports System.Security.Cryptography
Data: Agent Code ~ Userid ~ Security ID~ MerchantID~ Terminalid~ LoginKey
Public Function EncryptSHA(ByVal Data As String) As String
Dim sh As New SHA256Managed
Try
Convert.ToBase64String(sh.ComputeHash(Encoding.ASCII.GetBytes(Data)))
Dim eNC_data As Byte() = ASCIIEncoding.ASCII.GetBytes(Data)
Dim eNC_str As String = Convert.ToBase64String(eNC_data)
Return eNC_str
Catch ex As ExceptionGeneral.Err_Handler("General", "EncryptSHA", ex.Message)
Return Nothing
End Try
End Function
I am working on php and want same php encryption function in php .
Please someone explain what encryption this function is using ??
Here is my php code :
$data='Agent Code ~ Userid ~ Security ID~ MerchantID~ Terminalid~ LoginKey';
$encryptcode = hash('SHA256', $data);
Sorry for my bad english.
SHA256 is a hash function and that's a oneway enryption. There is no way to decrypt it. The whole purpose of a cryptographic hash function is that you can't reverse it. It is used for example to verify a users password: Compare the hash of a users password with the hash saved in the database, to verify a users identity.
If you want to break it you can try these techniques:
Brute force
Rainbow tables

PHP equivalent to Rijndael AES encryption/decryption in .Net?

Is there an equivalent functions in PHP that will allow interoperability with the .Net Rijndael AES encryption/decryption? (The encryption .Net code is below).
Basically, if I encrypt in .Net can I decrypt in PHP and vice-versa?
string outStr = null; // Encrypted string to return
RijndaelManaged aesAlg = null; // RijndaelManaged object used to encrypt the data.
// Generate the key from the shared secret and the salt.
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, _salt);
// Create a RijndaelManaged object
aesAlg = new RijndaelManaged();
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
// Create a decryptor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
// prepend the IV
msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof(int));
msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
}
outStr = Convert.ToBase64String(msEncrypt.ToArray());
}
You can, maybe, but I cannot in good conscience recommend it.
PHP offers two extensions that can, in principle, do the job. OpenSSL suffers from not being documented beyond function prototypes, and Mcrypt suffers from being an absolute minefield if you don't happen to know exactly what you're doing. I wouldn't use either if I could possibly get away with it.
If you do attempt this, you will need to implement authentication yourself. You will need to implement padding yourself. If you screw up, you will get no indication even if the library knows perfectly well it's been asked to do something absurd, for the most part it will (silently!) guess at what you meant and continue on (patches for much of this are available, but not yet in mainline).
Godspeed.
As long as PHP and .Net follow specs encryption/decryption should work. You may check this topic for more info and examples Using PHP mcrypt with Rijndael/AES
As #Andrew says, once you get everything in the same spec, it should work. AES is quite a well used algorithm so librarys in both languages should match up. Any problems are usually to do with the password to key derivation functions in the different languages. This project tries to solve the intercommunication issues between .NET and PHP. It implements Rfc2898DeriveBytes() in PHP using a pbkdf2 with 1000 iterations of HMACSHA1 which I guess is what .NET uses by default.
It is a rather simple AES string encryption so there is no authentication. The padding issue is solved by using base64 encoding and rtrimming null characters on decryption so it is NOT a binary safe implementation. I take no credit or responsibility for this code, nor have I tested it between the different environments, but I feel it could help someone fill in the gaps.

How to convert php crypt function (SHA512) to ruby?

note: i am not looking for workaround, i am looking for a plain ruby solution!
this question is the similar to this question, but it isn't answerd, its just a workaround to a shell commando there.
i want to generate a sha512 encrypted string which is compatible with the format in debian /etc/shadow.
the following create a correct string with php:
$salt = 'fGn9LR75';
$hash = crypt('test', '$6$'.$salt);
// hash is:
// $6$fGn9LR75$YpI/vJHjEhvrYp5/eUSRinpiXdMthCxFWSEo0ktFNUaRBsA7pCWYzzmQptmnfyHno9YEJFNHYuESj3nAQmSzc1
as far as i know this a normal, salted base64 encoded string. the spec of the sha generation method is here
irb(main):001:0> salt = 'fGn9LR75';
irb(main):002:0* hash = 'test'.crypt('$6$' + salt);
irb(main):003:0* hash
=> "$6$fGn9LR75$YpI/vJHjEhvrYp5/eUSRinpiXdMthCxFWSEo0ktFNUaRBsA7pCWYzzmQptmnfyHno9YEJFNHYuESj3nAQmSzc1"
The crypt() algorithm for SHA256/512 is not simply a base64-encoded hash. It's an intentionally crazy process which involves multiple hashes running in parallel.

Categories