I've been looking at this all day. I probably should have walked away from it hours ago; I might be missing something obvious at this point.
Short version: Is there a way to generate and boil down an asymmetrically encrypted hash to a reasonable number of unambiguous, human readable characters?
Long version:
I want to generate license keys for my software. I would like these keys to be of a reasonable length (25-36 characters) and easily read and entered by a human (so avoid ambiguous characters like the number 0 and the capital letter O).
Finally--and this seems to be the kicker--I'd really like to use asymmetric encryption to make it more difficult to generate new keys.
I've got the general approach: concatenate my information (user name, product version, a salt) into a string and generate a SHA1() hash from that, then encrypt the hash with my private key. On the client, build the SHA1() hash from the same information, then decrypt the license with the public key and see if I've got a match.
Since this is a Mac app, I looked at AquaticPrime, but that generates a relatively large license file rather than a string. I can work with that if I must, but as a user I really like the convenience of a license key that I can read and print.
I also looked at CocoaFob which does generate a key, but it is so long that I'd want to deliver it as a file anyway.
I fooled around with OpenSSL for a while but couldn't come up with anything of a reasonable length.
So...am I missing something obvious here? Is there a way to generate and boil down an asymmetrically encrypted hash to a reasonable number of unambiguous, human readable characters?
I'm open to buying a solution. But I work on a number of different of platforms, so I'd want something portable. Everything I've looked at so far has been platform specific.
Many, many thanks for a solution!
PS - Yes, I know it will still be cracked. I'm trying to come up with something reasonable that, as a user, I would still find friendly.
Unfortunately, no. If you make it shorter, you lose information and won't be able to recreate the original hash.
However, here's a couple things you may try:
Use base32. Map it to all the available letters in the alphabet that aren't ambiguous. (0vsO, etc.)
Use DSA, it tends to be more compact than RSA.
Making your input shorter (truncating the sha1 hash, or using md5 instead, for example) might make the output shorter, too.
Treat each SHA1 character as hex, perhaps drop any unnecessary formatting, (dashes or brackets), use some array mapping to convert 0-9A-F as say A-P in some random order, use that as your 'human' entered text. MD5 will give you your 32 chars or a few more for SHA1. Unmap the chars back to your SHA1/MD5 string/bytes and proceed from there.
I will not answer on the encryption part, but the thing I have started to do registration interfaces is to check the clipboard for text when the interface is raised. If text is present on the clipboard, scan it to see if the user has copied their registration information from somewhere (email, web page, etc.) and if you find information that could be your registration info/keys, pre-populate the registration interface with it.
It is also a good idea to show a small alert on the interface indicating that the info was successfully scraped from the clipboard (or not!) just so the user knows what did or did not happen.
The best signature based method to create short license keys currently seems to be the Boneh–Lynn–Shacham signature scheme, though it is rather recent (not so many reviews) and not implemented in common crypto tools.
Here is a way to do it with generic openssl and bash:
openssl ecparam -genkey -name sect113r1 -out private.key # generate the private key (store it on your server)
openssl ec hist-in private.key -pubout -out public.key # generate a public key (store it in the client software)
# generate a random one time activation userID or a hardware-based one here (CLIENT SIDE)
user_id="unique_on_the_fly_generated_user_ID" # send the user ID to the server for license generation
signature=""
return_value=0
while [[ $return_value == 0 ]]
do
signature=$(echo "$user_id" | openssl dgst -sign private.key | base64 > signature.txt) # generate a user licence
echo "$signature" | egrep -q 'O|l|/|\+|=' # check for ambiguous chars
return_value=$?
done
echo "$signature" | base64 -d > signature.txt # send the signature/license to the client
openssl dgst -verify public.key -signature signature.txt # verify signature (CLIENT SIDE)
Note that you still get a 48 characters long signature/licence key (plus a generic "M" header char you can avoid sending). As far as I know you can't generate shorter signatures with openssl at the moment.
I would consider the MD5 algorithm. It's widely implemented and will generate a 32 character alphanumeric string regardless of the input size. Apply the algorithm to your SHA1 hash and it may be what you're looking for.
Related
I have a string that was salted, hashed with SHA-256, then base64 encoded. Is there a way to decode this string back to its original value?
SHA-256 is a cryptographic (one-way) hash function, so there is no direct way to decode it. The entire purpose of a cryptographic hash function is that you can't undo it.
One thing you can do is a brute-force strategy, where you guess what was hashed, then hash it with the same function and see if it matches. Unless the hashed data is very easy to guess, it could take a long time though.
You may find the question "Difference between hashing a password and encrypting it" interesting.
It should be noted - Sha256 does not encrypt the data/content of your string, it instead generates a fixed size hash, using your input string as a seed.
This being the case - I could feed in the content of an encyclopedia, which would be easilly 100 mb in size of text, but the resulting string would still be 256 bits in size.
Its impossible for you to reverse the hash, to get that 100mb of data back out of the fixed size hash, the best you can do, is try to guess / compute the seed data, hash, and then see if the hash matches the hash your trying to break.
If you could reverse the hash, you would have the greatest form of compression to date.
SHA* is a hash function. It creates a representation (hash) of the original data. This hash is never intended to be used to recreate the original data. Thus it's not encryption. Rather the same hash function can be used at 2 different locations on the same original data to see if the same hash is produced. This method is commonly used for password verification.
You've done the correct thing by using a salt aka SSHA.
SHA and SHA-2 (or SHA-256) by itself without a salt are NOT considered secure anymore! Salting a SHA hash is called Salted SHA or SSHA.
Below is a simple example on how easily it is to de-hash SHA-1. The same can be done for SHA-2 without much effort as well.
Enter a password into this URL:
http://www.xorbin.com/tools/sha1-hash-calculator
Copy paste the hash into this URL:
https://hashes.com/en/decrypt/hash
Here's a page which de-hashes SHA-2. The way this pages works is somebody must have hashed your password before, otherwise it won't find it:
md5hashing dot net/hashing/sha256
Here's a page that claims to have complete SHA-2 tables available for download for a "donation" (I haven't tried it yet):
crackstation dot net/buy-crackstation-wordlist-password-cracking-dictionary.htm
Here's a good article that explains why you have to use SSHA over SHA:
crackstation dot net/hashing-security.htm
I'm using the DCPcrypt library in Delphi 2007 for encrypting text for an in-house app.
I'm currently using the following code (not my actual key):
Cipher := TDCP_rijndael.Create(nil);
try
Cipher.InitStr('5t#ck0v3rf10w', TDCP_md5);
Result := Cipher.EncryptString('Test string');
finally
Cipher.Burn;
Cipher.Free;
end;
The comment for InitStr is:
Do key setup based on a hash of the key string
Will exchanging the MD5 algorithm for, say, SHA2-256 or SHA2-512 make any theoretical or actual difference to the strength of the encryption?
The direct answer to your question is 'No' - it won't make any appreciable difference to cryptographic strength. Yes, MD5 is broken, but really it's weakness does not make any difference in this particular application. AES has key sizes of 128, 192 and 256 bits. All you are doing here is creating a string pseudonym for a key (being either 16 bytes, 24 bytes or 32 bytes). When cryptographic experts say that a hash function is broken, what they mean by this is that given a known hash output, it is feasible to compute a message different from the original message, which also hashes to the same output. In other words, in order for the cryptographic strength or weakness of the hash function to have any meaning, the binary key must already be known to the malicious party, which means that it is only relevant when your security is already completely defeated.
The strength of the hashing algorithm is COMPLETELY irrelevant to the strength of the asymmetric cipher.
However...
However, of a much more serious concern is the lack of salting in your code. Unless you plan to manually salt your message (unlikely), your communications are very vulnerable to replay attack. This will be infinity worse if you use ECB mode, but without salting, it is a major security issue for any mode. 'Salting' means injecting a sufficiently large non-predictable non-repeating value in either the IV or at the head of the message before encryption.
This highlights a huge problem with DCPCrypt. Most users of DCPcrypt will not know enough about cryptography to appreciate the importance of proper salting, and will use the crypto component in exactly the way you have. When you use DCPcrypt in this way (which is very natural), DCPcrypt does NOT salt. In fact, it sets the IV to zero. And it gets worse... If you have chosen a key-streaming type of chaining mode (which is very popular), and your IV is habitually zero, your security will be completely and utterly broken if a single plaintext message is known or guessed, (OR even just a fragment of the message is guessed). DCPcrypt does offer an alternative way to initialize a binary key (not from string), together with allowing the user to set the IV (you must generate a random IV yourself). The next problem is that the whole IV management gets a bit complicated.
Disclosure
I am the author of TurboPower LockBox 3. Dave Barton's DCPcrypt, an admirable and comprehensive engineering work, was one of my inspirations for writing LockBox 3.
You should specify the type of attack on your encryption; suppose known-plaintext attack is used, and intruder uses precomputed hash values to find key string - then there should be no difference between the hash algorithms used, any hash algorithm will require nearly the same time to find key string.
I'm looking for a RAIL way to create a very secure UID that will act as a authentication token.
I had been using UUID but was told they are not secure. I'd like to learn, what is the method of choice these days in ruby/rails 3?
This question is in no way Rails specific.
UUID is not secure for the simple fact that it is a unique identifier and it contains 'constant' parts of a given machine (e.g. it might use the MAC address for a machine), which makes it easier to guess.
If you want 100k+ strings without someone guessing one, you need to be able to distribute your keys across a large key-space. Let me explain:
If you only need 1 key (let's), you might pick 'A'. In a key-space of A-Z you have 1:26 chance of guessing it. Now, if you'd extend your key-space to A-Za-z you have a 1:52 chance of guessing.
Need more security still? Use a longer key: 'AA' 1:2704 chance.
Now, if you'd want to have 2000 keys and use a key length of 2 (e.g. 'AA'), there's a 2000:2704 => 1:1.352 chance someone might guess it. Pretty bad.
So, the key here is to pick a very long key size. With Digest::SHA1 you get 40-character keys (using Hex, with 16 different values per character). That's 1.46150164e48 unique values. Your 100k values should be random enough.
Edit:
With 40-digit HEX SHA1 values you have a 1:461501640000000000000000000000000000000000000000000 chance of guessing one. That takes ages.
I have a user model on my app, and my password field uses sha1. What i want is to, when i get the sha1 from the DB, to make it a string again. How do i do that?
You can't - SHA1 is a one-way hash. Given the output of SHA1(X), is not possible to retrieve X (at least, not without a brute force search or dictionary/rainbow table scan)
A very simple way of thinking about this is to imagine I give you a set of three-digit numbers to add up, and you tell me the final two digits of that sum. It's not possible from those two digits for me to work out exactly which numbers you started out with.
See also
Is it possible to reverse a sha1?
Decode sha1 string to normal string
Thought relating MD5, these other questions may also enlighten you:
Reversing an MD5 Hash
How can it be impossible to “decrypt” an MD5 hash?
You can't -- that's the point of SHA1, MDB5, etc. Most of those are one-way hashes for security. If it could be reversed, then anyone who gained access to your database could get all of the passwords. That would be bad.
Instead of dehashing your database, instead hash the password attempt and compare that to the hashed value in the database.
If you're talking about this from a practical viewpoint, just give up now and consider it impossible. Finding the original string is impossible (except by accident). Most of the point of a cryptographically secure hash is to ensure you can't find any other string that produces the same hash either.
If you're interested in research into secure hash algorithms: finding a string that will produce a given hash is called a "preimage". If you can manage to do so (with reasonable computational complexity) for SHA-1 you'll probably become reasonably famous among cryptanalysis researchers. The best "break" against SHA-1 that's currently known is a way to find two input strings that produce the same hash, but 1) it's computationally quite expensive (think in terms of a number of machines running 24/7 for months at a time to find one such pair), and does not work for an arbitrary hash value -- it finds one of a special class of input strings for which a matching pair is (relatively) easy to find.
SHA is a hashing algorithm. You can compare the hash of a user-supplied input with the stored hash, but you can't easily reverse the process (rebuild the original string from the stored hash).
Unless you choose to brute-force or use rainbow tables (both extremely slow when provided with a sufficiently long input).
You can't do that with SHA-1. But, given what you need to do, you can try using AES instead. AES allows encryption and decryption.
I need to encrypt a string (from a text area) that will also be decrypted later on when it is displayed.
I'm not to concerned about it being majorly secure, but just don’t want to store the data in plain text format.
Does anyone have any suggestions on how to do this easily in Rails?
There is a RubyGem named Crypt that provides a pure Ruby implementation of a number of encryption algorithms.
gem install encryptor
It wraps the standard Ruby OpenSSL library and allows you to use any of its algorithms.
http://github.com/shuber/encryptor
Is there a ROT13 implementation in Ruby/Rails (there must be...) that's totally insecure except to human readers (and idiot savants) so seems to fit your use case.
EDIT - This is a good start for swapping out characters:
$_.tr! "A-Za-z", "N-ZA-Mn-za-m";
It asks for user input then swaps the characters.
EDIT If you're not familiar, ROT13 assigns each letter its natural number. A=1, B=2, etc. Then it adds 13 to each number, effectively spinning it half way around the alphabet. The halfway bit is great, because unlike, say, ROT12, you can just run ROT13 again to decode. One function for both. OR you could run ROT12 13 times I guess (12 * 13 = 156. 156/26 = 6.) ROT 13 is better for this though.
If you're not concerned about security you can just base64-encode your string:
encoded = Base64::encode(string)
decoded = Base64::decode(encoded)
By the way it's also suitable for encoding binary data.
This isn't really encrypting as any developer may even guess that its Base64 encoded data.