Create a secure hash that hides an int value in C# - c#

I am trying to create a registration code for my C# 2.0 desktop application, which is a pay-per-use application. The registration code must hide an int value within it (the int value represents the number of uses for the application).
To generate the code from my machine, I have a separate application that uses Name, Random Number and the # of uses as the inputs.
For example:
Name: BOBSMITH
Random number: 51728
Number of Uses: 50
Concatenated String: BOBSMITH_51728_50
If I do a hash on the Concatenated String (for example an MD5 hash) I get a 32 hex string (I'll call it the Reg Code) similar to:
ABCD 1234 EFGH 5678 IJKL 9012 MNOP 3456
Now, on my users' side of things, when they are registering the application, I need to verify the Reg Code AND determine the # of uses from the Reg Code/Name/Random Number. So the user will enter these values:
Name: BOBSMITH
Random Number: 51728
Reg Code: ABCD 1234 EFGH 5678 IJKL 9012 MNOP 3456
My question: How can my application determine (based only on the Name, Random Number and Reg Code):
That the registration Code is correct
The # of uses that were initally given from my machine
One simple idea I have thought of is to generate a Hash based on only the Name and Random Number (let's call it code A) and then add the # of uses to this hash (code B). For example:
Code A: ABCD 1234 EFGH 5678 IJKL 9012 MNOP **1184**
Code B: ABCD 1234 EFGH 5678 IJKL 9012 MNOP **11B6**
If we subtract Code A from Code B, we get 50. Hence, my user would enter these values:
Name:BOBSMITH
Random Number: 51728
Reg Code: ABCD 1234 EFGH 5678 IJKL 9012 MNOP 11B6 (Code B)
To verify the Reg Code and # of uses (from the user side), my application would take the hash of Name & Random Number, which would give the same value as Code A. I would then subtract the Code A from the Reg Code that the user entered and see that the difference is 50. Hence, I would know to give the user 50 uses. This solution seems too insecure, however. I would appreciate anyone's suggestions.

TL;DR version: It's impossible. "Pay-per-use" and "desktop application" don't mix.
Is hiding the number actually the goal, or are you assuming that hiding it somehow helps prevent tampering? (Are you trying to not show the consumer how many uses they've paid for? Sounds dishonest.) You can verify that the value hasn't been tampered with by using a message authentication code, even when the number is stored in plain sight, since changes will invalidate the MAC.
This still won't solve your problem, however. It does you no good to protect the number of uses purchased if the user can tamper with the counter of how many have been used. In the simplest attack, the user can simply enter the same registration code onto a second computer, to double the number of uses. And this counter has to be incremented by the software running on the user's computer, so he necessarily possesses all the information needed to update it.
Even if you stored the counter on some secure central server under your control (which also removes the problem of protecting the allowed use count), you still can't prevent the user from patching out the part of the software that calls home. The only thing you can do is host the software in the cloud, so you can count the number of uses without the user cooperating.
See the #1 Law of Software Licensing.

The very definition of a secure hash disallows any possibility of getting a number back.
But that doesn't mean you can hash everything else, and then hide the number of in your hash code another way. You example of adding a number on the end of the hash can work, however if you do that I would also recommend you also compute a check sum from the resulting value and append it to the code to make tampering for difficult.

Hashes are one-way only, so you won't be able to get back anything you hash. Encryption is two-way so you will be able to get back anything you encrypt.
To prevent someone changing the encrypted number, you will need authentication as well. Either use AES-GCM (which includes authentication) or else either AES-CTR or AES-CBC (which don't include authentication) together with HMAC-SHA-256 for the authentication.
Computer security is not easy. A lot of the problems have been solved, but the solutions are not always simple. Apparently minor errors can cause major security holes.

Related

Generate password based on string in C#

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.

Perfect hash function to obfuscate a sequential value

Here is what I need (language: C# 4):
I am building a system where you can submit complaints. After complaint has been submitted you are given a unique 9 digits number that identifies your complaint in the system.
For security (security through obscurity) purposes I do not want ticket IDs to be sequential. But I do want to use database to generate sequential id.
So what I need is a injective function that is fast both ways: sequential number to my ticket id, and back from ticket id to the sequential number.
So that my ticketId in database is sequential, but before showing it to a user I will obfuscate it, similarly, when I get a number back from the user, I de-obfuscate it and use it to look up complaint in the database.
The obfuscation part does not need to be too complicated, just "not apparent enough" for general public.
For example I could simply change bitness of the value, which will get me (for 8-bit values):
0 -> 0
1 -> 128
2 -> 192
3 -> 64
4 -> 160
5 -> 96
etc.
I think you can solve this problem perfectly: Encrypt the ticket number with a constant key. There is a 32-bit block-size block cipher that you can use.
I would suggest something along the lines of symmetric encryption. For example, if you apply the substitution and diffusion steps of the DES encryption algorithm, you can get a number that can be quickly mapped back and forth but difficult to find a pattern. It is almost the same as your example but the S-Box and P-Box values are proved to be effective against cryptanalysis.
Why not just do something like this:
SHA1 your number, then store it in a table in your database along with your sequential number. Then when you receive the hash, just look up the sequential number in the database.
FYI, this is not really security. You should implement a real password system.

Generate serial number using letters and digits

I'm developing an application for taking orders in C# and DevExpress, and I need a function that generates a unique order number. The order number must contain letters and digits and has a length of 20 ..
I've seen things like Guid.NewGuid() but I don't want it to be totally random, nor to be just an auto increment number ..
Can anyone help? even if it's a script in a different language, I need ideas desperately :)
You can create type of your own .
lets say yyyyMMddWWW-YYY-XXXXXXX where WWW is the store number, YYY the cashier id XXXXXXX is a hexadecimal number ( -> maybe an actual autoincrement number that you turn it into hex ) . This is just an idea . Im afraid you have to decide by the elements of your system how it will be .
edited : also if you can apply a check digit algorithm on it will also help in avoiding mistakes
Two different methods:
Create MD5 or SHA1 hash of current time
Hash of increment number
One thought comes to mind.
Take the DateTime.Now.Ticks convert it to hexadecimal string.
Voila, String.Format("{0:X}", value);
If not long enough , you said you need 20 digits, you can always pad with zeros.
Get the mother board ID
Get the hdd ID
Merge it by any way
Add your secret code
Apply MD5
Apply Base54
Result: the serial code which is linked to the currect client PC :)
My two cents.
If you need ideas then take a look at the Luhn and Luhn mod N algorithms.
While these algorithms are not unique code generators, they may give you some ideas on how to generate codes that can be validated (such that you could validate the code for correctness before sending it off to the database).
Like Oded suggested, Guid is not random (well, not if you have a network card). It's based on time and location coordinates. See Raymond Chens blog post for a detailed explanation.
You are best off using an auto incremented int for order ids. I don't understand why you wouldn't want to use it or failing that a Guid?
I can't think of any way other then an auto id to maintain uniqueness and represent the order of your different orders in your system.

Optimum tempory password length for SHA hash

When creating a "forgotten password" mechanism, we might want to create a tempory password for the user which is stored using SHA1 (feel free to suggest other C# Cryptography mechanism).
How long should we make the tempory password? Too short, it could be brute forced. Too long and the unnecessary length is redundant since the string is hashed anyway? (Since a 20 character and 50 character string results in a hash of the same length anyway)
Update
Sorry if this was misleading. Sure we can pick a number out of the air, but I was wondering if there was a good mathematical reason to pick 13 rather than 12.
I think this is good advice regarding temp passwords:
The definitive guide to form-based website authentication
It talks about avoiding generating them in favour of getting to the real action the user wants.
I generally go with 10 characters. No particular reason for that, just something that I'd guess is above average length for a password chosen by a user.
Just by the fact that it's randomly generated, it'll probably be more secure and more difficult to brute force than anything chosen by your users. People pick stupid passwords such as myspace1, stackoverflow1, 12341234 etc.
If the password is in alphanumeric characters you only have about 6 bits of usable data per character and therefore you're wrong that there's no sense making a password longer than 20 characters.
It seems like you are worried about making the temporary password stronger than the user's password... when in reality, something like a 10-character base-64 (or similar - punctuation etc) is going to be very hard to crack and much stronger than the password the user will generate....
Make it a variable size as well (say 8-12 character) that will make it harder to brute force... if the attacker know you return an X character password all they have to do is try all passwords with N... assuming N is large it'll be impractical, but varying the size of N will at least make it that much harder for them.
Steve Gibson has created a "Ultra High Security Password Generator".
On that page he generates 3 different passwords on every page display:
64 random hexadecimal characters (0-9 and A-F)
63 random printable ASCII characters
63 random alpha-numeric characters (a-z, A-Z, 0-9)
He also explains the reasons behind this. It's a nice read. Hope this helps.
Go for whatever length your site specifies as recommended for the users. When generating a random string of base64 chars, I would sleep safely at night with 8-char password. But of course I'd limit login attempts to once every X second, and temporarily disable account after Y failed tries.
And remember to add a per-user unique salt before hashing, to thwart database-based attacks.

Address Match Key Algorithm

I have a list of addresses in two separate tables that are slightly off that I need to be able to match. For example, the same address can be entered in multiple ways:
110 Test St
110 Test St.
110 Test Street
Although simple, you can imagine the situation in more complex scenerios. I am trying to develop a simple algorithm that will be able to match the above addresses as a key.
For example. the key might be "11TEST" - first two of 110, first two of Test and first two of street variant. A full match key would also include first 5 of the zipcode as well so in the above example, the full key might look like "11TEST44680".
I am looking for ideas for an effective algorithm or resources I can look at for considerations when developing this. Any ideas can be pseudo code or in your language of choice.
We are only concerned with US addresses. In fact, we are only looking at addresses from 250 zip codes from Ohio and Michigan. We also do not have access to any postal software although would be open to ideas for cost effective solutions (it would essentially be a one time use). Please be mindful that this is an initial dump of data from a government source so suggestions of how users can clean it are helpful as I build out the application but I would love to have the best initial I possibly can by being able to match addresses as best as possible.
I'm working on a similar algorithm as we speak, it should handle addresses in Canada, USA, Mexico and the UK by the time I'm done. The problem I'm facing is that they're in our database in a 3 field plaintext format [whoever thought that was a good idea should be shot IMHO], so trying to handle rural routes, general deliveries, large volume receivers, multiple countries, province vs. state vs. county, postal codes vs. zip codes, spelling mistakes is no small or simple task.
Spelling mistakes alone was no small feat - especially when you get to countries that use French names - matching Saint, Sainte, St, Ste, Saints, Saintes, Sts, Stes, Grand, Grande, Grands, Grandes with or without period or hyphenation to the larger part of a name cause no end of performance issues - especially when St could mean saint or street and may or may not have been entered in the correct context (i.e. feminine vs. masculine). What if the address has largely been entered correctly but has an incorrect province or postal code?
One place to start your search is the Levenstein Distance Algorithm which I've found to be really useful for eliminating a large portion of spelling mistakes. After that, it's mostly a case of searching for keywords and comparing against a postal database.
I would be really interested in collaborating with anyone that is currently developing tools to do this, perhaps we can assist each other to a common solution. I'm already part of the way there and have overcome all the issues I've mentioned so far, having someone else working on the same problem would be really helpful to bounce ideas off.
Cheers -
[ben at afsinc dot ca]
If you would prefer tonot develop one and rather use an off-the-shelf product that uses many of the technologies mentioned here, see: http://www.melissadata.com/dqt/matchup-api.htm
Disclaimer: I had a role in its development and work for the company.
In the UK we would use:
House Name or Number (where name includes Flat number for apartment blocks)
Postcode
You should certainly be using the postcode, but in the US I believe your Zip codes cover very wide areas compared to postcodes in the UK. You would therefore need to use the street and city.
Your example wouldn't differentiate between 11 Test Street, 110 - 119 Test Street, etc.
If your company has access to an address lookup system, I would run all the data through that to get the data back in a consistent format, possibly with address keys that can be used for matching.
If I was to take a crack at this I'd convert each address string into a tree using a pre-defined order of operations.
Eg. 110 Test Street Apt 3. Anywhere California 90210 =>
Get the type of address. Eg Street addresses have different formats that rural route addresses and this is different by country.
Given that this is a street address, get the string that represents the type of street and convert that to an enum (eBoulevard, eRoad, etc..)
Given that this is a street address, pull out the street name (store in lower case)
Given that this is a street address, pull out the street number
Given that this is a street address, look for any apartment number (could be before the street number with a dash, could be after "Apt.", etc...)
eStreet //1.an enum of possible address types eg. eStreet, eRuralRoute,...
|
eStreet //2.an enum of street types eg. eStreet, eBlvd, eWay,...
/ | \
Name Number Apt
| | |
test 110 3
Eg. RR#3 Anywhere California 90210 =>
Get the type of address: rural route
Given that this is a rural route address, get the route number
eRuralRoute
|
3
You'll need to do something similar for country state and zip information.
Then compare the resulting trees.
This makes the comparison very simple, however, the code to generate the trees is very tricky. You'd want to test the crap out of it on thousands and thousands of addresses. Your problem is simpler if it is only US addresses you care about; British addresses as already mentioned are quite different, and Canadian address may have French in them (eg. Place D'Arms, Rue Laurent, etc...)
If it is cost-effective for your company to write its own address normalization tool then I'd suggest starting with the USPS address standard. Alternatively, there are any number of vendors offering server side tools and web services to normalize, correct and verify addresses.
My company uses AccuMail Gold for this purpose because it does a lot more than just standardize & correct the address. When we considered the cost of even one week's worth of salary to develop a tool in-house the choice to buy an off-the-shelf product was obvious.
If you dont chose to use an existing system, one idea is to do the following:
Extract numbers from the address line
replace common street words with blanks
create match string
ie: "555 Canal Street":
Extract number gives "555" + "Canal Street"
Replace street words gives "555" + "Canal"
Create match string gives "555Canal"
"Canal st 555" would give the same match string.
By street words i mean words and abbreviations for "street" in your language, for example "st", "st.", "blv", "ave", "avenue", etc etc all are removed from the string.
By extracting numbers and separating them from the string it does not matter if they are first or last.
use an identity for the primary key, this will always be unique and will make it easier to merge duplicates later.
force proper data entry with the user interface. Make them enter each component in its own text box. The house number is entered in own box, the street name in its own box, city in own box, state from select list, etc.. This will make looking for matches easier
have a two process "save"
after initial save, do a search to look up matches, present them with list of possible matches as well as the new one.
after they select the new one save it, if they pick an existing one use that ID
clean the data. Try to strip out "street", "st", "drive", etc and store it as a StreetType char(1) that uses a FK to a table containing the proper abbreviations, so you can build the street.
look into SOUNDEX and DIFFERENCE
I have worked at large companies that maintain mailinig lists, and they did not attempt to do it automatically, they used people to filter out the new from the dups because it is so hard to do. Plan for a merge feature so you can manually merge duplicates when they occur, and ripple the values through the PKs.
You might look into the google maps api and see if you can pass in you address and get a match back. I'm not familiar with it, this is just speculation.

Categories