We made a system for a school project and our professor told us not to have passwords stored in plain text in the database. She wants us to encrypt these passwords for security since our system will be handling a lot of confidential data. So we decided to use MD5 for making a hash of the passwords the problem is I don't really get how we would implement it in the login process.
Welcome to SO. I think there a post similar to yours has already been answered but I'll give you how I solved it.
private String encryptPassword(String password) throws NoSuchAlgorithmException{
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(password.getBytes());
byte[] digest = md.digest();
StringBuilder stringBuilder = new StringBuilder();
for (byte b : digest) {
stringBuilder.append(String.format("%02x", b & 0xff));
}
return stringBuilder.toString();
}
As you can see the method above that's how I encrypted the password which is a string passed through the parameters. MD5 is a one way encryption so there would be no way for you to decrypt it with Java but there are a few tools.
So what you should do is have the password converted when a user is registering(assuming you can add users in your system) then storing the converted value in the database as as string(varchar or text). Then when you want to login use the same method again then compare the result with whatever password is in the database. These generations aren't random so if you enter like "123" the generated hash will be the same everytime.
Related
I am trying to develop an android app in java which needs encryption. Also I want to use AES-256 for encryption. But when I look a tutorial of it, It always generates a random key. My question is: How can I decrypt a string if I encrypt it with a random key? Also I tried almost every code in web, but none of them worked, so can you provide a AES-256 encryption code with no salt and IV. If I know something wrong, please correct me and teach me the truth.
EDIT: I am trying to make a password manager app. App has two passwords, first one is the master password that we use for encryption string data. Second one is the passwords that we want to manage. Master password is stored in users mind. And other password will be stored in the app with encrypted version.
When user wants to see his passwords he will input his master key to decrypt the encrypted passwords. So how can I do it? And user's master password will be 32 or 64 digit and I don't think we need to generate a random key. Can you show me some way? I am not native english speaker, sorry for my bad english. Thanks for help.
As you have already discovered, a random key doesn't make sense for your app. Instead, you want to derive a key from the master password. To that end, you use a key derivation function or KDF.
In order to prevent dictionary attacks, you must also use a salt. A salt is a random value that you generate once and then store in your app (without any encryption).
Create salt
void initSalt()
{
byte[] salt = new byte[32];
new SecureRandom().nextBytes(salt);
... save salt ...
}
Get key for encryption
SecretKey getSecretKey(String masterPassword)
{
byte[] salt = ... retrieve saved salt ...
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
char[] chars = password.toCharArray();
int hashIterations = 1024;
int keySizeBytes = 32;
return keyFactory.generateSecret(
new PBEKeySpec(chars, salt, hashIterations, keySizeBytes * 8));
}
The getSecretKey() function is call both when the password manager is first setup as well as on any later use. The function will always return the same secret key if the salt doesn't change.
Some Android versions might not support PBKDF2WithHmacSHA256. If so, you have to revert to PBKDF2withHmacSHA1.
With the secret key generated from the master password, you can then go ahead an encrypt the data that the password manager wants to store.
I am trying to make a Java program that requires a password. The problem is that a Java class or JAR file can be converted back to source code, so people can see the password by converting the program back to source code. How can I fix this?
You can't.
Even if you encrypt the password, the code to decrypt the password will be available in, and so will not prevent someone decompiling your application.
You have some options:
Put your password in an environment variable (accessible with System.getProperty("variable.name"))
Store the password in a file (still not great, but better than sources)
Access the password from a server, however, you are still required to make the user enter their creds for the server, and now you're left with the same problem.
Make the user enter a password every time they run the application
Probably the best way is to protect the password is to use a one-way hash. I would recommend investigating the Secure Hash Algorithms (SHA). These are one-way hashes (aka cryptographic checksums) that generate, for all practical purposes, a unique hash for some given text or message. Store the hash in the JAR file and the use the same algorithm to hash the entered password. Compare that hash to the stored one for verification.
The down side to this is that it is not easy (or in some cases possible) to change the password.
The odds of generating identical hashes for different inputs is infinitesimal.
Here is one way it could be done using standard Java libraries.
MessageDigest md = MessageDigest.getInstance("SHA-256");
String password = "Password"; // password to be "stored"
byte[] bytes = password.getBytes();
md.update(bytes);
byte[] digest = md.digest();
// store the following string in the jar file
String storedDigest = toHex(digest);
// validation process
String enteredPassword = "Password";
md.update(enteredPassword.getBytes());
System.out.println(toHex(md.digest()).equals(storedDigest) ? "Passed"
: "Failed");
//Convert array of bytes to a long hex string
public static String toHex(byte[] digest) {
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(Integer.toHexString((b >> 4) & 0xF));
sb.append(Integer.toHexString(b & 0xF));
}
return sb.toString();
}
we use some Networkcredentials in out App. I just decompiled the app and was able to see the Credentials like Name and Password. I do not really get how to prevent this. I think the word "obfuscator" is the direction which I have to go.
We test proguard but it does not have string encryption or am I wrong?
Is there an easy and free way to do this?
Thank you.
Sorry, but this simply does't work no matter what you'll try. If you obfuscate / encrypt the credentials, the program still must be able to decrypt them at run-time. Therefore, the encryption keys must also be in the generated bytecode somewhere and therefore it's possible to take them, and decrypt the credentials manually outside the program (or just step through the program and read the credentials once they're decrypted).
What you're trying to do is Security by Obscurity and it doesn't work.
Whatever you do, if the program can obtain the credentials at run-time without any external help, a skilled attacker can do the same given enough time.
What you should do:
Store the credentials in plain-text in a property file. Don't bother with encryption, it's pointless. You must make sure the db user you're using is read-only or add-only or something similar so you prevent any damage.
Let the user input the password. If it's not stored in the bytecode, it's safe. He could e.g. input his password and have an account in the db...
Use a safe and known authentication mechanism. Plaintext login+password is not that.
Don't let your application go anywhere near a DB. Set up a service somewhere, with an API, which would hold the read DB conenction. Your application could connect to that and get data via this API. This way, an attacker can't directly access your DB. He could call anything in the new service, though, so you must make sure there's no sensitive data accessible in there.
You should consider to encipher the username and the password: How to encrypt String in Java.
// bytes to encrypt
byte[] input;
// the key and the initialization vector
byte[] keyBytes;
byte[] ivBytes;
// initialize the Cipher
SecretKeySpec key = new SecretKeySpec(keyBytes, "DES");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
// encryption
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] encrypted= new byte[cipher.getOutputSize(input.length)];
int enc_len = cipher.update(input, 0, input.length, encrypted, 0);
enc_len += cipher.doFinal(encrypted, enc_len);
// decryption
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
byte[] decrypted = new byte[cipher.getOutputSize(enc_len)];
int dec_len = cipher.update(encrypted, 0, enc_len, decrypted, 0);
dec_len += cipher.doFinal(decrypted, dec_len);
Usually, the key (bytes array) should be stored in a file that is only accessible on the specific instance where the server is running and not coded into the app source file.
Otherwise you can use hash (e.g: md5 or sha1) and store the fingerprint instead of the plain string:
// SHA1("hello world") -> "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
This is a simple method which allows you to calculate the SHA1 hash of a string:
public static String SHA1(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(text.getBytes("iso-8859-1"));
byte[] hash = md.digest();
Formatter formatter = new Formatter();
for (byte b : hash)
formatter.format("%02x", b);
return formatter.toString();
}
Import java.io.UnsupportedEncodingException, java.security.MessageDigest and java.security.NoSuchAlgorithmException are required.
Your issue is related to encryption and not obfuscation. You may use this library to store the credentials in an encrypted way: http://www.jasypt.org/encrypting-configuration.html
There are different ways to pass the encryption key to it.
Otherwise, depending on your context, consider using different authentication mechanisms (SSO like) instead of login/password.
i try to find the good way for the best technology/method for hidden password in a file, but without use external jar or library.
Actually i use one object that represent a list of user name and password. Convert my list in a xml (only in memory) and after that, i store in a file with AES.
Use only java 7, no external library.
Is a good/secure method?
If this operation is no good, is possible to create dynamically xml encrypted?
thanks
You can use a FileOutputStream wrapped in a CipherOutputStream.
It's not really secure to save passwords encrypted with AES because:
1) Where do you store the key? If you store it in the server, if an attacker violates the server and finds the key, he will have complete acces to the users information.
2) Do you really need to know the users' passwords? In many application, for security reasons, it's better to keep only the hash of the password. The username can be stored in plaintext and you can also add a salt to the password to enforce it. You can do that with some algorithms offered by Java7 platform. In this way, even if someone enters your server, he can't use users login informations without breaking the hash function.
Here's an example that worked for me:
public byte[] getHash(String password, byte[] salt, String algorithm) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest digest = MessageDigest.getInstance(algorithm);//The String rapresents the alg you want to use: for example "SHA-1" or "SHA-256"
digest.reset();
digest.update(salt);
return digest.digest(password.getBytes("UTF-8"));
}
You can also look at this link for a more complete example: https://www.owasp.org/index.php/Hashing_Java
I am storing passwords for my users as an encrypted string. If I open a user to edit in the admin console. The entire encrypted sting is not copied over and if I save the user, their password no longer works. I'm guessing the encryption is creating characters that interfere with the data viewer and say the field is ending before it really is. Is this a problem with app engine or should I be storing my passwords as a different type? If any other information is needed I will be happy to provide more details.
Below is the hashing method I use, this is directly saved into the data store.
public String getHash(String password, byte[] salt) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.reset();
md.update(salt);
return new String(md.digest(password.getBytes("UTF-8")));
}