I try to decrypt data which is encrypted with PHP from local money transfer service.
There is PHP example as following:
<?php
require_once('phpseclib/Crypt/AES.php');
define('API_PASSKEY', 'abcdefghijklmnop');
if($_SERVER['REMOTE_ADDR'] == '203.146.127.115' && isset($_GET['request']))
{
$aes = new Crypt_AES();
$aes->setKey(API_PASSKEY);
$_GET['request'] = base64_decode(strtr($_GET['request'], '-_,', '+/='));
$_GET['request'] = $aes->decrypt($_GET['request']);
if($_GET['request'] != false)
{
parse_str($_GET['request'],$request);
$request['Ref1'] = base64_decode($request['Ref1']);
echo 'SUCCEED';
}
else
{
echo 'ERROR|INVALID_PASSKEY';
}
}
else
{
echo 'ERROR|ACCESS_DENIED';
}
?>
However, I want to do decrypt with C#.
I also set up simple PHP encrypt text for testing but cannot decrypt with C# either.
<?php
include('phpseclib/Crypt/AES.php');
$aes = new Crypt_AES();
$aes->setKey('abcdefghijklmnop');
$plaintext = 'Hello';
$cryptoText = $aes->encrypt($plaintext) ;
$cryptoText = base64_encode( $cryptoText);
echo $cryptoText . "<br/>";
echo $aes->decrypt(base64_decode($cryptoText));
?>
I looking forward to get your good suggestion.
phpseclib uses CBC by default with PKCS#7 padding enabled and 128-bit keys if that helps.
Related
So I got an ASP.NET web app which uses hashing with salt to store password in mysql database. I am now trying to allow user to login with the same credentials as my web app through a php website. I used the following code to compare user input and hash in php
$pw = $salt . $extpassword;
if (!mb_check_encoding($pw, 'UTF-8')) {
$pw = mb_convert_encoding($pw, 'UTF-8');
}
return ($fromdb == base64_encode(hash('sha256',$pw, true)));
As for my code in c# used to generate hash:
System.Security.Cryptography.SHA256Managed sha256 = new System.Security.Cryptography.SHA256Managed();
byte[] hash = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(pw + salt));
return Convert.ToBase64String(hash);
I am not sure why this wouldn't work as I'm completely new to php. Can anyone please help?
In php you have salt + password, in .net you have pw + salt.
That will give different results. Fix by using:
$pw = $extpassword . $salt;
or
byte[] hash = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(salt + pw));
I have a c# code that convert a string to md5 and then base64 encode it.
I would like to do the same thing with a perl script or linux cli, openssl.
i tried using openssl cli, but i get a different result from the c# code.
can anyone explain and show me how to convert the c# code to linux cli or perl script?
Thanks.
public class Program {
public static void Main() {
var myString = "7512";
var o = CalculateMD5Hash(myString);
Console.WriteLine("Generated String is: {0}", o);
}
public static string CalculateMD5Hash(string input) {
HashAlgorithm ha = new MD5CryptoServiceProvider();
string prefix = "MD5:";
string password = "";
UnicodeEncoding enc = new UnicodeEncoding();
password = Convert.ToBase64String(ha.ComputeHash(enc.GetBytes(input)));
return prefix+password;
}
}
# Linux openssl cli
echo -ne '7512' | openssl dgst -md5 -binary | openssl base64
When i run the c# code with the string: 7512, i get:
cA5YjDeU2fOJwwnVFPCuAw==
But when i am using the openssl cli command, i get:
FhxcWtUfzIhBV4kFEbPIsA==
Well, got an answer in perlmonks site.
https://perlmonks.org/index.pl?node_id=1227872
UnicodeEncoding encodes to UTF-16LE. So in Perl, you'll have to use the Encode module for that, and then either use md5_base64 from Digest::MD5, which removes the padding at the end of the string (==), or, if you want the padding, you'll have to use MIME::Base64 separately:
use warnings;
use strict;
use Encode qw/encode/;
use Digest::MD5 qw/md5/;
use MIME::Base64 qw/encode_base64/;
my $string = "7512";
my $md5b64 = encode_base64( md5( encode( 'UTF-16LE', $string,
Encode::FB_CROAK|Encode::LEAVE_SRC ) ), "" );
print "Generated String is: MD5:$md5b64\n";
my $expect = "cA5YjDeU2fOJwwnVFPCuAw==";
print $md5b64 eq $expect ? "Matches!\n" : "Doesn't match!\n";
__END__
I am in need of assistance with signing a string in PHP. We are building a web application which is able to alter profile data on an external website. We want to achieve this without requiring end users to enter our password on our site. The external website therefore created an API which allows us to edit the profile as long we send them email address of the profile signed by a certificate. This allows them to check whether the request came from a trusted source (us).
We tried both native PHP functions and PHPSeclib to sign an email address using a certificate:
$rsa = new RSA();
$rsa->setHash("sha1");
$rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
$originalkey = file_get_contents('key.ppk');
$rsa->loadKey($originalkey);
echo bin2hex($rsa->sign("test#email.nl"));
// Using native PHP methods
$email = 'test#email.nl';
$signature = '';
$private_key = openssl_pkey_get_private(file_get_contents("key.ppk"));
var_dump(openssl_sign($email, $signature, $private_key, "sha1"));
echo bin2hex($signature);
The signatures are fine because PHP is able to verify the posted signatures. The webservice of the external website does not accept our signatures however. They only allow a signature length of 40 characters whilst a hexidecimal dump of our signature exceeds 1000 characters.
They sent us this C# example to sign a string but we do not have enough C# knowledge to see why the output differs.
string Sign(string username, string thumbprint, string hasher = "SHA1")
{
var store = new
System.Security.Cryptography.X509Certificates.X509Store(System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine);
store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.OpenExistingOnly |
System.Security.Cryptography.X509Certificates.OpenFlags.ReadOnly);
try
{
foreach (System.Security.Cryptography.X509Certificates.X509Certificate2 certificate in store.Certificates.Find(System.Security.Cryptography.X509Certificates.X509FindType.FindByThumbprint, thumbprint, false))
{
var privateKey = certificate.PrivateKey as System.Security.Cryptography.RSACryptoServiceProvider;
if (privateKey != null)
{
var bytes = privateKey.SignData(Encoding.UTF8.GetBytes(username),
System.Security.Cryptography.HashAlgorithm.Create(hasher));
return string.Join("", bytes.Select(b => b.ToString("x2")));
} else throw new ArgumentException("no private key");
}
}
finally
{
store.Close();
}
return null;
}
Is there anyone who can point us to the right direction?
Thanks in advance!
I am trying to connect to a MS SQL database through Unity. However, when I try to open a connection, I get an IOException: Connection lost.
I have imported System.Data.dll from Unity\Editor\Data\Mono\lib\mono\2.0. I am using the following code:
using UnityEngine;
using System.Collections;
using System.Data.Sql;
using System.Data.SqlClient;
public class SQL_Controller : MonoBehaviour {
string conString = "Server=myaddress.com,port;" +
"Database=databasename;" +
"User ID=username;" +
"Password=password;";
public string GetStringFromSQL()
{
LoadConfig();
string result = "";
SqlConnection connection = new SqlConnection(conString);
connection.Open();
Debug.Log(connection.State);
SqlCommand Command = connection.CreateCommand();
Command.CommandText = "select * from Artykuly2";
SqlDataReader ThisReader = Command.ExecuteReader();
while (ThisReader.Read())
{
result = ThisReader.GetString(0);
}
ThisReader.Close();
connection.Close();
return result;
}
}
This is the error I get:
IOException: Connection lost
Mono.Data.Tds.Protocol.TdsComm.GetPhysicalPacketHeader ()
Mono.Data.Tds.Protocol.TdsComm.GetPhysicalPacket ()
Mono.Data.Tds.Protocol.TdsComm.GetByte ()
Mono.Data.Tds.Protocol.Tds.ProcessSubPacket ()
Mono.Data.Tds.Protocol.Tds.NextResult ()
Mono.Data.Tds.Protocol.Tds.SkipToEnd ()
Rethrow as TdsInternalException: Server closed the connection.
Mono.Data.Tds.Protocol.Tds.SkipToEnd ()
Mono.Data.Tds.Protocol.Tds70.Connect (Mono.Data.Tds.Protocol.TdsConnectionParameters connectionParameters)
Mono.Data.Tds.Protocol.Tds80.Connect (Mono.Data.Tds.Protocol.TdsConnectionParameters connectionParameters)
Please disregard any security risks with this approach, I NEED to do this for testing, security will come later.
Thank you for your time.
Please disregard any security risks with this approach
Do not do it like this. It doesn't matter if security will come before or after. You will end of re-writing the whole code because the password is hard-coded in your application which can be decompiled and retrieved easily. Do the connection the correct way now so that you won't have to re-write the whole application.
Run your database command on your server with php, perl or whatever language you are comfortable with but this should be done on the server.
From Unity, use the WWW or UnityWebRequest class to communicate with that script and then, you will be able to send and receive information from Unity to the server. There are many examples out there. Even with this, you still need to implement your own security but this is much more better than what you have now.
You can also receive data multiple with json.
Below is a complete example from this Unity wiki. It shows how to interact with a database in Unity using php on the server side and Unity + C# on the client side.
Server Side:
Add score with PDO:
<?php
// Configuration
$hostname = 'localhot';
$username = 'yourusername';
$password = 'yourpassword';
$database = 'yourdatabase';
$secretKey = "mySecretKey"; // Change this value to match the value stored in the client javascript below
try {
$dbh = new PDO('mysql:host='. $hostname .';dbname='. $database, $username, $password);
} catch(PDOException $e) {
echo '<h1>An error has ocurred.</h1><pre>', $e->getMessage() ,'</pre>';
}
$realHash = md5($_GET['name'] . $_GET['score'] . $secretKey);
if($realHash == $hash) {
$sth = $dbh->prepare('INSERT INTO scores VALUES (null, :name, :score)');
try {
$sth->execute($_GET);
} catch(Exception $e) {
echo '<h1>An error has ocurred.</h1><pre>', $e->getMessage() ,'</pre>';
}
}
?>
Retrieve score with PDO:
<?php
// Configuration
$hostname = 'localhost';
$username = 'yourusername';
$password = 'yourpassword';
$database = 'yourdatabase';
try {
$dbh = new PDO('mysql:host='. $hostname .';dbname='. $database, $username, $password);
} catch(PDOException $e) {
echo '<h1>An error has occurred.</h1><pre>', $e->getMessage() ,'</pre>';
}
$sth = $dbh->query('SELECT * FROM scores ORDER BY score DESC LIMIT 5');
$sth->setFetchMode(PDO::FETCH_ASSOC);
$result = $sth->fetchAll();
if(count($result) > 0) {
foreach($result as $r) {
echo $r['name'], "\t", $r['score'], "\n";
}
}
?>
Enable cross domain policy on the server:
This file should be named "crossdomain.xml" and placed in the root of your web server. Unity requires that websites you want to access via a WWW Request have a cross domain policy.
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*"/>
</cross-domain-policy>
Client/Unity Side:
The client code from Unity connects to the server, interacts with PDO and adds or retrieves score depending on which function is called. This client code is slightly modified to compile with the latest Unity version.
private string secretKey = "mySecretKey"; // Edit this value and make sure it's the same as the one stored on the server
public string addScoreURL = "http://localhost/unity_test/addscore.php?"; //be sure to add a ? to your url
public string highscoreURL = "http://localhost/unity_test/display.php";
//Text to display the result on
public Text statusText;
void Start()
{
StartCoroutine(GetScores());
}
// remember to use StartCoroutine when calling this function!
IEnumerator PostScores(string name, int score)
{
//This connects to a server side php script that will add the name and score to a MySQL DB.
// Supply it with a string representing the players name and the players score.
string hash = Md5Sum(name + score + secretKey);
string post_url = addScoreURL + "name=" + WWW.EscapeURL(name) + "&score=" + score + "&hash=" + hash;
// Post the URL to the site and create a download object to get the result.
WWW hs_post = new WWW(post_url);
yield return hs_post; // Wait until the download is done
if (hs_post.error != null)
{
print("There was an error posting the high score: " + hs_post.error);
}
}
// Get the scores from the MySQL DB to display in a GUIText.
// remember to use StartCoroutine when calling this function!
IEnumerator GetScores()
{
statusText.text = "Loading Scores";
WWW hs_get = new WWW(highscoreURL);
yield return hs_get;
if (hs_get.error != null)
{
print("There was an error getting the high score: " + hs_get.error);
}
else
{
statusText.text = hs_get.text; // this is a GUIText that will display the scores in game.
}
}
public string Md5Sum(string strToEncrypt)
{
System.Text.UTF8Encoding ue = new System.Text.UTF8Encoding();
byte[] bytes = ue.GetBytes(strToEncrypt);
// encrypt bytes
System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] hashBytes = md5.ComputeHash(bytes);
// Convert the encrypted bytes back to a string (base 16)
string hashString = "";
for (int i = 0; i < hashBytes.Length; i++)
{
hashString += System.Convert.ToString(hashBytes[i], 16).PadLeft(2, '0');
}
return hashString.PadLeft(32, '0');
}
This is just an example on how to properly do this. If you need to implement session feature and care about security, look into the OAuth 2.0 protocol. There should be existing libraries that will help get started with the OAuth protocol.
An alternative would be to create your own dedicated server in a command prompt to do your communication and connecting it to unity to Handel multiplayer and SQL communication. This way you can stick with it all being created in one language. But a pretty steep learning curve.
Unity is game engine.
so That's right what the answer says.
but, Some domains need to connect database directly.
You shouldn't do that access database directly in game domain.
Anyway, The problem is caused by NON-ENGLISH computer name.
I faced sort of following errors at before project.
IOException: Connection lost
Mono.Data.Tds.Protocol.TdsComm.GetPhysicalPacketHeader ()
Mono.Data.Tds.Protocol.TdsComm.GetPhysicalPacket ()
Mono.Data.Tds.Protocol.TdsComm.GetByte ()
Mono.Data.Tds.Protocol.Tds.ProcessSubPacket ()
Mono.Data.Tds.Protocol.Tds.NextResult ()
Mono.Data.Tds.Protocol.Tds.SkipToEnd ()
Rethrow as TdsInternalException: Server closed the connection.
Mono.Data.Tds.Protocol.Tds.SkipToEnd ()
Mono.Data.Tds.Protocol.Tds70.Connect (Mono.Data.Tds.Protocol.TdsConnectionParameters connectionParameters)
Mono.Data.Tds.Protocol.Tds80.Connect (Mono.Data.Tds.Protocol.TdsConnectionParameters connectionParameters)
And after changing computer name as ENGLISH, It works.
I don't know how it's going. But It works.
Mono's System.Data.dll has some issues in P.C has NON-ENGLISH Computer name.
So, at least Unity project.
You should tell your customer Do not set their computer name as NON-ENGLISH.
I don't know people in mono knows these issue or not.
---------- It's OK in after 2018 version ----------
Api Compatibility Level > .Net 4.x
You can connect database in Non-english computer name machine.
what i am trying to do is when a user registers the password gets encrypted, and the encrypted password gets saved in a database, and when the user logs in it should then decrypt the password to compare if the user entered the correct password, but when i try to decrypt its gives me a "Bad data" exception.
Please help guys.
Here is my code:
protected void btnLogin_Click(object sender, EventArgs e)
{
try
{
private Cryptography crypt = new Cryptography();
var registerUser = new test.Model.User();
registerUser.EmailAddress = txtEmail.Text;
registerUser.Password = txtPassword.Text;
//new test().Getbyusername(registerUser);
new test().getbyemail(registerUser, crypt);
}
catch (Exception ex)
{
}
}
public void getbyemail(User user, Cryptography crypt)
{
try
{
var repo = new UserRepository();
var test = repo.GetEncryptedPasswrd(user);
var o = repo.getPrivateKey(user.EmailAddress);
crypt.privateKey = o;
var j = repo.getpublicKey(user.EmailAddress);
crypt.publicKey = j;
decryptPassword(test, o, crypt);
}
catch (Exception ex)
{
}
}
public String decryptPassword(byte [] encryptedpassword, string privateKey, Cryptography cry)
{
decrypted = cry.decrypt(encryptedpassword, privateKey);
//return Encoding.ASCII.GetString(decrypted);
return Encoding.ASCII.GetString(decrypted);
}
protected void btnRegister_Click(object sender, EventArgs e)
{
Cryptography crypt = new Cryptography();
var registerUser = new test.Model.User();
registerUser.Name = txtName.Text;
registerUser.Surname = txtSurname.Text;
registerUser.EmailAddress = txtEmailAddress.Text;
registerUser.Password = txtPassword.Text;
registerUser.DateRegisterd = DateTime.Now;
new test().RegisterUser(registerUser, crypt.privateKey, crypt.publicKey,crypt, encrypted);
}
public void RegisterUser(User user, string privateKey, string publicKey, Cryptography crypt, byte[] encrypted)
{
try
{
var repo = new UserRepository();
byte[] plainText = Encoding.ASCII.GetBytes(user.Password);
encrypted = crypt.encrypt(plainText, crypt.publicKey);
user.Password = Encoding.ASCII.GetString(encrypted);
user.PrivateKey = crypt.privateKey;
user.PublickKey = crypt.publicKey;
repo.Add(user);
}
catch (Exception ex)
{
}
}
Thanks in advance.
As said above comment you should really hash it .
Still if you want to encrypt as you example don't decrypt password . Instead you should encrypt password from user and simply compare to database .
You can Consider this simple option to hash the password . http://davidhayden.com/blog/dave/archive/2004/02/16/157.aspx .
You should not be encrypting passwords. Encryption is a reversable process, so if someone were to steal the encryption key and the passwords, they could get the user's password.
Instead, you should hash the password, and compare the hashes. A hash is destructive - it is impossible to get the original data from a hash. When a user signs up, you store the hash. When they want to sign back in, you hash what they entered and compare the hashes in the database. A hash using an algorithm like SHA-256 can be done like this:
public string GetPasswordHash(string clearPassword)
{
using (var hash = new System.Security.Cryptography.SHA256Managed())
{
var hashBytes = System.Text.Encoding.UTF8.GetBytes(clearPassword);
return Convert.ToBase64String(hash.ComputeHash(hashBytes));
}
}
This gets us a step further, but you should also use a salt as well to prevent attacks like Rainbow Tables. In addition, hashing it multiple times (say 10,000) helps prevent against against brute force attacks. 10,000 hashes is fast for the user logging in, but extremely slow trying to brute force.
I would start with writing a unit test that takes a password, encrypts it an immediately decrypts it.
Once you know that works, make a copy of the encrypted password, and test if you can make a successful roundtrip to the database. If that is binary, encoding it to hex or base64 might help.
there can be a security hole when you're able to decrypt the password. What you should do is encrypt the submitted password as well and compare the encrypted strings.
EDIT: thanks Matthew... that's what i meant...doh
the better question is why aren't you making full use of .net built in login control? You'll need to configure your web.config.
for best security. add the following in your membership provider settings in web.config
enablePasswordRetrieval="False" enablePasswordReset="True" passwordFormat="Hashed"
also add machinekey in
<system.web>
http://www.qualitydata.com/products/aspnet-membership/help/configuration/no-machinekey.aspx