I need to pass secure information to an executable in my application. In other words I have the line:
Process.Start("someExecutable.exe","MyUsername, myPassword");
I want to prevent people from seeing those parameters. (The username and password are specified by the user at run time so I do not have to worry about those parameters).
Now a problem that I have now is: If someone replaces someExecutable.exe with their own program they will be able to see the credentials!
For future reference I refere to someExecutable.exe (program I am sending the credientials as arguments as ) A and I will refere to the executable created by this program as B
I will like to prevent that problem here are some solutions I have think of:
Compute the hash of A and check it before executing it.
static bool? VerifyThatExeIsReliable(string pathOfExe)
{
if (System.IO.File.Exists(pathOfExe) == false)
return null;
var bytes = System.IO.File.ReadAllBytes(pathOfExe);
using (SHA1Managed a = new SHA1Managed())
{
var hash = a.ComputeHash(bytes);
StringBuilder formatted = new StringBuilder(2 * hash.Length);
foreach (byte b in hash)
formatted.AppendFormat("{0:X2}", b);
var code = formatted.ToString();
if (code == "4835658749AF89A65C5F4835658749AF89A65C5F")
return true;
}
return false;
}
the problem with this approach is that the hash 4835658749AF89A65C5F4835658749AF89A65C5F will be stored in the executable A and if someone opens this program with a hex editor he is going to be able to find the hash and modify it. In other words they will calculate the sha1 hash of the program they write and place that hash instead of 4835658749AF89A65C5F4835658749AF89A65C5F
Use a the file Watcher class to detect when the file has been modified. If my program is not running I will not be able to detect this
make sure that the user is not able to see the command line arguments passed to that executable: See command line arguments being passed to a program
To solve the problems with option #1, Use asymmetric encryption on the hash, that way your program (and the user) will only be able to decrypt the hash, not encrypt a different one. Of course if they can edit compiled C# code then you can't stop them from altering it to not decrypt the hash, but that requires a lot more time and expertise.
To solve problem #2, store a hash of executable A in your program, and verify that executable A matches the hash before starting it.
As for #3, as far as I am aware there is no way to resolve the problem. However, if you are able to modify the target program you could send the username and password via an encrypted network socket, for example.
Note also that it is possible to reverse engineer .NET applications, and that you should possibly consider running some kind of obfuscation tool on your executable if security is important to you. Ultimately its not about making the program 100% tamper-proof, because that is impossible. Its about making it not worth the bother to anyone who would have a reason to do so.
Related
I'd like to generate (secure) local admin passwords based on computer names in our organisation. This way I can build a small UI that takes the computername and gives the password.
With PowerShell we will use the same DLL to generate the password and set it on each workstation.
I've already searched, but all the things I find about cryptography in C# is to hash a password, but I need the hash itself to be the password.
The password should also be of a length between 8 and 12 characters to make it easy enough to type it in.
I'm using .NET Core 2.0 (could use .NET Framework too if needed)
You definitely want to be able to change the passwords on your machines, so include some sort of date or counter in the formula.
You ideally also want to include some form of authentication into the tool, whether that be a master password, a complicated thing with smartcards, or something else. That way when your tool gets into the hands of a baddie they don't necessarily get all your data.
If you go the master password route, you need a plan for how to deal with suspecting that got leaked. (Including someone who knew it leaving the organization, since that's a leak.)
A strawman example which includes:
Using a date
Using a master password
Using HMAC to process the machine name, keyed by a key from the master password
An iteration count to PBKDF2 which matches modern computers.
.
private static string GeneratePassword(
string masterPassword,
string machineName,
DateTimeOffset lastChangeDate)
{
// Use the date (ignoring time) of the last password change as a salt.
byte[] salt = BitConverter.GetBytes(lastChangeDate.ToUniversalTime().Date.Ticks);
HashAlgorithmName prf = HashAlgorithmName.SHA256;
using (var pbkdf2 = new Rfc2898DeriveBytes(masterPassword, salt, 123456, prf))
{
byte[] key = pbkdf2.GetBytes(256 / 8);
using (HMAC hmac = new HMACSHA256(key))
{
byte[] value = hmac.ComputeHash(
Encoding.UTF8.GetBytes(machineName.ToUpperInvariant()));
// Or however long.
return Convert.ToBase64String(value).Substring(0, 16);
}
}
}
The Rfc2898DeriveBytes constructor overload which takes a HashAlgorithmName for the PBKDF2-PRF is new in netcoreapp20. If you are trying to be netstandard20 you can drop the last parameter and use the SHA-1-based version with probably little harm (since HMACSHA-1 isn't currently considered broken).
When going to change a password for a machine you'd enter the date of the last generation to get the existing one. Then enter today's date to get the new value, then write down the new date in whatever text file / spreadsheet / database / sticky note remembers these things.
Another alternative is generating random passwords and saving them in an encrypted structured file. Something like EnvelopedCms as the encryption container gives you smartcard for nearly free, and lets you add/remove readers without changing all the machine passwords (adding is easy, removing might warrant changing them all anyways).
Which is to say: Building a stable generator and deploying the usage is easy. It's maintaining it that gets tricky. Maintaining random might be easier, therefore it's possibly better to pay the cost up front.
I don't know if this is such a good idea - the tool only works as long as the passwords on each and every computer stay unchanged.
Anyway, you could hash the computer name and use the result as a password. Most if not all hashes produce larger hashes than 8-12 "easy enough to type in" characters, but you can solve that by:
Base64 encoding the hash (to get letters, numbers and a couple of other characters)
Take the desired number of characters from the result.
To make this a bit safer, let your UI take a password (a single one) and append it to the computer name before computing the hash. This way, when someone steals your tool, they still won't be able to generate valid passwords.
You won't ever be able to change that password, though. If you share it with a coworker, they will know how to reproduce every password, forever.
Previously I asked a question about combining SHA1+MD5 but after that I understand calculating SHA1 and then MD5 of a lagrge file is not that faster than SHA256.
In my case a 4.6 GB file takes about 10 mins with the default implementation SHA256 with (C# MONO) in a Linux system.
public static string GetChecksum(string file)
{
using (FileStream stream = File.OpenRead(file))
{
var sha = new SHA256Managed();
byte[] checksum = sha.ComputeHash(stream);
return BitConverter.ToString(checksum).Replace("-", String.Empty);
}
}
Then I read this topic and somehow change my code according what they said to :
public static string GetChecksumBuffered(Stream stream)
{
using (var bufferedStream = new BufferedStream(stream, 1024 * 32))
{
var sha = new SHA256Managed();
byte[] checksum = sha.ComputeHash(bufferedStream);
return BitConverter.ToString(checksum).Replace("-", String.Empty);
}
}
But It doesn't have such a affection and takes about 9 mins.
Then I try to test my file through sha256sum command in Linux for the same file and It takes about 28 secs and both the above code and Linux command give the same result !
Someone advised me to read about differences between Hash Code and Checksum and I reach to this topic that explains the differences.
My Questions are :
What causes such different between the above code and Linux sha256sum in time ?
What does the above code do ? (I mean is it the hash code calculation or checksum calculation? Because if you search about give a hash code of a file and checksum of a file in C#, they both reach to the above code.)
Is there any motivated attack against sha256sum even when SHA256 is collision resistant ?
How can I make my implementation as fast as sha256sum in C#?
public string SHA256CheckSum(string filePath)
{
using (SHA256 SHA256 = SHA256Managed.Create())
{
using (FileStream fileStream = File.OpenRead(filePath))
return Convert.ToBase64String(SHA256.ComputeHash(fileStream));
}
}
My best guess is that there's some additional buffering in the Mono implementation of the File.Read operation. Having recently looked into checksums on a large file, on a decent spec Windows machine you should expect roughly 6 seconds per Gb if all is running smoothly.
Oddly it has been reported in more than one benchmark test that SHA-512 is noticeably quicker than SHA-256 (see 3 below). One other possibility is that the problem is not in allocating the data, but in disposing of the bytes once read. You may be able to use TransformBlock (and TransformFinalBlock) on a single array rather than reading the stream in one big gulp—I have no idea if this will work, but it bears investigating.
The difference between hashcode and checksum is (nearly) semantics. They both calculate a shorter 'magic' number that is fairly unique to the data in the input, though if you have 4.6GB of input and 64B of output, 'fairly' is somewhat limited.
A checksum is not secure, and with a bit of work you can figure out the input from enough outputs, work backwards from output to input and do all sorts of insecure things.
A Cryptographic hash takes longer to calculate, but changing just one bit in the input will radically change the output and for a good hash (e.g. SHA-512) there's no known way of getting from output back to input.
MD5 is breakable: you can fabricate an input to produce any given output, if needed, on a PC. SHA-256 is (probably) still secure, but won't be in a few years time—if your project has a lifespan measured in decades, then assume you'll need to change it. SHA-512 has no known attacks and probably won't for quite a while, and since it's quicker than SHA-256 I'd recommend it anyway. Benchmarks show it takes about 3 times longer to calculate SHA-512 than MD5, so if your speed issue can be dealt with, it's the way to go.
No idea, beyond those mentioned above. You're doing it right.
For a bit of light reading, see Crypto.SE: SHA51 is faster than SHA256?
Edit in response to question in comment
The purpose of a checksum is to allow you to check if a file has changed between the time you originally wrote it, and the time you come to use it. It does this by producing a small value (512 bits in the case of SHA512) where every bit of the original file contributes at least something to the output value. The purpose of a hashcode is the same, with the addition that it is really, really difficult for anyone else to get the same output value by making carefully managed changes to the file.
The premise is that if the checksums are the same at the start and when you check it, then the files are the same, and if they're different the file has certainly changed. What you are doing above is feeding the file, in its entirety, through an algorithm that rolls, folds and spindles the bits it reads to produce the small value.
As an example: in the application I'm currently writing, I need to know if parts of a file of any size have changed. I split the file into 16K blocks, take the SHA-512 hash of each block, and store it in a separate database on another drive. When I come to see if the file has changed, I reproduce the hash for each block and compare it to the original. Since I'm using SHA-512, the chances of a changed file having the same hash are unimaginably small, so I can be confident of detecting changes in 100s of GB of data whilst only storing a few MB of hashes in my database. I'm copying the file at the same time as taking the hash, and the process is entirely disk-bound; it takes about 5 minutes to transfer a file to a USB drive, of which 10 seconds is probably related to hashing.
Lack of disk space to store hashes is a problem I can't solve in a post—buy a USB stick?
Way late to the party but seeing as none of the answers mentioned it, I wanted to point out:
SHA256Managed is an implementation of the System.Security.Cryptography.HashAlgorithm class, and all of the functionality related to the read operations are handled in the inherited code.
HashAlgorithm.ComputeHash(Stream) uses a fixed 4096 byte buffer to read data from a stream. As a result, you're not really going to see much difference using a BufferedStream for this call.
HashAlgorithm.ComputeHash(byte[]) operates on the entire byte array, but it resets the internal state after every call, so it can't be used to incrementally hash a buffered stream.
Your best bet would be to use a third party implementation that's optimized for your use case.
using (SHA256 SHA256 = SHA256Managed.Create())
{
using (FileStream fileStream = System.IO.File.OpenRead(filePath))
{
string result = "";
foreach (var hash in SHA256.ComputeHash(fileStream))
{
result += hash.ToString("x2");
}
return result;
}
}
For Reference: https://www.c-sharpcorner.com/article/how-to-convert-a-byte-array-to-a-string/
I spent 100s of hours researching this subject, and other senior programmer who coded the original project also could not make it work. I have an xml with a parameter of SignatureValue, Certificate (X509Certificate2) and Digest Value. The created and given Signature value stated in the same xml was made by converting concatinated fields (equal to Digest Value) into a hash (SHA1), then encrypted via private key. Private key is taken out of the certificate for privacy and I only have the Public key within. Now, no matter how I code around it, I always get a false value back (as in VerifyHash/verifyHashResult is false). Here is the code I am using:
// Need your help please.
static void VerifyHash(string sigVal , string digestVal, System.Security.Cryptography.X509Certificates.X509Certificate2 cert)
{
sigValInBytes = Convert.FromBase64String(sigVal);
try
{
using (RSACryptoServiceProvider rsaProviderDecrypt = (RSACryptoServiceProvider)cert.PublicKey.Key)
{
// Line below always return value of FALSE no matter how I code it. Here I want to verify the hashed freshly calculated digest value that is now hashed with the signature value
rsaProviderDecrypt.Decrypt(sigValInBytes, false);
rsaProviderDecrypt.Dispose();
}
}
}
// At the main program I get the certificate from the xml given and call the method above:
main
{
// Code below gets the certificate details from a given xml, details of each variable confirmed to be accurate.
char[] Base64_x509ByteArray;
Base64_x509ByteArray = t.DigitalSignatures.First().X509Data.ToCharArray();
byte[] x509ByteArray;
x509ByteArray = Convert.FromBase64CharArray(Base64_x509ByteArray, 0, Base64_x509ByteArray.Length);
// Here am creating the certificate from the gathered data/certificate:
System.Security.Cryptography.X509Certificates.X509Certificate2 cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(x509ByteArray);
VerifyHash(t.DigitalSignatures.FirstOrDefault().SignatureValue.Trim(), concatenatedFieldValues, cert);
}
Some shots in the dark:
Find the piece that is broken: Try doing the entire "encrypt / hash check" process in code without transfering anything over XML. If you can hash a string locally, and the hashes match, then the problem is in XML. Otherwise, the problem is in the cert or decryptor.
If the problem is on the cert / encryptor side, try hash matching with a local .NET cryptography class. If that fails, the problem is an encryption setting. Otherwise, it is the cert.
BIG shot in the dark: The call to Dispose right after the hash check. It shouldn't matter, but that caused an issue while I was decrypting using the Rijndael algorithm. Best guess was the optimizer was closing the stream early or something weird like that. Moving the constructor out of the using statement and manually calling Dispose after accessing the result fixed that "optimization".
Might try a reversable encryption algorithm. Rinjdael is native to .NET, and is reversable. Good for debug and proof of concept work. (Note: it uses Time as part of the salt, so RJ doesn't match hashes, it decrypts. So not good for passwords in Production environments.)
If the XML is the cause, check the encodings. Encryption is very sensitive to encodings, and XML serializers are finnicky beasts to begin with. The strings may look the same, but represented differently, or extra control characters added. Sql Server nvarchars are UCS-2, varchars are iso-8859-1, C# strings are utf-8, etc. Easy for encodings to mis-match, and an encoding change would easily cause this. Try converting the original value to utf-16 before inserting into the Xml, and set the Xml Declaration Encoding to utf-16. Just to be safe.
Note about NotePad: if you have opened the Xml in Notepad to take a quick look or edit, and saved it, there are probably extra "end of line" characters on your strings now. If you did the same in Word... oh my... Might want to try an original copy.
Failing that, try generating new encrypted values and see if they match.
I attemt to write a program, with which you can login to a remote website. For some people having multiple accounts, I try to make it easy for them and store account data in IsolatedStorage. At the current state of my code, the password is just entered in a TextBox and as soon as it's stored converted to a MD5 hash.
Now I'd like to refactor this to proper code, but I got stuck.
A PasswordBox exposes its data through PasswordBox.SecureString and PasswordBox.Password.
So when clicking my save button I'd perform something like
public void OnClick(...)
{
var password = passwordBox.Password;
// store it somehow (e.g. custom MD5 encryption)
var savePassword = passwordBox.SecureString;
// store this string somehow, but how?
}
Here my questions
As soon as I put the plain password from my PasswordBox into var password, is there something visible in memory? Would some hacker be able to make this plain value visible through reflection/debugging? Which code makes these strings actually visible? And what do I need to be aware of?
How to handle SecureString of the PasswordBox?
I'm a bit overwhelmed by all this stuff and I can't figure out the essence of how to handle passwords in an application properly, yet.
I'm not pleading for a whole solution and running code. I'd just be glad, if someone can get me started. And also, I don't want an enterprise solution. I'm just searching for one, which is easy to implement and as save as possible for the effort I put in.
Do you really need the password to be reversible?
A safer way to store it is to salt and hash it.
User: JOHN
Password: (starts out as) myUserPassword667!
Then use some sort of database unique code against the user in the DB. Lets say a GUID.
Now you have abcd-1234-12-1212121ab as the uniquifier for JOHN
so you now have a base password(before hashing)
myUserPassword667!abcd-1234-12-1212121ab
You can now Hash this with one of the SHA or other hashing algorithms in the System.Security namespace.
Now you internally have some Salt that you Apply to your hashing algorithm... (Part of your code only)
MySecretSaltWords559BC
then store the Result as either a Base64 or Binary in your DB.
Ab09l\311sas== (simplified)
Next time the user logs on you find their record in the DB, you get your Unique code that was used when you generated the account and attach to the password they entered.
Hash the entered password with the same technique and binary compare the result, then you don't need to ever store their password. If the hashes don't match you don't have the same password.
Using one of the C# implementations of BCrypt to hash passwords and store them into a SQL database. However when I return to validate against the hash string BCrypt generates a different hash than the one in the database to compare to. The salts are visibly the same as well as the factors.
Here is what I know
$2a$12$vF/1s3MqIzHwnDshyzH/rOYUelofrj4UWv./vzWqk4o2K0uwhix7W is actually "Qwerty123" and its stored in a column which is initialized to be [nvarchar] (200).
When I use the BCrypt.Verify() or BCrypt.CheckPassword() depending on the implementation, I trace it until just before it makes the comparison and the hash that it is about to compare to the before mentioned one is $2a$12$vF/1s3MqIzHwnDshyzH/rOKVRePZSXFXaIpDv6.IPkbPEoOxZgSEe
If you look close you can see that the salts and the factor parts are the same. Any idea what could be causing this?
The explicit implementation I am working with can be found here http://bcrypt.codeplex.com/
My question could be related to ASP.NET MVC 3 app, BCrypt.CheckPassword failing
Suggestion for testing
private void FindWhatsFailing(string password) //password = Whatever you're passing in to verify BCrypt is working
{
const string expectedpassword = "Qwerty123";
if(expectedpassword != password)
{
Debug.WriteLine("My password isn't what I thought it was");
return;
}
string hashed = BCrypt.HashPassword(expectedpassword , BCrypt.GenerateSalt(12));
if(!BCrypt.Verify(expectedpassword , hashed))
{
Debug.WriteLine("Something is wrong with BCrypt");
return;
}
/// ... Test hashing password, compare to hash of expectedpassword, verify password against hash of itself and expectedpassword
Debug.WriteLine("Everything worked, maybe the database storage is off?");
}
If the Bcrypt.Verify isn't working in this example for you, I have no idea what's wrong, but I'm guessing Bcrypt isn't actually the issue here.
The problem was the input to Bcrypt. I was using a Multiview and MultiViewPanels to collect user data(of which a password), allow user to verify all the data, then on the last MultiViewPanel add the user to the DB and in that process there were postbacks. After some research I found that password fields do not retain their text property after postbacks for security reasons and because I was passing txtPassword.text to Bcrypt this was the problem. This makes a new problem for me to look into.