 |
|
 |
Hi,
thanks for this information.
first i have rewritten your code a bit and i got different execution times. Then i downloaded also your code and an my executions are similar then the once of my rewritten once. In your article you describe, that using "RNGCryptoServiceProvider and Character Masking" you have an execution time of: 00.40 sec. In all my tests this is the slowest one but yes it does not contain dublication even with 10 mio. generations 
here is a result set:
Total of: 999997, GenTime: 2406.3578 ms Total of: 131, GenTime: 2390.7321 ms Total of: 0, GenTime: 8094.1126 ms Done!
When i'm chaning the mask to: 1234567890 then its a bit faster:
Total of: 999997, GenTime: 2328.2293 ms Total of: 105, GenTime: 2312.6036 ms Total of: 999999, GenTime: 6547.1683 ms Done!
<big>UPDATE:</big> I done some additional researches and I found the following link: <a href="http://madskristensen.net/post/Generate-unique-strings-and-numbers-in-C.aspx">http://madskristensen.net/post/Generate-unique-strings-and-numbers-in-C.aspx</a>[<a href="http://madskristensen.net/post/Generate-unique-strings-and-numbers-in-C.aspx" target="_blank" title="New Window">^</a>]
private long GenerateId1() { byte[] buffer = Guid.NewGuid().ToByteArray(); return BitConverter.ToInt64(buffer, 0); }
private string GenerateId2() { long i = 1; foreach (byte b in Guid.NewGuid().ToByteArray()) { i *= ((int)b + 1); } return string.Format("{0:x}", i - DateTime.Now.Ticks); }
so i added both methods and here are the results:
Total of: 999997, GenTime: 2312.5296 ms Total of: 112, GenTime: 2312.5296 ms Total of: 999999, GenTime: 6500.0832 ms Total of: 0, GenTime: 1546.8948 ms -> GenerateId1 Total of: 0, GenTime: 3093.7896 ms -> GenerateId2 Done!
I should mention that I used GenerateId1().ToString() to receive an ID.
and here an additional result set with 10'000'000: Total of: 9999976, GenTime: 22937.7936 ms Total of: 11666, GenTime: 43500.5568 ms Total of: 9999999, GenTime: 65547.714 ms Total of: 0, GenTime: 23594.052 ms Total of: 0, GenTime: 62313.2976 ms Done!
regards, roni schuetz
modified on Tuesday, August 18, 2009 3:57 AM
|
|
|
|
 |
|
 |
In Cryptograph namespace, there are many other classes, for many uses, for example: Symmetric Algorithms, Asymmetric algorithms, NonKeyed Hashing algorithms, and Keyed Hashing algorithms.
|
|
|
|
 |
|
 |
I had a problem using the
Guid.NewGuid().ToString().GetHashCode().ToString("x");
and the
DateTime.Now.Ticks.ToString("x")
i kept it in a for loop of 10 and it gave me duplicates
so i knew it was useless,
but your method using the crypto is great.
Thanks again.
Regards
|
|
|
|
 |
|
|
 |
|
 |
thanks for youre helpful guide , thanks to anybody how writes code example an put it free to others 
|
|
|
|
 |
|
 |
Altaf Najvani
I tried to translate the CS Version of your uniqueKey Program, but some is lost in the translation. Was wondering if you could help me figure it out. I keep getting the a string back 8 times in a long string. Tried to link to you on Link website, but was not successful.
Dim maxSize As Integer = 8 Dim minSize As Integer = 5 Dim chars(61) As Char
Dim a As String a = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
chars = a.ToCharArray()
Dim size As Integer = maxSize Dim data(0) As Byte
Dim crypto As New RNGCryptoServiceProvider() crypto.GetNonZeroBytes(data) size = maxSize data = New Byte(size - 1) {} crypto.GetNonZeroBytes(data)
Dim result As New StringBuilder(size)
For Each b As Byte In data result.Append(chars) Next b
Return result.ToString()
|
|
|
|
 |
|
 |
JKIRKERX,
I found this to work with your translation :
For Each b As Byte In data result.Append(chars(b Mod (chars.Length - 1))) Next
Otherwise the loop is continuously adding the contents of chars.
|
|
|
|
 |
|
 |
That was a long time ago, I trying to remember if that was the unique key for software protection, or the unique key for payment procesing transactions. I ended up using this, that allows for up to 100,000 unique keys, but I know I need several million of them.
This program could use a boost to increase the amount of unique keys. I use it for SecureNet Transactions, because each transaction needs a unique key for submission. I didn't want to use the record index with identity seed, in case of accidental duplication.
Public Shared Function MakeUniqueKey2() As String
Dim maxSize As Integer = 8 Dim minSize As Integer = 5 Dim chars(61) As Char
Dim a As String a = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
chars = a.ToCharArray()
Dim size As Integer = maxSize Dim data(0) As Byte
Dim crypto As New RNGCryptoServiceProvider() crypto.GetNonZeroBytes(data) size = maxSize data = New Byte(size - 1) {} crypto.GetNonZeroBytes(data)
Dim result As New StringBuilder(size)
For Each b As Byte In data result.Append(chars) Next b
Return result.ToString()
End Function
|
|
|
|
 |
|
 |
Now I remember, I could not get the program to work, but wanted to use it. Thanks a million, for the help, I will try it out later today.
I ended up using this, not sure which is better
Dim UniqueID As String = Nothing UniqueID = DateTime.Now.ToString().GetHashCode().ToString("x")
|
|
|
|
 |
|
 |
What happen if I want to use just numbers? chars = New Char(9) {} a = "1234567890"
|
|
|
|
 |
|
 |
it will work! I m using it in my system !! there wil b collisions but not so much !! u can experiment it with little change in attached source code.
|
|
|
|
 |
|
 |
Thank you for a very nice and usefull article. 
|
|
|
|
 |
|
 |
A short and concise example is like an image. It's worth a thousand words. Thanks, Co.
|
|
|
|
 |
|
 |
It's really an amazing article. And it is going to help me in my project.
|
|
|
|
 |
|
 |
In your code i.e
private string GetUniqueKey() { int maxSize = 8 ; int minSize = 5 ; char[] chars = new char[62]; string a; a = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; chars = a.ToCharArray(); int size = maxSize ; byte[] data = new byte[1]; RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider(); crypto.GetNonZeroBytes(data) ; size = maxSize ; data = new byte[size]; crypto.GetNonZeroBytes(data); StringBuilder result = new StringBuilder(size) ; foreach(byte b in data ) { result.Append(chars1)>); } return result.ToString(); }
I am getting an error in the line"result.Append(chars1)>);" Can u point out d error. Please as i am finding your code very useful. If it works. Please help me out.
|
|
|
|
 |
|
 |
come on man.. take a look at the sources laziness will eventually get to you 
Co.
|
|
|
|
 |
|
 |
100,000 keys 0 dups
1,000,000 keys 0 dups
10,000,000 keys 0 dups
I ran each of these with 5 concurrent threads generating and adding keys to the same hashtable. Each test was executed 3 times.
w/ the speed that these are generated in it wouldn't be hard to grab a new one if it wasn't unique. I'm going to use this method for a file system data store to uniquely name the files. Granted I'll never even come close to having even 10,000 files under one directory so this solution is both efficient and effective for my needs.
|
|
|
|
 |
|
 |
private string GetUniqueKey() { int maxSize = 8 ; int minSize = 5 ; char[] chars = new char[62]; string a; a = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; chars = a.ToCharArray(); int size = maxSize ; byte[] data = new byte[1]; RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider(); crypto.GetNonZeroBytes(data) ; size = maxSize ; data = new byte[size]; crypto.GetNonZeroBytes(data); StringBuilder result = new StringBuilder(size) ; foreach(byte b in data ) { result.Append(chars1)>;); } return result.ToString(); }
i have to use it for my project.... wen i ran this code i got an error in the 'foreach' loop... the error is coming on the... result.append(chars1)>;); line..
please let me know wot the error is and how i can solve it....
thanks..
|
|
|
|
 |
|
 |
i have a gridview which is storing a record .i want to generate a unique no while saving one record.
the format should be like (pscode(2place),year(4place)and num(4place)) example:- 01-2007-0001
where ps_code is char(2), year comes form date-which is of date and time datattype and the last 4 place are char(4),
where ps_code and date are the field of my data base.i want retrive ps_code and year from my database to generate the unique number.
can tell me how will i do it? i am devloping a web applcation where the backend is vb.net2005.
|
|
|
|
 |
|
 |
I beleive that it would be a better approach with the collision with seeded values would make the collisions negligible.
|
|
|
|
 |
|
 |
I'm missing something here. Do you mean that it would be better to use a truncated SHA or MD5 hash? I'm certainly no mathmatician but I'm guessing that the number of collisions would increase dramatically by truncating all but the first 8 bytes. Since my mind struggles with things it can't visualize, somebody let me know if my statement is incorrect so I can revise my world a little.
|
|
|
|
 |
|
 |
Perhaps I made an error, but after generating 100,000 hashes from DateTime.Now I got 100,000 collisions on SHA1 and 99,999 with MD5 using only the first 8 characters. Here is the method, tell me if my method is flawed:
int coll = 0; List hashs = new List(); ; string hashed;
for (int i = 0; i < 100000; i++) { MD5CryptoServiceProvider crypto = new MD5CryptoServiceProvider(); byte[] buffer = ASCIIEncoding.ASCII.GetBytes(DateTime.Now.ToString());
byte[] hash = crypto.ComputeHash(buffer); hashed = hash.ToString().Substring(0, 8);
if (hashs.Contains(hashed)) coll++;
hashs.Add(hashed); }
And then I did the exact same thing with SHA1CryptoServiceProvider.
p.s. pardon the poor variable names and generall messiness, I did not spend much time on this.
|
|
|
|
 |
|
 |
This is more along the lines of what I would expect. It's not so much your code but your expectation. Unlike an encryption algorithm, a hash is designed to create the same number from the same data every time. Since you are making hashes from sequential data, the first part of the hash is going to be the same. Try the last 8 characters.
Even using the last eight, you will still get numerous collisions.
One more thing. The way .net works, a tight loop like that may be returning the same datetime value throughout the entire 99,000 iterations. Since .net likes to get ahead of itself, you could try throwing in a small delay.
SHA256, 384 & 512 are much stronger than MD5 in terms of encryption but we're not really encrypting; we're just trying to generate random unique id's.
As I recall, when you first started, you were using random numbers rather than timestamps. If you're going to use a hash, I would stick with the random numbers.
You could also consider using a key generation algorithm. This way, your invoices could be self-validating. Again, it's not really extreme security but it's kinda cool. That way, if somebody tried to guess an invoice number, they would have had to use a key generator with the same algorithm and password.
|
|
|
|
 |
|
 |
If you are using the key to protect sensitive data, this is a misapplication. Even casual crackers won't be put off by a 64 bit key. Inexpensive computers can easily handle the number of permutations required to create a collision. Just look at how long it took to generate 100,000 keys.
Sensitive data should be protected by a login system using strong passwords and encryption. AES, Blowfish, and Twofish seem to be the best. The database record itself can be linked to the login account so even if a cracker could create a collision, they still couldn't access the data.
On the other hand, if the objective is to create unique transaction ID's, it doesn't matter if they're sequential because they shouldn't be guarding the data. You could use a random increment value to leave "holes" in the sequence but even that wouldn't matter.
If you want something that looks more unique than '1234567' (the Spaceballs password), you can use a combination of a serial number, date, customer ID, time, random machine state, and a CRC (to validate). With a little work, this can be kept to 8 printable bytes. Also, consider using bit flags and different generation methods. For instance, bit 0 of byte 3 could indicate a different sequence to the bytes. The date and time are going to be the most unique portions of the key.
Another approach is to pre-compute sufficient unique keys to cover anticipated transactions. This way, you can eliminate collisions up front and identify anything that looks sequential. The assignment code simply picks an unassigned number from a database. You could even randomize that process if you wanted.
These are practical approaches to the problem that don't place undue expectations on the results. I'm sure there are thousands of coders and mathematicians that can come up with more unique and inventive approaches than this. My point is that there is a conflict in the basic premise: an 8 byte printable key code cannot provide significant data security no matter how random.
|
|
|
|
 |
|
 |
Thanks alot, Very good insight.
|
|
|
|
 |