Perfect hash function to obfuscate a sequential value - c#

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.

Related

Hash a string for duplicate detection

I'm writing a C# API which stored SWIFT messages types. I need to write a class that takes the entire string message and create a hash of it, store this hash in the database, so that when a new message is processed, it creates another hash, and checks this hash against ones in the database.
I have the following
public static byte[] GetHash(string inputString)
{
HashAlgorithm algorithm = MD5.Create(); // SHA1.Create()
return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
}
and I need to know, if this will do?
Global Comment*
So, I receive the files in a secure network, so we have full control over their validity - What I need to control is duplicate payments being made. I could split the record down into it's respective tag elemenents (SWFIT terminology) and then check them individually, but this then need to compare against records in the database, and the cost isn't something that can happen.
I need to check if the entire message is a duplicate of a message already processed, which is why i used this approach.
It depends on what you want to do. If you are expecting messages to never be intentionally tampered with, even CRC64 will do just fine.
If you want a .NET provided solution that is fast and provides no cryptographic security, MD5 is just fine and will work for what you need.
If you need to determine if a message is different from another, and you expect someone to tamper with the data in transit and it may potentially be modified with bit twiddling techniques to force a hash collision, you should use SHA-256 or SHA-512.
Collisions shouldn't be a problem unless you are hashing billions of messages or someone is tampering with the data in transit. If someone is tampering with the data in transit, you have bigger problems.
You could implement it the way that Dictionary implements it. The Bucket system.
Have a Hash value in the database, and store the raw data.
----------------
| Hash | Value |
----------------
By searching through the hashes first the query will be faster, and if there are multiple hits, as there at some point will be with MD5, you can just iterate through them, and match them more closely to see if they really are the same.
But as Michael J. Gray says, the probability of a collision is very small, on smaller datasets.

Create a secure hash that hides an int value in 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.

Coupon code generation

I would like to generate coupon codes , e.g. AYB4ZZ2. However, I would also like to be able to mark the used coupons and limit their global number, let's say N. The naive approach would be something like "generate N unique alphanumeric codes, put them into database and perform a db search on every coupon operation."
However, as far as I realize, we can also attempt to find a function MakeCoupon(n), which converts the given number into a coupon-like string with predefined length.
As far as I understand, MakeCoupon should fullfill the following requirements:
Be bijective. It's inverse MakeNumber(coupon) should be effectively computable.
Output for MakeCoupon(n) should be alphanumeric and should have small and constant length - so that it could be called human readable. E.g. SHA1 digest wouldn't pass this requirement.
Practical uniqueness. Results of MakeCoupon(n) for every natural n <= N should be totally unique or unique in the same terms as, for example, MD5 is unique (with the same extremely small collision probability).
(this one is tricky to define) It shouldn't be obvious how to enumerate all remaining coupons from a single coupon code - let's say MakeCoupon(n) and MakeCoupon(n + 1) should visually differ.
E.g. MakeCoupon(n), which simply outputs n padded with zeroes would fail this requirement, because 000001 and 000002 don't actually differ "visually".
Q:
Does any function or function generator, which fullfills the following requirements, exist? My search attempts only lead me to [CPAN] CouponCode, but it does not fullfill the requirement of the corresponding function being bijective.
Basically you can split your operation into to parts:
Somehow "encrypt" your initial number n, so that two consecutive numbers yield (very) different results
Construct your "human-readable" code from the result of step 1
For step 1 I'd suggest to use a simple block cipher (e.g. a Feistel cipher with a round function of your choice). See also this question.
Feistel ciphers work in several rounds. During each round, some round function is applied to one half of the input, the result is xored with the other half and the two halves are swapped. The nice thing about Feistel ciphers is that the round function hasn't to be two-way (the input to the round function is retained unmodified after each round, so the result of the round function can be reconstructed during decryption). Therefore you can choose whatever crazy operation(s) you like :). Also Feistel ciphers are symmetric, which fulfills your first requirement.
A short example in C#
const int BITCOUNT = 30;
const int BITMASK = (1 << BITCOUNT/2) - 1;
static uint roundFunction(uint number) {
return (((number ^ 47894) + 25) << 1) & BITMASK;
}
static uint crypt(uint number) {
uint left = number >> (BITCOUNT/2);
uint right = number & BITMASK;
for (int round = 0; round < 10; ++round) {
left = left ^ roundFunction(right);
uint temp = left; left = right; right = temp;
}
return left | (right << (BITCOUNT/2));
}
(Note that after the last round there is no swapping, in the code the swapping is simply undone in the construction of the result)
Apart from fulfilling your requirements 3 and 4 (the function is total, so for different inputs you get different outputs and the input is "totally scrambled" according to your informal definition) it is also it's own inverse (thus implicitely fulfilling requirement 1), i.e. crypt(crypt(x))==x for each x in the input domain (0..2^30-1 in this implementation). Also it's cheap in terms of performance requirements.
For step 2 just encode the result to some base of your choice. For instance, to encode a 30-bit number, you could use 6 "digits" of an alphabet of 32 characters (so you can encode 6*5=30 bits).
An example for this step in C#:
const string ALPHABET= "AG8FOLE2WVTCPY5ZH3NIUDBXSMQK7946";
static string couponCode(uint number) {
StringBuilder b = new StringBuilder();
for (int i=0; i<6; ++i) {
b.Append(ALPHABET[(int)number&((1 << 5)-1)]);
number = number >> 5;
}
return b.ToString();
}
static uint codeFromCoupon(string coupon) {
uint n = 0;
for (int i = 0; i < 6; ++i)
n = n | (((uint)ALPHABET.IndexOf(coupon[i])) << (5 * i));
return n;
}
For inputs 0 - 9 this yields the following coupon codes
0 => 5VZNKB
1 => HL766Z
2 => TMGSEY
3 => P28L4W
4 => EM5EWD
5 => WIACCZ
6 => 8DEPDA
7 => OQE33A
8 => 4SEQ5A
9 => AVAXS5
Note, that this approach has two different internal "secrets": First, the round function together with the number of rounds used and second, the alphabet you use for encoding the encyrpted result. But also note, that the shown implementation is in no way secure in a cryptographical sense!
Also note, that the shown function is a total bijective function, in the sense, that every possible 6-character code (with characters out of your alphabet) will yield a unique number. To prevent anyone from entering just some random code, you should define some kind of restictions on the input number. E.g. only issue coupons for the first 10.000 numbers. Then, the probability of some random coupon code to be valid would be 10000/2^30=0.00001 (it would require about 50000 attempts to find a correct coupon code). If you need more "security", you can just increase the bit size/coupon code length (see below).
EDIT: Change Coupon code length
Changing the length of the resulting coupon code requires some math: The first (encrypting) step only works on a bit string with even bit count (this is required for the Feistel cipher to work).
In the the second step, the number of bits that can be encoded using a given alphabet depends on the "size" of chosen alphabet and the length of the coupon code. This "entropy", given in bits, is, in general, not an integer number, far less an even integer number. For example:
A 5-digit code using a 30 character alphabet results in 30^5 possible codes which means ld(30^5)=24.53 bits/Coupon code.
For a four-digit code, there is a simple solution: Given a 32-Character alphabet you can encode *ld(32^4)=5*4=20* Bits. So you can just set the BITCOUNT to 20 and change the for loop in the second part of the code to run until 4 (instead of 6)
Generating a five-digit code is a bit trickier and somhow "weakens" the algorithm: You can set the BITCOUNT to 24 and just generate a 5-digit code from an alphabet of 30 characters (remove two characters from the ALPHABET string and let the for loop run until 5).
But this will not generate all possible 5-digit-codes: with 24 bits you can only get 16,777,216 possible values from the encryption stage, the 5 digit codes could encode 24,300,000 possible numbers, so some possible codes will never be generated. More specifically, the last position of the code will never contain some characters of the alphabet. This can be seen as a drawback, because it narrows down the set of valid codes in an obvious way.
When decoding a coupon code, you'll first have to run the codeFromCoupon function and then check, if bit 25 of the result is set. This would mark an invalid code that you can immediately reject. Note that, in practise, this might even be an advantage, since it allows a quick check (e.g. on the client side) of the validity of a code without giving away all internals of the algorithm.
If bit 25 is not set you'll call the crypt function and get the original number.
Though I may get docked for this answer I feel like I need to respond - I really hope that you hear what I'm saying as it comes from a lot of painful experience.
While this task is very academically challenging, and software engineers tend to challenge their intelect vs. solving problems, I need to provide you with some direction on this if I may. There is no retail store in the world, that has any kind of success anyway, that doesn't keep very good track of each and every entity that is generated; from each piece of inventory to every single coupon or gift card they send out those doors. It's just not being a good steward if you are, because it's not if people are going to cheat you, it's when, and so if you have every possible item in your arsenal you'll be ready.
Now, let's talk about the process by which the coupon is used in your scenario.
When the customer redeems the coupon there is going to be some kind of POS system in front right? And that may even be an online business where they are then able to just enter their coupon code vs. a register where the cashier scans a barcode right (I'm assuming that's what we're dealing with here)? And so now, as the vendor, you're saying that if you have a valid coupon code I'm going to give you some kind of discount and because our goal was to generate coupon codes that were reversable we don't need a database to verify that code, we can just reverse it right! I mean it's just math right? Well, yes and no.
Yes, you're right, it's just math. In fact, that's also the problem because so is cracking SSL. But, I'm going to assume that we all realize the math used in SSL is just a bit more complex than anything used here and the key is substantially larger.
It does not behoove you, nor is it wise for you to try and come up with some kind of scheme that you're just sure nobody cares enough to break, especially when it comes to money. You are making your life very difficult trying to solve a problem you really shouldn't be trying to solve because you need to be protecting yourself from those using the coupon codes.
Therefore, this problem is unnecessarily complicated and could be solved like this.
// insert a record into the database for the coupon
// thus generating an auto-incrementing key
var id = [some code to insert into database and get back the key]
// base64 encode the resulting key value
var couponCode = Convert.ToBase64String(id);
// truncate the coupon code if you like
// update the database with the coupon code
Create a coupon table that has an auto-incrementing key.
Insert into that table and get the auto-incrementing key back.
Base64 encode that id into a coupon code.
Truncate that string if you want.
Store that string back in the database with the coupon just inserted.
What you want is called Format-preserving encryption.
Without loss of generality, by encoding in base 36 we can assume that we are talking about integers in 0..M-1 rather than strings of symbols. M should probably be a power of 2.
After choosing a secret key and specifying M, FPE gives you a pseudo-random permutation of 0..M-1 encrypt along with its inverse decrypt.
string GenerateCoupon(int n) {
Debug.Assert(0 <= n && n < N);
return Base36.Encode(encrypt(n));
}
boolean IsCoupon(string code) {
return decrypt(Base36.Decode(code)) < N;
}
If your FPE is secure, this scheme is secure: no attacker can generate other coupon codes with probability higher than O(N/M) given knowledge of arbitrarily many coupons, even if he manages to guess the number associated with each coupon that he knows.
This is still a relatively new field, so there are few implementations of such encryption schemes. This crypto.SE question only mentions Botan, a C++ library with Perl/Python bindings, but not C#.
Word of caution: in addition to the fact that there are no well-accepted standards for FPE yet, you must consider the possibility of a bug in the implementation. If there is a lot of money on the line, you need to weigh that risk against the relatively small benefit of avoiding a database.
You can use a base-36 number system. Assume that you want 6 characters in the coupen output.
pseudo code for MakeCoupon
MakeCoupon(n)
{
Have an byte array of fixed size, say 6. Initialize all the values to 0.
convert the number to base - 36 and store the 'digits' in an array
(using integer division and mod operations)
Now, for each 'digit' find the corresponding ascii code assuming the
digits to start from 0..9,A..Z
With this convension output six digits as a string.
}
Now the calculating the number back is the reverse of this operation.
This would work with very large numbers (35^6) with 6 allowed characters.
Choose a cryptographic function c. There are a few requirements on c, but for now let us take SHA1.
choose a secret key k.
Your coupon code generating function could be, for number n:
concatenate n and k as "n"+"k" (this is known as salting in password management)
compute c("n"+"k")
the result of SHA1 is 160bits, encode them (for instance with base64) as an ASCII string
if the result is too long (as you said it is the case for SHA1), truncate it to keep only the first 10 letters and name this string s
your coupon code is printf "%09d%s" n s, i.e. the concatenation of zero-padded n and the truncated hash s.
Yes, it is trivial to guess n the number of the coupon code (but see below). But it is hard to generate another valid code.
Your requirements are satisfied:
To compute the reverse function, just read the first 9 digits of the code
The length is always 19 (9 digits of n, plus 10 letters of hash)
It is unique, since the first 9 digits are unique. The last 10 chars are too, with high probability.
It is not obvious how to generate the hash, even if one guesses that you used SHA1.
Some comments:
If you're worried that reading n is too obvious, you can obfuscate it lightly, like base64 encoding, and alternating in the code the characters of n and s.
I am assuming that you won't need more than a billion codes, thus the printing of n on 9 digits, but you can of course adjust the parameters 9 and 10 to your desired coupon code length.
SHA1 is just an option, you could use another cryptographic function like private key encryption, but you need to check that this function remains strong when truncated and when the clear text is provided.
This is not optimal in code length, but has the advantage of simplicity and widely available libraries.

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.

Categories