Read Encrypted Password in Java - java

I have the following code in javascript / nodejs that encrypt passwords. I need to read these passwords in java:
encryptPassword: function(password, salt) {
var salt = new Buffer(salt, 'base64');
return crypto.pbkdf2Sync(password, salt, 10000, 64).toString('base64');
}
I Used this method to create encrypted password for testing. this is the result (as java variables):
static String password = "123456";
static String salt = "CPvFo+klD9Vh2iE07JEGXA==";
public final String encrypted = "LtStqkNQjrr+P4V8fGtnauNJNOIB7t35O5I4a4/I9lFUnMR3ckbZyT85g/wO0Da9318Wrql/y1bsY2XdpXqx+Q==";
I tried to tranalte the encryption code above to java, using this http://www.javacodegeeks.com/2012/05/secure-password-storage-donts-dos-and.html :
public static byte[] getEncryptedPassword(String password, byte[] salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
String algorithm = "PBKDF2WithHmacSHA1";
int derivedKeyLength = 64;
int iterations = 10000;
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, derivedKeyLength);
SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm);
return f.generateSecret(spec).getEncoded();
}
Finally, I used apache codecs to set the 64 based string:
public static String getEncryptedPassword(String password, String salt) throws NoSuchAlgorithmException, InvalidKeySpecException
{
byte[] bytes = Base64.decodeBase64(salt);
byte[] encryptedPassword = getEncryptedPassword(password, bytes);
return Base64.encodeBase64String(encryptedPassword);
}
The tester is this:
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {
System.out.println(encrypted);
System.out.println(getEncryptedPassword(password, salt));
}
And the output is
LtStqkNQjrr+P4V8fGtnauNJNOIB7t35O5I4a4/I9lFUnMR3ckbZyT85g/wO0Da9318Wrql/y1bsY2XdpXqx+Q==
LtStqkNQjro=
As you can see, the java code produce something that is pretty much a prefix of the encryped password produced by the javascript.
I tested this on different complicated passwords, and got the same result: a string that is a prefix of the javascript encrypted password. Different passwords are not a prefix of each other.
Therefore, I think I am pretty much close. But I can't figure out what is missing.

Related

How do I compare salt with a generated password?

So I'm trying to compare my original password to a password that was salted. I know how to compare a hash password, I take the original password add hash to it and it works. However, I don't know how to compare the salt.
public static String saltPassword(String password) throws NoSuchAlgorithmException{
String salt = getSalt();
return password + salt;
}
public static String getSalt(){
Random r = new SecureRandom();
byte[] saltBytes = new byte[32];
r.nextBytes(saltBytes);
return Base64.getEncoder().encodeToString(saltBytes);
}
What do I have to do to compare the original password with this?
this is literally what my assignment says,
"Compare the generated password with the stored salt and hashed password".
You should also store the salt. Salt is used to prevenet generating the same hashed password when two user choose same password. something like the following codes can be used for saving password as hashedPassord and verifying entered password.It's not complete but can be used as a sample code.
private static void savePassword(String rawPassword) throws InvalidKeySpecException, NoSuchAlgorithmException {
byte[] salt = getSalt();
String hashedPassword = getHashedPassword(rawPassword, salt);
String encodedSalt = base64Encode(salt);
/* todo: store hashPassword and encodedSalt */
}
private static boolean verifyPassword(String rawPassword, String hashedPassword, String encodedSalt) throws InvalidKeySpecException, NoSuchAlgorithmException {
return Objects.equals(hashedPassword, getHashedPassword(rawPassword, base64Decode(encodedSalt)));
}
private static String getHashedPassword(String rawPassword, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeySpec spec = new PBEKeySpec(rawPassword.toCharArray(), salt, 65536, 128);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] hash = factory.generateSecret(spec).getEncoded();
return base64Encode(hash);
}
private static byte[] getSalt() {
Random r = new SecureRandom();
byte[] saltBytes = new byte[32];
r.nextBytes(saltBytes);
return saltBytes;
}
private static String base64Encode(byte[] src) {
return Base64.getEncoder().encodeToString(src);
}
private static byte[] base64Decode(String src) {
return Base64.getDecoder().decode(src);
}
Ok here is what i have. I would love to look up a stored password but my teacher is not doing it that way in her solution video
public static String saltPassword(String password) throws NoSuchAlgorithmException{
String salt = getSalt();
return hashPassword(password + salt);
}
public static String getSalt(){
Random r = new SecureRandom();
byte[] saltBytes = new byte[32];
r.nextBytes(saltBytes);
return Base64.getEncoder().encodeToString(saltBytes);
}
public static String generatePassword(){
String charSet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-+!##$%";
String password = "";
int start = 0;
int stop = 0;
int minLength = 8;
for (int i = 0; i <= minLength; i++) {
// get a random character from the chars string
start = getRandomNumber(charSet.length());
stop = start + 1;
password += charSet.substring(start, stop);
}
return password;
}
private static int getRandomNumber(int maxValue){
double randomNumber;
randomNumber = Math.floor(Math.random() * maxValue);
return (int)randomNumber;
}
public static String hashPassword(String password)throws NoSuchAlgorithmException{
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(password.getBytes());
byte[] mdArray = md.digest();
StringBuilder sb = new StringBuilder(mdArray.length * 2);
for (byte b : mdArray){
int v = b & 0xff;
if(v < 16){
sb.append('0');
}
sb.append(Integer.toHexString(v));
}
return sb.toString();
}
Then to create it I am going to go
String newPassword = PasswordUtil.generatePassword();
String hashedPassword = "";
String saltedPassword = "";
try{
hashedPassword = PasswordUtil.hashPassword(newPassword);
}
catch(NoSuchAlgorithmException e){
System.out.println();
}
try{
saltedPassword = PasswordUtil.saltPassword(hashedPassword);
}
catch(NoSuchAlgorithmException e) {
System.out.println();
}
What happens next?
this is the hashed password:
50f99d2a635cc9bac7e001506789b55a7c603d93c89d362cc5d95ab257fc2666
and this is the hash with the salt
e954fbc2309cc359cd603effb6d0644947a3253110ad6c3b2416dd49168331a3
How do I compare salt with a generated password?
What do I have to do to compare the original password with this?
The answer is that you don't do either if these things.
To register the original password you do the following:
Obtain a salt1
Combine the original password with the salt
Hash that.
Store the salt and the hash.
You then discard the original password.
To check that a supplied password you do the following:
Lookup the stored hash and the corresponding salt that were created when registering; see above.
Combine the supplied password and salt in the same way as above.
Hash that as above.
Compare the resulting hash with the stored hash. If they are the same, then the supplied password is the correct password.
As you can see, you don't compare either the salt or the original password with anything.
But it is also essential that you use the same salt when generating the hashes for the original password and the password that you are checking. If you don't, the password check doesn't work.
1 - The salt is just a number or string. Ideally the salt values should be different. The purpose of the salt is to avoid a so-called "rainbow table" attack to recover the original password from a stolen (un-salted) password hash. If there are (say) a million possible salt values, then the bad guys need to generate a million different rainbow tables. Generating and storing many rainbow tables becomes impractical.

How to specify HMAC key as hexadecimal in Java

I'm able to successfully get a HMAC SHA256 using the following code:
public static String getHac(String dataUno, String keyUno) throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
SecretKey secretKey = null;
Mac mac = Mac.getInstance("HMACSHA256");
byte[] keyBytes = keyUno.getBytes("UTF-8");
secretKey = new SecretKeySpec(keyBytes,mac.getAlgorithm());
mac.init(secretKey);
byte[] text = dataUno.getBytes("UTF-8");
System.out.println("Hex encode: " + Hex.encode(keyUno.getBytes()));
byte[] encodedText = mac.doFinal(text);
return new String(Base64.encode(encodedText)).trim();
}
which yields:
HMAC: 9rH0svSCPHdbc6qUhco+nlkt2O7HE0rThV4M9Hbv5aY=
However, i would like getting this:
HMAC:eVXBY4RZmFQcOHHZ5FMRjDLOJ8vCuVGTjy7cHN7pqfo=
I tried an online tool and it appears that the difference between my code and online tool is that I am working with a text in the key type.
Test values:
String data = "5515071604000fAIkwJtkeiA:APA91bH_Pb5xB2lrmKWUst5xRuJ3joVE-sb9KoT0zXZuupIEfdHjii-cODj-JMnjyy7hFJUbIRAre9o2yaCU43KaFDmxKlhJhE36Dw0bZ2VntDUn_Zd1EJBuSyCYiUtmmkHfRvRy3hIb";
String key = "fc67bb2ee0648a72317dcc42f232fc24f3964a9ebac0dfab6cf47521e121dc6e";
getHac("5515071604000fAIkwJtkeiA:APA91bH_Pb5xB2lrmKWUst5xRuJ3joVE-sb9KoT0zXZuupIEfdHjii-cODj-JMnjyy7hFJUbIRAre9o2yaCU43KaFDmxKlhJhE36Dw0bZ2VntDUn_Zd1EJBuSyCYiUtmmkHfRvRy3hIb", "fc67bb2ee0648a72317dcc42f232fc24f3964a9ebac0dfab6cf47521e121dc6e"));
the execution of my method return
9rH0svSCPHdbc6qUhco+nlkt2O7HE0rThV4M9Hbv5aY=
(the online returns the same value with key type text selected)
and i expected
eVXBY4RZmFQcOHHZ5FMRjDLOJ8vCuVGTjy7cHN7pqfo=
(the online returns the same value with key type hex selected)
Assuming that you are using Apache Commons Codec 1.11, use the following:
byte[] keyBytes = Hex.decodeHex(keyUno);
getHac Method
You code just slightly modified looks like this then:
public static String getHac(String dataUno, String keyUno)
throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException, DecoderException {
SecretKey secretKey;
Mac mac = Mac.getInstance("HMACSHA256");
byte[] keyBytes = Hex.decodeHex(keyUno);
secretKey = new SecretKeySpec(keyBytes, mac.getAlgorithm());
mac.init(secretKey);
byte[] text = dataUno.getBytes("UTF-8");
byte[] encodedText = mac.doFinal(text);
return new String(Base64.encodeBase64(encodedText)).trim();
}
Test
This Java method gives then expected result:
eVXBY4RZmFQcOHHZ5FMRjDLOJ8vCuVGTjy7cHN7pqfo=

Hashing vulnerability

I want to add some security to my project so I added a password field. In, order to store the password I was going to use a txt and save it in there, to add a bit more security I used the below code to hash the password(theirs more than one password saved this way if that's important). This is just and example of how I have done the hashing, the actual program uses text files etc.
public static void main(String[] args) throws NoSuchAlgorithmException {
System.out.println("Enter Password: ");
Scanner scanner = new Scanner(System.in);
String enteredPassword = scanner.nextLine();
String storedPassword = "�D�Ϛ-�UK�c�=�,�}��}��D��Zj>�m";
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(enteredPassword.getBytes());
String hashedString = new String(messageDigest.digest());
System.out.println(hashedString);
if(storedPassword.equals(hashedString)){
System.out.println("Passwords Match!");
}else{
System.out.println("Passwords Do Not Match!");
}
}
My question is am I doing this securely, besides decompiling my project and bypassing this feature is my project secure or can this method be exploited? Also, is there a way to secure a project against being decompiled and the code re-written to bypass security features?? Thank You
The approach itself is good; SHA-256 by itself is a strong, one-way hashing function. It cannot be "decrypted". But it's fast, thus allowing rapid brute-forcing of the password using a dictionary.
For better security you can slow things down with e.g. bcrypt or PBKDF2. Some 100ms will not be noticeable by the user, but makes brute-forcing impractical.
Here's an example with PBKDF2 using 100000 iterations of SHA-256. It also uses a random salt.
SecureRandom random = SecureRandom.getInstanceStrong();
byte[] salt = new byte[16];
random.nextBytes(salt);
KeySpec spec = new PBEKeySpec("my-secret-password".toCharArray(), salt, 100000, 256);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
byte[] hash = f.generateSecret(spec).getEncoded();
Base64.Encoder enc = Base64.getEncoder();
System.out.printf("salt: %s%n", enc.encodeToString(salt));
System.out.printf("hash: %s%n", enc.encodeToString(hash));
Note: PBKDF2WithHmacSHA256 is available since Java 8.
Here's a more complete example:
private static final SecureRandom random = new SecureRandom();
/**
* One-way encrypts (hashes) the given password.
*
* #param saltpw the salt (will be generated when null)
* #param pw the password to encrypt
* #return encrypted salted password
*/
public static String encrypt(String saltpw, String pw) throws GeneralSecurityException {
byte[] salt;
if (saltpw == null) {
salt = new byte[16];
random.nextBytes(salt);
} else {
salt = Base64.getDecoder().decode(saltpw.replaceFirst("\\$.*", ""));
}
KeySpec spec = new PBEKeySpec(pw.toCharArray(), salt, 100000, 256);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
byte[] hash = f.generateSecret(spec).getEncoded();
Base64.Encoder enc = Base64.getEncoder();
return enc.encodeToString(salt) + "$" + enc.encodeToString(hash);
}
public static void main(String[] args) throws Exception {
String enc = encrypt(null, "my-secret-password");
System.out.printf("enc : %s\n", enc);
String test1 = encrypt(enc, "my-secret-password");
System.out.printf("test 1: %s, valid: %b\n", test1, enc.equals(test1));
String test2 = encrypt(enc, "some-other-password");
System.out.printf("test 2: %s, valid: %b\n", test2, enc.equals(test2));
}
Prints:
enc : B5V6SjkjJpeOxvMAkPf7EA==$NNDA7o+Dpd+M+H99WVxY0B8adqVWJHZ+HIjgPxMljwo=
test 1: B5V6SjkjJpeOxvMAkPf7EA==$NNDA7o+Dpd+M+H99WVxY0B8adqVWJHZ+HIjgPxMljwo=, valid: true
test 2: B5V6SjkjJpeOxvMAkPf7EA==$4H1SpH8N+/jqU40G6RWb+ReHUB3C58iAaU4l39j+TV8=, valid: false
Notice how test 1 results in exactly the same encrypted string as the original password, and that test 2 (with a wrong password) doesn't. So that's how you can verify that the provided password is valid or not, by just comparing the hashes.
There is no way to prohibit decompiling of java.
But you can make it hard to understand the decompiled code if you use an obfuscator.
E.g. https://www.guardsquare.com/en/products/proguard
This changes all you method-, class-, variable- names to meaningless short names.
A side-effect is that your class file will shrink too.

How to generate a 128 bit key to use in AES algorithm

I am using the code in below mentioned post to encrypt and decrypt values between Java and Java script module of my application.
Compatible AES algorithm for Java and Javascript
In a above post they are using 128 bit key value. I want to use my own key instead of hard coding the 128 bit key value.
My question is that can I convert any random string into 128 bit key value.
Please post some examples if it is possible to convert any string into 128 bit value.
Characters are represented with 8 bits. hence to form 128 bit key, create a string having 16 chars (16*8=128), e.g. "abcdefgh12345678".
to mask this key as base64, you may use Apache commons-codec Base64.encodeBase64... #see http://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/binary/Base64.html
Something I fount by google, and use in my project:
private final static String algorithm = "PBKDF2WithHmacSHA1";
private final static String HEX = "0123456789ABCDEF";
private static final String CP_ALGORITH = "AES";
private static final String CP_KEY = "PUTsomeKEYinHere";
public static String cipher(String cipherKey, String data) throws NoSuchAlgorithmException,
InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException,
IllegalBlockSizeException, BadPaddingException {
SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);
KeySpec spec = new PBEKeySpec(cipherKey.toCharArray(), cipherKey.getBytes(), 128, 256);
SecretKey tmp = skf.generateSecret(spec);
SecretKey key = new SecretKeySpec(tmp.getEncoded(), CP_ALGORITH);
Cipher cipher = Cipher.getInstance(CP_ALGORITH);
cipher.init(Cipher.ENCRYPT_MODE, key);
return toHex(cipher.doFinal(data.getBytes()));
}
public static String decipher(String cipherKey, String data) throws NoSuchAlgorithmException,
InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException,
IllegalBlockSizeException, BadPaddingException {
SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);
KeySpec spec = new PBEKeySpec(cipherKey.toCharArray(), cipherKey.getBytes(), 128, 256);
SecretKey tmp = skf.generateSecret(spec);
SecretKey key = new SecretKeySpec(tmp.getEncoded(), CP_ALGORITH);
Cipher cipher = Cipher.getInstance(CP_ALGORITH);
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(toByte(data)));
}
private static byte[] toByte(String data) throws NullPointerException{
int len = data.length()/2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(data.substring(2*i, 2*i+2), 16).byteValue();
return result;
}
private static String toHex(byte[] doFinal) {
StringBuffer result = new StringBuffer(2*doFinal.length);
for (int i = 0; i < doFinal.length; i++) {
result.append(HEX.charAt((doFinal[i]>>4)&0x0f)).append(HEX.charAt(doFinal[i]&0x0f));
}
return result.toString();
}
usage:
cipher(CP_KEY, STRINGtoCIPHER);
decipher(CP_KEY, YOURcipheredSTRING)
I put that all in a shared class with static fields and methods, so i can use it everywhere in my app. I use it to store SessionID i shared preferences, and it works nice.

Password encryption method never returns the same result for the same parameters

I have found code leveraging java.security.* in order to encrypt passwords. But when I use it, It's not working. Each time I call the encrypt method with the same parameters (which are displayed in the encrypt() method, and are really each time the same), I get a different result, which of course makes the code useless. Here my code:
public byte[] encrypt(String clearPassword, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
System.out.println(clearPassword+" ********** "+salt);
String algorithm = "PBKDF2WithHmacSHA1";
int derivedKeyLength = 1600;
int iterations = 20000;
KeySpec spec = new PBEKeySpec(clearPassword.toCharArray(), salt, iterations, derivedKeyLength);
SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm);
byte [] truc = f.generateSecret(spec).getEncoded();
System.out.println(truc);
return truc;
}
public byte[] generateSalt() throws NoSuchAlgorithmException {
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[8];
random.nextBytes(salt);
return salt;
}
I think I introduced an error in the original code at some point, but I can't see where. Any idea?
It's because System.out.println(truc); does not do what you think it does. If you tried:
System.out.println(Arrays.toString(truc));
you would print the actual content of the array, which should be the same every time you call the method with the same parameters.
See for example: printing arrays

Categories