Let say i have encripted SHA1 password like this
String pass = "f6ce584e7b4ff5253eed4a2ea2b44247";
and i want make condition like this :
if (pass.equals("userinput")){
System.out.println("success");
}
please someone help me to make proper condition / function to compare those both value between user input and encripted password. Your help will be highly appreciated. thanks
SHA1 is a hash algorithm, which means that it is one-way. You can't get the original message after hashing it. Unlike encryption which is two-way (allows encryption and decryption).
This means that if you want to compare a hash, you don't try to get the original message. Instead, you hash the message-to-be-compared as well, then you perform the match:
So if the hashed pw is stored as:
String pass = "f6ce584e7b4ff5253eed4a2ea2b44247";
To match the subsequent input of the password, you do:
//check if hashed userInput is also "f6ce584e7b4ff5253eed4a2ea2b44247"
if(pass.equals(sha1(userInput))){
//do whatever
}
To implement a sha1() hash function, refer to: Java String to SHA1
To get your hashcode:
public static byte[] sha1(byte[] data)
Calculates the SHA-1 digest and returns the value as a byte[].
Parameters:
data - Data to digest
Returns:
SHA-1 digest
Found these at
https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/digest/DigestUtils.html#sha1Hex(java.lang.String)
This helps your process.
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jcajce.provider.asymmetric.rsa.DigestSignatureSpi.SHA1;
public class SHA1_test {
public static String sha1(String s, String keyString)
throws UnsupportedEncodingException, NoSuchAlgorithmException,
InvalidKeyException {
SecretKeySpec key = new SecretKeySpec((keyString).getBytes("UTF-8"),
"HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(key);
byte[] bytes = mac.doFinal(s.getBytes("UTF-8"));
return new String(Base64.encodeBase64(bytes));
}
public static void main(String[] args) throws InvalidKeyException,
UnsupportedEncodingException, NoSuchAlgorithmException {
Boolean validate = false;
String code = sha1("admin", "123456");
String your_user_inputString = "testpassword";
if (code.equals(sha1(your_user_inputString, "123456"))) {
System.out.println("Correct");
} else {
System.out.println("Bad password");
}
}
}
This works!!!
Related
I'm trying to implement a more advanced password hashing algorithm (PBKDF2) that uses the Base64 class that is found in the java util library, but since this class is outdated I need to get the Apache Codecs library that supports the updated Base64 class. The amazing thing is that on a normal java class this works flawlessly, but when I use the same piece of code in an android activity it gives me an error saying that the method that I'm trying to call from Base64 does not exist!
I think the problem here is that in the activity, the Base64 is called from the util library that has the outdated version of Base64.
Here is an example of the code.
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.SecureRandom;
import org.apache.commons.codec.binary.Base64;
public class Password {
// The higher the number of iterations the more
// expensive computing the hash is for us and
// also for an attacker.
private final int iterations = 20 * 1000;
private final int saltLen = 32;
private final int desiredKeyLen = 256;
/**
* Computes a salted PBKDF2 hash of given plaintext password
* suitable for storing in a database.
* Empty passwords are not supported.
*/
public String getSaltedHash(String password) throws Exception {
byte[] salt = SecureRandom.getInstance("SHA1PRNG").generateSeed(saltLen);
// store the salt with the password
return Base64.encodeBase64String(salt) + "$" + hash(password, salt);
}
/**
* Checks whether given plaintext password corresponds
* to a stored salted hash of the password.
*/
public boolean check(String password, String stored) throws Exception {
String[] saltAndPass = stored.split("\\$");
if (saltAndPass.length != 2) {
throw new IllegalStateException(
"The stored password have the form 'salt$hash'");
}
String hashOfInput = hash(password, Base64.decodeBase64(saltAndPass[0]));
return hashOfInput.equals(saltAndPass[1]);
}
// using PBKDF2 from Sun, an alternative is https://github.com/wg/scrypt
// cf. http://www.unlimitednovelty.com/2012/03/dont-use-bcrypt.html
private String hash(String password, byte[] salt) throws Exception {
if (password == null || password.length() == 0)
throw new IllegalArgumentException("Empty passwords are not supported.");
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecretKey key = f.generateSecret(new PBEKeySpec(
password.toCharArray(), salt, iterations, desiredKeyLen)
);
return Base64.encodeBase64String(key.getEncoded());
}
public static void main(String[] args) throws Exception {
Password passwordHash = new Password();
String password = passwordHash.getSaltedHash("password");
String password2 = passwordHash.getSaltedHash("password");
System.out.println("P1-HASH: " + password);
System.out.println("P2-HASH: " + password2);
System.out.println(passwordHash.check("password", password2));
}
}
The method seems to be called encodeToString. I really don't know where you found your particular method, but it isn't documented; I think you were just referring to the wrong class.
I need a little help from you, I have an exercise , to do a login program and to store the password with sha-256 and salt, I made a part, but here it's the hard part. I've read that if you use sha-256 that you can't reverse the operation to determine the password. If it's true then what I need to use to encrypt the password and after I encrypt the password, how can I login if the password is encrypted?
PS: I've searched on google.
You should read about how hash functions work. Hash functions only produce a value, that depends on your input. Since the formula to calculate that value is always the same for a particular hash function (i.e. SHA-256), you can always produce it, if you know the input (the password in your case). So, unlike ciphers, a value calculated by the hash function is not supposed to be decrypted.
what I need to use to encrypt the password
You don't have to encrypt the password, since as you said, you cannot reverse the operation by just knowing the hash value, that's stored in you database. You can only gain access, if you know the password in plain text form.
Try the sample code below, it works well on my side
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Base64;
import java.util.Base64.Encoder;
import java.util.Scanner;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.util.Base64.Decoder;
public class Cryptography {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {
Encoder encoder = Base64.getUrlEncoder().withoutPadding();
Decoder decoder = Base64.getUrlDecoder();
String integritystring = "810710202108241079100KAY435788318046";
String strSalt = "3a9IbkKNr2RjwFwGnPudHbLfA4zugj6TVcoBtlWpJl0m";
byte[] bSalt = Base64.getMimeDecoder().decode(strSalt);
System.out.println("Salt: " + strSalt);
System.out.println("integritystring: " + integritystring);
String strHash = encoder.encodeToString(Hash(integritystring, bSalt));
System.out.println("Hash: " + strHash);
}
private static byte[] Salt() {
SecureRandom random = new SecureRandom();
byte salt[] = new byte[6];
random.nextBytes(salt);
return salt;
}
private static byte[] Hash(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] hash = factory.generateSecret(spec).getEncoded();
return hash;
}
}
Let's assume your password is 12345678. You are going to hash this password and save it to you program. In your login program you take the input from the user, hash it with the same algorithm and then compare the two hashed strings. If the are equal, the strings are equal, if not, they aren't equal. The person cannot figure out what the correct password is and you have hashed your password.
I have been working on my own little project, where I am trying to make a simple password manager. The problem I'm having currently, is getting it to work in a way so that when ran, it saves the encrypted password to a file, then when ran another time, you can call it and it will be decrypted, showing you your password for the username you call.
For something I would like to add on to the program later, I do need to keep the encryption/decryption methods separate.
The current error is:
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
Any help is greatly appreciated.
Code follows:
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.util.Scanner;
import javax.crypto.spec.SecretKeySpec;
public class PasswordManager3
{
static String key = "SimplePasswordMg";
static String password1 = "";
static String password2 = "";
static String username = "";
public static void main(String[] args)
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException,
BadPaddingException, IOException
{
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
System.out.println("Enter New to input a new password, or Retrieve to retrieve an old password:");
Scanner scanner1 = new Scanner(System.in);
String answer = scanner1.nextLine();
if(answer.equalsIgnoreCase("New")) {
System.out.println("Please enter a username: ");
Scanner scanner2 = new Scanner(System.in);
username = scanner2.nextLine();
System.out.println("Please enter a password: ");
Scanner scanner3 = new Scanner(System.in);
password1 = scanner3.nextLine();
System.out.println("Please enter your password again: ");
Scanner scanner4 = new Scanner(System.in);
password2 = scanner4.nextLine();
if (password1.equalsIgnoreCase(password2)) {
Files.write(Paths.get(username + ".txt"), encrypt(password1, cipher, aesKey));
System.out.println("Your password has been stored.");
}
else {
System.out.println("The passwords you entered did not match. Exiting password manager.");
}
}
else if(answer.equalsIgnoreCase("Retrieve")) {
System.out.println("Please enter the username you would like to retrieve the password for: ");
Scanner scanner5 = new Scanner(System.in);
username = scanner5.nextLine();
BufferedReader in = new BufferedReader(new FileReader(username + ".txt"));
String encryptedpass = in.readLine();
byte[] encryptedpass2 = encryptedpass.getBytes("UTF-8");
System.out.println(decrypt(encryptedpass2, cipher, aesKey));
}
else {
System.out.println("You entered an incorrect option, program exited.");
}
}
public static byte[] encrypt(String str, Cipher cipher, Key aesKey)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException
{
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher.doFinal(key.getBytes("UTF-8"));
return encrypted;
}
public static String decrypt(byte[] byte1, Cipher cipher, Key aesKey)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
cipher.init(Cipher.DECRYPT_MODE, aesKey);
String decrypted = new String(cipher.doFinal(byte1));
return decrypted;
}
}
You are not writing a text file. Encrypted data is effectively random bits, and your main passes the return from encrypt directly to Files.write(Path,byte[]) which writes it as binary.
When you read it back in with FileReader it uses the default encoding for your platform, which you didn't identify, and sometimes your user's environment, which may or may not mangle some bytes; using readLine() may discard part of the data, and encoding it with getBytes("UTF-8") when it was never valid characters to start with is about 99.6% certain to mangle whatever is left. As a result the value you pass to decrypt is completely wrong, and can't be decrypted.
The easy, symmetric fix is use File.readAllBytes(Path) to read the (whole) file as binary, and decrypt the byte[] value that returns.
Alternatively, if you really want text files for some reason (and I don't see any), you need to first encode the encrypted value into a textual form and write that, probably with a line terminator added, then read it back (as a line if you chose that) and decode it before decrypting. Base64 and hexadecimal (abbreviated hex) are the two most common methods of textually encoding binary data.
Also: using a key which is all printable ASCII and contains even parts of English words hugely weakens your encryption, from the nominal 128 bits to something more like 20-30 bits, which can be easily broken by any half-competent attacker. Using any hardcoded key is also a danger, although this is a harder problem and there is no single, easy and good solution.
And you are using AES in ECB mode by default. Using ECB for passwords (and almost anything else) is a bad idea; to learn why google "ECB penguin" and "Adobe password breach" and/or see
https://crypto.stackexchange.com/questions/11451/can-ecb-mode-really-leak-some-characters
https://crypto.stackexchange.com/questions/11456/what-does-it-mean-if-second-half-of-8-char-string-encrypted-in-3des-is-always-id
I am trying to create a basic demo application where one class will generate a message to be sent in the following format
SignedMessage_using_HMAC.BASE64encoded_message
At the receiving end (DecodeData.java) first I wan to compare if the message was signed using the right key by decrypting the signed message and then signing the message with the same key and then compare the signed message at the receiver end the signed message sent.
But these do not work.
When I try to decode the Base64 encoded message it does not give me the correct message.
Can anyone please guide me what's wrong here?
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class EncodeData {
public static void main(String[] args) throws Exception {
String myAppContext = "abc123def";
String consumerSecret = "959595";
String algorithm = "HMACSHA256";
byte[] encodedContext;
// Base64 encoded context;
encodedContext = new Base64(true).encode(myAppContext.getBytes());
System.out.print("Encoded Context : ");
System.out.println(encodedContext);
//Generate Signed context
SecretKey hmacKey = new SecretKeySpec(consumerSecret.getBytes(), algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(hmacKey);
byte[] digest = mac.doFinal(myAppContext.getBytes());
System.out.print("Created digest : ");
System.out.println(digest);
// Signed Based64 context and Base64 encoded context
String messageToSend = digest.toString() + "." + encodedContext.toString();
System.out.println(messageToSend);
}
}
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;
public class DecodeData {
public static void main(String[] args) throws Exception {
byte[] myAppContext;
String consumerSecret = "959595";
String algorithm = "HMACSHA256";
String messageRecieved = args[0];
byte[] singedDecodedContext;
String recievedDigest = messageRecieved.split("[.]", 2)[0];
String encodedContext = messageRecieved.split("[.]", 2)[1];
myAppContext = new Base64(true).decode(encodedContext);
System.out.print("Decrypted message : ");
System.out.println(myAppContext);
//Check if the message is sent by the correct sender by signing the context and matching with signed context
SecretKey hmacKey = new SecretKeySpec(consumerSecret.getBytes(), algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(hmacKey);
byte[] digest = mac.doFinal(myAppContext);
System.out.print("Created digest : ");
System.out.println(digest);
if (Arrays.equals(digest, recievedDigest.getBytes())) {
System.out.println("Message was not tempered and was sent by the correct sender");
} else {
System.out.println("Message was tempered or was not sent by the corrrect sender");
}
}
}
Output
Output of EncodeData.java
C:\Users\vivek.patel\Desktop\API\java\encoding>java -cp commons-codec-1.10.jar;. EncodeData
Encoded Context : [B#510bfe2c
Created digest : [B#73f025cb
[B#73f025cb.[B#510bfe2c
Output of DecodeData.java
C:\Users\vivek.patel\Desktop\API\java\encoding>java -cp commons-codec- 1.10.jar;. DecodeData [B#73f025cb.[B#510bfe2c
Decrypted message : [B#6726a408
Created digest : [B#7168bd8b
Message was tempered or was not sent by the correct sender
Before evaluate your code, you aren't actually comparing the values.
If you print like this:
System.out.print("Encoded Context : ");
System.out.println(encodedContext);
You are just printting the type of the array ([B) followed by its hashCode.
Initialize a String with the encoded bytes:
System.out.println(new String(encodedContext, "UTF8"));
You should also consider using an explicit charset instead of the default one (depending on your origin charset).
Try it and re-post your results.
I am trying to make an api call in java using these steps:
json encode
RC4 encryption
base64 encoding
I am currently using the same system in php and its working correctly:
$enc_request = base64_encode(openssl_encrypt(json_encode($request_params), "rc4", $this->_app_key));
But when I use the same system in java, the results are not as expected. Here's my code:
//json encoding
JSONObject obj = new JSONObject();
obj.put("email", username);
obj.put("password", password);
obj.put("action", "login");
//function to encode base64
private String getBase64Encoded(String encryptedJsonString)
{
byte[] encoded = Base64.encodeBase64(encryptedJsonString.getBytes());
String encodedString = new String(encoded);
return encodedString;
}
//function to encrypt in RC4
private String getRC4EncryptedString2(String string, String key) throws Exception
{
Cipher cipher = Cipher.getInstance("RC4");
SecretKeySpec rc4Key = new SecretKeySpec(key.getBytes(), "RC4");
cipher.init(Cipher.ENCRYPT_MODE, rc4Key);
byte[] cipherText = cipher.update(string.getBytes());
return new String(cipherText);
}
I was able to identify the problem upto the RC4 encryption which is not returning the same result as the php version.
I've been battling this for 2 days now. I hope I have not missed any stupid thing because this should be straight-forward.
Thanks
You should use a byte[] not a String to hold intermediate byte array values. A String is for text, not raw data, and will attempt to decode the bytes as character data using your system's default character set (at least, the single-parameter String constructor will). Same with String.getBytes().
Just return cipherText directly from getRC4EncryptedString2(), and pass it directly to getBase64Encoded(). There's a reason those encoders operate on byte arrays, and that reason is not so that you can garble the data by applying a character encoding to it in between.
The same goes for the key you are passing to getRC4EncryptedString2(). At the bare minimum use String.getBytes("ISO-8859-1") or something (assuming that your key is actually text and not yet another garbled byte array). The no-parameter version of getBytes() returns the text encoded using your system's default character set, which is not guaranteed to be what you want.
That also all applies to the String you are returning from your base 64 encoder. I don't know what base 64 encoder you are using, but make sure you specify the character set to the String constructor. Most likely you will be OK, purely by coincidence, but you should always specify a character set when converting to/from String and raw bytes. And that, of course, assumes that your base 64 encoder returns text, rather than bytes in the range 0-63.
The general point here is you can't just convert back and forth from String to byte[]. A String is for text and it's representation as a byte[] depends on the character encoding.
I am able to achieve this using the following code. Hope this helps!
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.codec.DecoderException;
import org.bouncycastle.util.encoders.Hex;
import org.json.JSONException;
import org.json.JSONObject;
public class RC4Algo {
public static void main(String args[])throws IOException, NoSuchAlgorithmException, DecoderException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, JSONException
{
decryptRC4();
}
static String decryptRC4() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, JSONException{
//byte[] plainBytes = "testString".getBytes();
//json encoding
JSONObject obj = new JSONObject();
obj.put("email", "username");
obj.put("password", "password");
obj.put("action", "login");
byte [] plainBytes = obj.toString().getBytes();
String hashedKey = hashedData("thisismysecretkey");
//Generate a new key using KeyGenerator
/*KeyGenerator rc4KeyGenerator = KeyGenerator.getInstance("RC4");
SecretKey key = rc4KeyGenerator.generateKey();*/
Key key = new SecretKeySpec(Hex.decode(hashedKey), "RC4");
// Create Cipher instance and initialize it to encrytion mode
Cipher cipher = Cipher.getInstance("RC4"); // Transformation of the algorithm
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherBytes = cipher.doFinal(plainBytes);
String encoded = encodeBase64(cipherBytes);
String decoded = decodeBase64(encoded);
// Reinitialize the Cipher to decryption mode
cipher.init(Cipher.DECRYPT_MODE,key, cipher.getParameters());
byte[] plainBytesDecrypted = cipher.doFinal(Hex.decode(decoded));
System.out.println("Decrypted Data : "+new String(plainBytesDecrypted));
return new String(plainBytesDecrypted);
}
static String decodeBase64(String encodedData){
byte[] b = Base64.getDecoder().decode(encodedData);
String decodedData = DatatypeConverter.printHexBinary(b);
return decodedData;
}
static String encodeBase64(byte[] data){
byte[] b = Base64.getEncoder().encode(data);
String encodedData = new String(b);
/*String encodedData = DatatypeConverter.printHexBinary(b);*/
return encodedData;
}
static String hashedData(String key) throws NoSuchAlgorithmException{
String password = key;
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(password.getBytes());
byte byteData[] = md.digest();
//convert the byte to hex format method 1
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
//convert the byte to hex format method 2
StringBuffer hexString = new StringBuffer();
for (int i=0;i<byteData.length;i++) {
String hex=Integer.toHexString(0xff & byteData[i]);
if(hex.length()==1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
}
Output: