I am converting .net project to PHP . But unable to convert the following code:
public static string HashString(string value)
{
SHA1 hasher = new SHA1CryptoServiceProvider();
UTF8Encoding enc = new UTF8Encoding();
byte[] hashInBytes = hasher.ComputeHash(enc.GetBytes(value));
return Convert.ToBase64String(hashInBytes);
}
So far I have done this but result is not same:
function HashString($str) {
return base64_encode(sha1($str));
}
Please help, thanks.
The reason behind the difference is, PHP uses ASCII encoding for hash calculations.
In C#, you can replace UTF8Encoding with ASCIIEncoding in order to have same results.
Finally I found the solution:
This is the final code which is equivalent to .net code:
function HashString($str) {
return base64_encode(sha1($str,true));
}
I have added "true" with sha1 function.
Related
I've been trying to get this for hours now, and I can't find what's wrong. I'm using a php RESTful API that I made to encrypt data using asymmetric encryption.
First, I save my user's public key in the server by exporting it in android:
fun exportPublicKey() : String {
val publicKey = getPublicKey()
return android.util.Base64.encodeToString(
publicKey!!.encoded,
android.util.Base64.NO_WRAP
)
}
This allows me in the PHP server to do that:
$public_key_core = $_POST["public_key"];
$public_key = "-----BEGIN PUBLIC KEY-----\n" . $public_key_core . "\n-----END PUBLIC KEY-----";
I am unsure that's the right way but openssl seems to be "ok" with that key ?
I then tested my keystore in local using both keys, and it works just fine using this code:
Encrypt:
fun encryptAsymmetricData(data: String, usePrivateKey : Boolean = true): ByteArray {
val cipher : Cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
val encryptedBytes: ByteArray
if (usePrivateKey){
cipher.init(Cipher.ENCRYPT_MODE, getPrivateKey())
encryptedBytes = cipher.doFinal(data.toByteArray(Charsets.UTF_8))
} else {
cipher.init(Cipher.ENCRYPT_MODE, getPublicKey())
encryptedBytes= cipher.doFinal(data.toByteArray(Charsets.UTF_8))
}
return encryptedBytes
}
Decrypt:
fun decryptAsymmetricData(data: ByteArray): String{
val cipher : Cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
cipher.init(Cipher.DECRYPT_MODE, getPrivateKey())
return cipher.doFinal(data).toString(Charsets.UTF_8)
}
Using this works because I do ".toByteArray(Charsets.UTF_8)" on the encryptData result.
Now here's the problem, I use base64 encoding and do the following to encrypt in PHP:
openssl_public_encrypt($token->token, $encrypted_token, $user->public_key);
openssl_public_encrypt($user->id, $encrypted_id, $user->public_key);
[...]
'encrypted_user_id' => base64_encode($encrypted_id),
'encrypted_token' => base64_encode($encrypted_token)
But when I try to decrypt this in Android I'm getting an exception "javax.crypto.IllegalBlockSizeException" caused by this code:
val tokenBA = String(getDecoder().decode(this.encryptedToken), Charsets.UTF_8).toByteArray(Charsets.UTF_8)
val userIDBA = String(getDecoder().decode(this.encryptedUserId), Charsets.UTF_8).toByteArray(Charsets.UTF_8)
val token = App.encryptionController.decryptAsymmetricData(tokenBA)
val userID = App.encryptionController.decryptAsymmetricData(userIDBA)
(The logic being, I use base64 to send back my data in PHP, so I convert it to UTF8 in Android, then get the associated ByteArray to decrypt it ?)
I know that the encryption works in "local" but it doesn't when using both PHP and KeyStore, so I guess the problem is coming either from the PHP encryption, or from the way I try to decrypt it in android, but I can't seem to find what wrong, could you guys help me there please ?
Thank you by advance!
Ok, after searching and making sure the issue wasn't the public key stored in the PHP server, I found the answer. It was caused by the way to convert the "base64" string in an actual ByteArray in the App. This worked:
val token = App.encryptionController.decryptAsymmetricData(getDecoder().decode(encryptedToken))
val userID = App.encryptionController.decryptAsymmetricData(getDecoder().decode(encryptedUserId))
This is only working because I do the "base64_encode" in the server, for some (bad) reason I thought it was needed to go back to UTF8 to get the ByteArray in the app.
TrinityCore deprecated the old sha_pass_hash column on the auth table, in favour of the much safer SRP6 method. However, I am unable to properly calculate the verifier in C#/dotnet NOR in PHP using the example provided here. I've looked at examples but it doesn't seem to be working the way that the TrinityCore developers suggest. Does anyone know about SRP6 that might be able to figure out what's wrong in the code? I've also looked at this example but it uses a hardcoded salt? If someone can show me what's wrong in the PHP I might be able to figure out what's wrong with the .NET
The code I tried looks closest to the first example, but I flip my arrays around to be little-endian.
public byte[] CalculateVerifier(string username, string password, byte[] salt)
{
if (BitConverter.IsLittleEndian)
{
return BigInteger.ModPow(
g,
new BigInteger(Hash(salt, Hash(Encoding.UTF8.GetBytes($"{username.ToUpper()}:{password.ToUpper()}")))),
N
).ToByteArray();
}
else
{
return BigInteger.ModPow(
g,
new BigInteger(Hash(salt, Hash(Encoding.UTF8.GetBytes($"{username.ToUpper()}:{password.ToUpper()}")).Reverse().ToArray())),
N
).ToByteArray();
}
}
public bool VerifySRP6Login(string username, string password, byte[] salt, byte[] verifier)
{
// re-calculate the verifier using the provided username + password and the stored salt
byte[] checkVerifier = CalculateSRP6Verifier(username, password, salt);
Console.WriteLine($"{Encoding.ASCII.GetString(verifier)} {verifier.Length} bytes\n{Encoding.ASCII.GetString(checkVerifier)} {checkVerifier.Length} bytes");
Console.WriteLine($"{new BigInteger(verifier)}\n{new BigInteger(checkVerifier)}");
// compare it against the stored verifier
return verifier.SequenceEqual(checkVerifier);
}
public byte[] Hash(byte[] componentOne, byte[] componentTwo)
{
if (componentOne == null) throw new ArgumentNullException(nameof(componentOne));
if (componentTwo == null) throw new ArgumentNullException(nameof(componentTwo));
//WoW expects non-secure SHA1 hashing. SRP6 is deprecated too. We need to do it anyway
using (SHA1 shaProvider = SHA1.Create())
{
//See Jackpoz's Combine function
return shaProvider.ComputeHash(componentOne.Concat(componentTwo).ToArray());
}
}
public byte[] Hash(byte[] bytes)
{
if (bytes == null) throw new ArgumentNullException(nameof(bytes));
//WoW expects non-secure SHA1 hashing. SRP6 is deprecated too. We need to do it anyway
using (SHA1 shaProvider = SHA1.Create())
{
return shaProvider.ComputeHash(bytes);
}
}
The answer was found in this solution, apparently I wasn't properly making my BigInteger, because the data was an unsigned int and I was treating it as signed.
I have a project I'm working on that uses an API for it request, but in order to preform them I need to generate the token first.
Before the API was update everything was working, after the update I don't know how to adjust my code to make it work again.
This was the code that worked before the update (Android | Kotlin):
fun hmacHash(str: String, secret: String): String {
val sha256HMAC = Mac.getInstance("HmacSHA256")
val secretKey = SecretKeySpec(secret.toByteArray(), "HmacSHA256")
sha256HMAC.init(secretKey)
return convertToHex(sha256HMAC.doFinal(str.toByteArray()))
}
fun convertToHex(data: ByteArray): String {
val buf = StringBuilder()
for (b in data) {
var halfbyte = (b.toInt() shr 4) and (0x0F.toByte()).toInt()
var two_halfs = 0
do {
buf.append(if (halfbyte in 0..9) ('0'.toInt() + halfbyte).toChar() else ('a'.toInt() + (halfbyte - 10)).toChar())
halfbyte = (b and 0x0F).toInt()
} while (two_halfs++ < 1)
}
return buf.toString()
}
Which was equivalent to this PHP code:
hash_hmac('sha256', $string, $privateKey);
But now after the update the php code looks like this:
hash_hmac('sha256', $string, hex2bin($privateKey));
And I don't know how to adjust my code to make it work with this new change.
From what I can deduce, the PHP code made that change because $privateKey went from being plain text to being hex-encoded. So hex2bin was needed to change it back to plain text (hex2bin changes hex-encoded text to plain text; a confusingly named function if you ask me).
Since your secret is plain text, you don't need to change anything to match. But there are other ways to improve your code. For example, converting a byte array to a hex-encoded string is much easier than that.
fun hmacHash(str: String, secret: String): String {
val sha256HMAC = Mac.getInstance("HmacSHA256")
val bytes = secret.toByteArray()
val secretKey = SecretKeySpec(bytes, "HmacSHA256")
sha256HMAC.init(secretKey)
return convertToHex(sha256HMAC.doFinal(str.toByteArray()))
}
fun convertToHex(data: ByteArray): String =
data.joinToString("") { "%02x".format(it) }
There's a following function written in VBA.NET which I'm trying convert to PHP. I'm primarly a PHP developer, and I have alsmost zero-knowledge in VB.
<%
Public Shared Function ComputeHash(ByVal Key As String) As String
Dim objSHA1 As New SHA1CryptoServiceProvider
objSHA1.ComputeHash(System.Text.Encoding.UTF8.GetBytes(Key.ToCharArray))
Dim buffer() As Byte = objSHA1.Hash
Dim HashValue As String = System.Convert.ToBase64String(buffer)
Return HashValue
End Function
%>
I have tried searching for manuals and found some guidelances.
This is so far what I have converted to PHP myself:
function compute_hash($string){
return base64_encode(sha1($string));
}
Hovewer it doesn't produce the same result as VB's function ComputeHash(). Coudn't someone tell what I'm doing wrong?
Example of execution on both languages:
VBA.NET
string = "orange45877687459999SENTRYORD01154321"
ComputeHash(string) // Returns = WbwSWEBzPqgo9C4nZmGwHhd/FBQ=
PHP
$string = "orange45877687459999SENTRYORD01154321";
compute_hash(string) // Returns = NTliYzEyNTg0MDczM2VhODI4ZjQyZTI3NjY2MWIwMWUxNzdmMTQxNA== (but I need "WbwSWEBzPqgo9C4nZmGwHhd/FBQ=")
You need to instruct PHP to return the SHA1-hash in bytes instead of in hex format, by passing the TRUE parameter to the hashing function:
function compute_hash($string){
return base64_encode(sha1($string, TRUE));
}
PHP manual for SHA1
I'm currently rewriting an asp classic site in PHP, everything so far has been simple until I reached the password hashing function. In PHP I've used hash_hmac and hash, but I seem unable to replicate this functions results using a static salt in PHP. Please could someone help guide me as to how to produce the same result in PHP?
<% Function Hash(strPassword, strIndividualSalt)
Const strSiteWideSalt = "Bacon and HASH is best served with a good Salt!"
Hash = HashSHA512Managed(strSiteWideSalt & strPassword & strIndividualSalt)
End Function
Function HashSHA512Managed(saltedPassword)
Dim objMD5, objUTF8
Dim arrByte
Dim strHash
Set objUnicode = CreateObject("System.Text.UnicodeEncoding")
Set objSHA512 = Server.CreateObject("System.Security.Cryptography.SHA512Managed")
arrByte = objUnicode.GetBytes_4(saltedPassword)
strHash = objSHA512.ComputeHash_2((arrByte))
HashSHA512Managed = ToBase64(strHash)
End Function
Function ToBase64(rabyt)
Dim xml: Set xml = CreateObject("MSXML2.DOMDocument.3.0")
xml.LoadXml "<root />"
xml.documentElement.dataType = "bin.base64"
xml.documentElement.nodeTypedValue = rabyt
ToBase64 = xml.documentElement.Text
End Function
response.write Hash("mypassword", "mysalt")%>
This outputs...
1Asf3PuLZetBni4laI7jDKG3fbhlzKzB41G2694oZdH6nELLXklqtvY8Tniqjf3/2/gGg01fzs4w67l1Tfs20A==
Should I be using hash_hmac? Or do I need to replicate the function in PHP using hash()? Any help would be appreciated.