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
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've written a C# piece that encrypts/decrypts a string using RtlEncryptMemory/RtlDecryptMemory. This string is then saved in a config file, it all works well but the problem is that once I logoff/logon, I can no longer decrypt the string. I am using the RTL_ENCRYPT_OPTION_SAME_LOGON option which means the internal mechanism uses something from the Windows session in order to perform the decryption. I am looking for a solution that works in the same manner but is tied to the network user (or token, etc...). Is Windows providing something already?
My goal is to be able to decrypt the string from anywhere as long as the process is running under the same user (network credentials). I also do not want to have the user type in a password or use an internal value as that could be compromised. Ideally it would be just like the RTL functions but provide an RTL_ENCRYPT_OPTION_SAME_USER option.
You want to use the DataProtection API
Here is a simple implementation that adds Encrypt and Decrypt string extensions...
public static class StringExtensions
{
public static string Encrypt(this string s)
{
if (String.IsNullOrEmpty(s))
{
return s;
}
else
{
var encoding = new UTF8Encoding();
byte[] plain = encoding.GetBytes(s);
byte[] secret = ProtectedData.Protect(plain, null, DataProtectionScope.CurrentUser);
return Convert.ToBase64String(secret);
}
}
public static string Decrypt(this string s)
{
if (String.IsNullOrEmpty(s))
{
return s;
}
else
{
byte[] secret = Convert.FromBase64String(s);
byte[] plain = ProtectedData.Unprotect(secret, null, DataProtectionScope.CurrentUser);
var encoding = new UTF8Encoding();
return encoding.GetString(plain);
}
}
}
Here is an example...
class Program
{
static void Main(string[] args)
{
string password = "Monkey123";
string encrypted = password.Encrypt();
Console.WriteLine($"Encrypted password = '{encrypted}'");
string decrypted = encrypted.Decrypt();
Console.WriteLine($"Decrypted password = '{decrypted}'");
}
}
Which produces this output...
Encrypted password = 'AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAA/6wDgM21DkStrNJQ35QDiwAAAAACAAAAAAAQZgAAAAEAACAAAAAPr3/aqafbt/RRoPVe75b+PFBhE6h9MLcQ2Ivsd3adOwAAAAAOgAAAAAIAACAAAABYxqEdzotL+7qXpWnbbpPRkfWZF6oh/meFsXzFtLPnrBAAAAB59VGbboP4Tye1N3dB7E3jQAAAAMQn8cAlnTDe1mwDEJriADizdT2Qr0DtPgpMje+rbjdkVpL+cKiEQs4om4i1hlLPgPn5MG5oVWFFnxU0d4c9TFg='
Decrypted password = 'Monkey123'
Notes:
Only the currently logged in user can decrypt the data encrypted with this code. This works across the network as long as the current user has a roaming profile.
Alternatively the scope can be local machine in which case only users logged in to the same machine can decrypt the data.
This is .NET Core 3.1 code and works only on Windows machines
Using statements...
using System;
using System.Security.Cryptography;
using System.Text;
You should not be using RtlEncryptMemory if you want to store the string, it is meant to only keep strings secure inside the running applications memory, it therefore can be stored/serialized and decrypted.
Have a look at DPAPI password encryption I think it should meet your needs.
I have a Nuget package you might like:
DataJuggler.Net.Cryptography .Net Framework
DataJuggler.Core.Cryptography Dot Net Core
Pretty simple to work with, here is a live demo:
https://blazorcrypto.datajuggler.com/
Source code and video link is available above also.
Usage:
Encryption:
// get the encryptedText
encryptedResult = CryptographyHelper.EncryptString(textToEncrypt, keyCode);
Decryption:
// get thedecryptedText
decryptedResult = CryptographyHelper.DecryptString(textToDecrypt, keyCode);
It also includes password hashing.
Let me know if you think it is worth the price of free.
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!
So I was coding a simple login registration windows app on visual studio as I wanted to start learning again C#
I have this registration page with a few fields, the code is very simple, I didn't do anything related to validation.
I am basically trying to hash the password using SHA1 in c# and output in another textbox, but I am a getting some unknown characters
Here is my code
private void button1_Click(object sender, EventArgs e)
{
if (username.Text.Trim()=="" || password.Text=="" || passwordc.Text=="" || fname.Text == "" || lname.Text == "" || birthday.Text == "")
{
MessageBox.Show("Please fill all the fields!");
}
else if (password.Text!=passwordc.Text) {
MessageBox.Show("Passwords don't match !");
}
else
{
String passwd="";
passwd = password.Text;
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(passwd);
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] passbyte = sha.ComputeHash(bytes);
string pass = System.Text.Encoding.UTF8.GetString(passbyte);
textBox1.Text = pass;
}
https://i.stack.imgur.com/SOPit.png
Is there anything wrong or is this a normal hashing? I am kinda confused now.
Thanks
The hash is just a bunch of bytes. They're not meaningful characters. If you want to turn the hash into a textual form, you can use Convert.ToBase64String():
string pass = Convert.ToBase64String(passByte);
Also, consider switching to SHA256. SHA1 is becoming easier and easier to crack as computing power increases. One common thing to do is to run the hashing process (the new hash becomes the password to hash) hundreds or thousands of times before storing it. It doesn't make too significant a difference in time for creating a hash to store, but it makes cracking the password take that many times longer.
Also, you'll want to start incorporating a random salt to each password to hash. This avoids rainbow table attacks and won't generate the same hash for identical passwords.
I have developed an C# win forms application in Visual Studio 2010 and to provide security to it I am generating a machine dependent key by using systems cpuId, biosId, diskId. It looks like
Now in Setup I am just getting one key input area like below.
and I want to show the machine key which is created for the specific system, above the serial key input area.
My need is that the end user or buyer of the Software call me and give me the machine key and then I will calculate a key using that key and send back to client or buyer.
This is my first setup project so I am totally unaware of this thing. I will really appreciate your humble response.
I like to break your question into two parts
Creating a UI with required fields or controls where user can provide the license key
There are two way to get the user input during the installation,
Creating a windows form with required controls to get the input(You can not open windows form as a modal pop up during the installation)
Creating a .wid file to get the user input(This would be the recommended approach)
Validating the license Key and aborting the installation when invalid key is used
Once you have got the user input during the installation you have to validate it, You can use Installer Class for this.
Install() method example
public override void Install(System.Collections.IDictionary stateSaver)
{
//Invoke the base class method
base.Install(stateSaver);
if (!keyEnteredByUser.Equals(generatedKey))
{
//This would abort the installation
throw new Exception("Invalid Key");
}
}
I think better you should take look in this Article.
In that he have taken the same way to generating the unique key as per the system. And the way to generate the unique key is follows.
public static string GetSystemInfo(string SoftwareName)
{
if (UseProcessorID == true)
SoftwareName += RunQuery("Processor", "ProcessorId");
if (UseBaseBoardProduct == true)
SoftwareName += RunQuery("BaseBoard", "Product");
if (UseBaseBoardManufacturer == true)
SoftwareName += RunQuery("BaseBoard", "Manufacturer");
// See more in source code
SoftwareName = RemoveUseLess(SoftwareName);
if (SoftwareName.Length < 25)
return GetSystemInfo(SoftwareName);
return SoftwareName.Substring(0, 25).ToUpper();
}
private static string RunQuery(string TableName, string MethodName)
{
ManagementObjectSearcher MOS =
new ManagementObjectSearcher("Select * from Win32_" + TableName);
foreach (ManagementObject MO in MOS.Get())
{
try
{
return MO[MethodName].ToString();
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.Message);
}
}
return "";
}
And following method which describes how to generate the password code which matches the unique key ,
static public string MakePassword(string st, string Identifier)
{
if (Identifier.Length != 3)
throw new ArgumentException("Identifier must be 3 character length");
int[] num = new int[3];
num[0] = Convert.ToInt32(Identifier[0].ToString(), 10);
num[1] = Convert.ToInt32(Identifier[1].ToString(), 10);
num[2] = Convert.ToInt32(Identifier[2].ToString(), 10);
st = Boring(st);
st = InverseByBase(st, num[0]);
st = InverseByBase(st, num[1]);
st = InverseByBase(st, num[2]);
StringBuilder SB = new StringBuilder();
foreach (char ch in st)
{
SB.Append(ChangeChar(ch, num));
}
return SB.ToString();
}
So when the user enters the correct password it will be stored in the user system and the next run it wont ask for the password.
public static void WriteFile(string FilePath, string Data)
{
FileStream fout = new FileStream(FilePath, FileMode.OpenOrCreate,
FileAccess.Write);
TripleDES tdes = new TripleDESCryptoServiceProvider();
CryptoStream cs = new CryptoStream(fout, tdes.CreateEncryptor(key, iv),
CryptoStreamMode.Write);
byte[] d = Encoding.ASCII.GetBytes(Data);
cs.Write(d, 0, d.Length);
cs.WriteByte(0);
cs.Close();
fout.Close();
}
So as you asked when the unique key generated , the user as to call you and read his code after based on the code you can generate the password as by above method .
But my point of view is different, this method is not good to collaborate with user. Its waste of time that user needs to call you for password. Better try some other method where user just need to click the link which makes project as full from trail. Anyway the above method will solve your question, I guess.
I suggest using an approach of symmetric or asymmetric encryption - that is direction you must look in to provide machine-based secret key generation. Look for its model in .NET.
Of course, if you want your application to be much more secured, you'll have to provide an activation server for it with client keyhashes database.