I'm creating a simple web application and want to store hashed passwords into a database. I need the hash function for the authentication token too (concatenating the user name and the date and send them with their hash to the client as the token).
I've found that MessageDigest Java class can help me with this. Here is one link.
The basic idea goes like this:
public String digestString (String stringToHash) throws NoSuchAlgorithmException {
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
byte[] stringBytes = stringToHash.getBytes();
byte[] stringDigest = sha256.digest(stringBytes);
return new String(stringDigest);
}
What I don't get is:
In this code, how can I set the hash key? I need to be sure that the same key will be used in the verification process. How can I do that if I don't set the key?
BTW: I know I should add a salt (256 bytes in this case) to the hashed text before hashing it.
A hash uses no key. It's just a one-way algorithm. You give it something to digest, and it returns a hash. What it guarantees is that it's extremely hard to find the original input or any other input that leads to the same hash.
Your algorithm has two basic problems (besides the lack of salting):
it uses String.getBytes(), which relied on the default platform encoding, and thus differs from platform to platform. You should specify an encoding such as UTF-8.
it uses new String(byte[]), which has the same problem as above + an additional one: all the sequence of bytes are not valid character. To transform a purely binary byte array into a String, use a base64 encoding algorithm. apache commons codes has one.
Related
I'm creating a website on which each new user created (that's what I'm doing for now) will have a auth-key generated which is in Base64 encoding. The auth-key is important as almost all actions performed will require the auth-key of the user. The problem started when I read this article on Base64-Padding and created a few users with more or less the same unique-name (the encryption is done using the unique-name and LocalDateTime at which the user is created). I saw that the keys generated are all very similar to one-another. And then I went through a few more resources and found it is extremely easy to decode it.
Ever since I've been wondering what are the security flaws that I'm facing if I use Base64 encoding? How bad is it? How vulnerable the website will be etc.?
Apart from the above questions I want to know when should I be using Base64 encoding and when I should not? Also what should I use if not Base64?
Note: I'm generating auth-key in Java and the encryption is in AES.
Thank you.
In security, use of Base64 is not to encrypt a string you want to keep secret, it is used to encode it.
In Basic Authentication, for example, the intent of the encoding is to encode non-HTTP-compatible characters that may be in a user name, password, or token into those that are HTTP-compatible.
Encoding does not provide any confidentiality, for that you need to encrypt the string.
Think of the encryption as the security bit, and the encoding is the making string play nice with HTTP.
A common approach at generating a token is to first encrypt it, and then encode it.
As the first line of the article you gave tells :
Base64 is a group of similar binary-to-text encoding schemes that
represent binary data in an ASCII string format by translating it into
a radix-64 representation.
As Base64 encoding can be reversed very easily (it has been designed for this) it would be easily to break through your authentication. You shouldn't consider using Base64 encoding or any cipher encryption for your purpose but instead an hash algorithm like MD5, SHA or other because they are, theoretically, non-reversible and unique. Here is an example for MD5 :
public byte[] digestAuthKey(String login, Date d) {
MessageDigest md = MessageDigest.getInstance("MD5");
String key = login + SALT + d.getTime();
return md.digest(key.getBytes());
}
The SALT contant is a randomly generated string that enhanced the security making it harder to break.
To convert the byte array to string see this post
I am converting my password in Md5 , its working fine and giving me md5 converted password but i also want to have special characters in my md5 password.
how can i achieve this
public String createMd5(String password){
String salt = "Random$SaltValue#WithSpecialCharacters12#$#4&#%^$*";
String hash = md5(password + salt);
return hash;
}
public static String md5(String input) {
String md5 = null;
if(null == input) return null;
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(input.getBytes(), 0, input.length());
md5 = new BigInteger(1, digest.digest()).toString(32);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return md5;
}
md5() is a hash function that maps from any string to {0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f}^32.
You usually use it when you want to make sure that in case of a successful attack (this means the attacker could get your users data) the attacker does not have all users plaintext passwords (and hack e.g. their email accounds with this information).
You cannot get special characters out of md5() and it would not improve anything.
WARNING: MD5 should not be used anymore for hashing passwords as it is too fast to calculate (more information). Instead, you should use bcrypt with salt (example).
there is nothing like "md5 converted password" md5 generates checksum which you can not control.
I think this question stems from a misunderstanding of password hashing. Hashed passwords work like this:
A hash function is deterministic, that is, with the same input you always get the same output.
A good hash function is one-way, that is, you can't get from the hash value to the input without a lot of effort.
So take a password + salt (the salt makes creating an exhaustive dictionary MUCH harder)
Feed that into the hash function to generate a hash.
Store the hash and the salt.
To check passwords hash the user input and the stored salt and compare to the stored hash.
This operates on the byte level, so special characters are obviously included in the input. The output of the hash function is represented in hexadecimal for your convenience and does not contain special characters. If you do want the raw output just parse the hexadecimal representation into bytes but I don't see why you would want to, it's still the same number of output bits represented differently.
Another thing to note: MD5 is not a good hash function for passwords because it is much too fast. A really fast hash function is a hash function where trying a large amount of passwords from a generator is a trivial task. You might want to look for something more password specific for this use case.
I'm connecting lamp using JDBC and I have the word LondonWeight as a password hashed using MD5 on a MySQL database. I then need to check an inputted password against the collection, i.e LondonWeight to check to see if they match. However the hashing in my Java code returns a different output for the word.
MySQL hash:
1274d1c52d7a5a9125bd64f1f9a26dce
Java hash:
132310771724320562704545645352563257040366
Here's my hash code:
private String hashPass(String pass) throws NoSuchAlgorithmException {
MessageDigest mdEnc = MessageDigest.getInstance("MD5");
mdEnc.update(pass.getBytes(), 0, pass.length());
String md5 = new BigInteger(1, mdEnc.digest()).toString(8); // Encrypted
return md5;
}
It definitely hashes the String entered in the text box as I have it printed to the terminal so I can check. Any idea why it gives a different output? I understand there a different ways to hash the bytes or something?
You're currently converting the hash into octal in Java, whereas the MySQL version is in hex.
That's the first problem, but also:
Your MySQL hash appears to be 33 characters, which is too much data for an MD5 hash in hex. There's something odd going on there.
I wouldn't use BigInteger to convert a byte array into hex anyway; that's not what it's there for. Use Apache Commons Codec or something designed for hex conversion. For example, that way you'll get appropriate leading zeroes which BigInteger may suppress
Your current code assumes a single byte per character
Your current code assumes that the default character encoding is appropriate; I would suggest always specifying an encoding in String.getBytes
Using MD5 for password hashing is weak; update to a more appropriate hash if you possibly can
I am using a 3rd party platform to create a landing page, it is a business requirement that I use this particular platform.
On their page I can encrypt data and send it to my server through a request parameter when calling a resource on my site. This is done through an AES Symmetric Encryption.
I need to specify a password, salt (which must be a hex value) and an initialization vector (but be 16 characters).
Their backend is a .NET platform. I know this because if I specify an IV longer than it expects the underlying exception is:
System.Security.Cryptography.CryptographicException: Specified initialization vector (IV) does not match the block size for this algorithm.
Source: mscorlib
So for example, on their end I specify:
EncryptSymmetric("Hello World","AES","P4ssw0rD","00010203040506070809", "000102030405060708090A0B0C0D0E0F")
Where the inputs are: plain text, algorithm, pass phrase, salt, and IV respectively.
I get the value: eg/t9NIMnxmh412jTGCCeQ==
If I try and decrypt this on my end using the JCE or the BouncyCastle provider I get (same algo,pass phrase, salt & IV, with 1000 iterations): 2rrRdHwpKGRenw8HKG1dsA== which is completely different.
I have looked at many different Java examples online on how to decrypt AES. One such demo is the following: http://blogs.msdn.com/b/dotnetinterop/archive/2005/01/24/java-and-net-aes-crypto-interop.aspx
How can I decrypt a AES Symmetric Encryption that uses a pass phrase, salt and IV, which was generated by the .NET framework on a Java platform?
I don't necessarily need to be able to decrypt the contents of the encryption string if I can generate the same signature on the java side and compare (if it turns out what is really being generated here is a hash).
I'm using JDK 1.5 in production so I need to use 1.5 to do this.
As a side note, a lot of the example in Java need to specify an repetition count on the java side, but not on the .NET side. Is there a standard number of iterations I need to specify on the java side which matches the default .NET output.
It all depends on how the different parts/arguments of the encryption are used.
AES is used to encrypt bytes. So you need to convert the string to a byte array. So you need to know the encoding used to convert the string. (UTF7, UTF8, ...).
The key in AES has some fixed sizes. So you need to know, how to come from a passphrase to an AES key with the correct bitsize.
Since you provide both salt and IV, I suppose the salt is not the IV. There is no standard way to handle the Salt in .Net. As far as I remember a salt is mainly used to protect against rainbow tables and hashes. The need of a Salt in AES is unknown to me.
Maybe the passphrase is hashed (you did not provide the method for that) with the salt to get an AES key.
The IV is no secret. The easiest method is to prepend the encrypted data with the IV. Seen the length of the encrypted data, this is not the case.
I don't think your unfamiliarity of .Net is the problem here. You need to know what decisions the implementer of the encryption made, to come from your parameters to the encrypted string.
As far as I can see, it is the iteration count which is causing the issue. With all things the same (salt,IV,iterations), the .Net implementation generates the same output as the Java implementation. I think you may need to ask the 3rd party what iterations they are using
public static String encryptPassword( String password ) {
String encrypted = "";
try {
MessageDigest digest = MessageDigest.getInstance( "MD5" );
byte[] passwordBytes = password.getBytes( );
digest.reset( );
digest.update( passwordBytes );
byte[] message = digest.digest( );
StringBuffer hexString = new StringBuffer();
for ( int i=0; i < message.length; i++)
{
hexString.append( Integer.toHexString(
0xFF & message[ i ] ) );
}
encrypted = hexString.toString();
}
catch( Exception e ) { }
return encrypted;
}
I am using Java. I used this method for hashing the password and it correctly worked while storing into the database. Now I have difficulty with decryption. Are there any methods more effective than this one?
You can't decrypt it. MD5 is a hash - it's one way, unlike a two-way encryption algorithm.
You generally shouldn't be trying to decrypt passwords though - you store the hash (salted, ideally) and then compare the "known good" hash with the hash of the password given to you by the user later.
(I would avoid MD5 these days personally, but that's another story.)
MD5 is a hash function, i.e. a one-way function. It is not possible to "decrypt" an MD5 code.
While not useful for encryption applications, hash codes are typically used for the following applications:
password storage:When user initially registers, the password he provides is submited to the hash function and the resulting code is kept on file. When he/she tries to login, the credential he passes then are submited to the same hash function, and the code so produced is compared to the hash code kept on file. The interesting benefit of this approach is that even if someone has access to the list of hash codes corresponding to users' password, he/she is not able to know what the passwords are, because if the irreversibility of the hash function.
detecting changes in data recordsThe MD5 code provides a short code which can summarize the content of a whole record (with a relatively low probability but not impossibility that a different record content could have the same MD5 value); this code can then be use to detect if the record was modified without requiring access to the original record. This is used for fraud detection and also for quickly computing differential update sets for datasets which are updated on batch basis.
Providing keys for database indexingAgain because of the relatively short size of the MD5 compared to the original data, MD5 or other other hash codes provide a way of building relatively compact indexes for data which may be quite long.
If you must... [store passwords so they can be retrieved at a later time] and BTW, there are many use cases where doing so is necessary (for example to be supplied to 3rd party site to login on-behalf of your application's various users etc.)...
...you should use a encryption algorithm such as Blowfish, DES, AES and the like (I'm only mentioning symmetric key encryption here, for while public key encryption may be used as well, it doesn't appear this is what is needed here).
Be sure to read-up about encryption and cryptography at large, for it is relatively easy to implement encryption-decryption applications which are not very secure :-( Also remember that the algorithm is only one of the elements (typically the "easier" one) of the whole chain.