I'm developping an Android App that need authentication. However, there an existing web application (using Symfony) with accounts, and I have to reuse the same accounts to authenticate my users.
In the DB, I have the basicals : username, salt, encryptedPassword, encryption_type(sha1)...
The problem is that I don't know how to authenticate my users, by using these informations.
If someone can help me solving this...
Many thanks!
Depending on the encryption algorithm you would do something like this:
public final boolean authenticate(String attemptedPassword, byte[] encryptedPassword, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
String algorithm = "PBKDF2WithHmacSHA1";
int derivedKeyLength = 160;
int iterations = 20000;
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, derivedKeyLength);
SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm);
byte[] encryptedPassword = f.generateSecret(spec).getEncoded();
return Arrays.equals(encryptedPassword, encryptedAttemptedPassword);
}
You need to know which settings were used to generate the encrypted passwords in your database.
I finally succeded in doing that ! I've analysed the way Symfony check the password thanks to the PHP class "PluginsfGuardUser".
public final boolean authenticate(User user)
MessageDigest md = MessageDigest.getInstance(SHA1);
byte[] saltPassword = (user.getSalt() + user.getPassword()).getBytes();
byte[] encryptedPassword = md.digest(saltPassword);
String pass = byteArrayToHexString(encryptedPassword);
if (pass.equals(user.getDbPassword()))
{
return true;
}
else
{
return false;
}
}
private String byteArrayToHexString(byte[] array) {
String result = "";
for (int i = 0; i < array.length; i++) {
result
+= Integer.toString((array[i] & 0xff) + 0x100, 16).substring(1);
}
return result;
}
Related
I am currently working on my final project for school. It´s a client management system, and on the login, I have decided to include an encryption feature so that clients can store their credentials without having to worry about their passwords being out in the open.
I have found this code online, and, since I'm still new on programming, I was wondering if you could give me a little bit of help regarding the meaning of the code.
I know what it does, I just need a little bit of explanation on how it does it.
Here is the code:
package Login;
import java.security.MessageDigest;
public class Encrypter {
public static void main(String[] args) {
String password = "password";
String algorithm = "SHA";
byte[] plainText = password.getBytes();
MessageDigest md = null;
try {
md = MessageDigest.getInstance(algorithm);
} catch (Exception e) {
e.printStackTrace();
}
md.reset();
md.update(plainText);
byte[] encodedPassword = md.digest();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < encodedPassword.length; i++) {
if ((encodedPassword[i] & 0xff) < 0x10) {
sb.append("0");
}
sb.append(Long.toString(encodedPassword[i] & 0xff, 16));
}
System.out.println("Plain : " + password);
System.out.println("Encrypted: " + sb.toString());
}
}
Since yesterday when I posted the frist time I learned a lot. So what I am trying to do now is to implement user console input instead of the given values, written in bold, encrypt, save them in the file and then keep verifying next user input with the encrypted values saved in the file until correct or up to 10 times.
String openPwd = "my password is datasecurity";
String openUser = "a user is ME";
The first question is: can I implement second user input and verification in the same main method of the class?
Moreover I encrypt values with two way encryption AES (Now I know that is not the safest way to encrypt) and one way encryption with hash and salt would be the safest option due to the number of reasons. Also I save password and key in the system file, since setting up database would be too time consuming for the task.
The second question is: can I use PBKDF2 and salt instead of encryption with AES if I do not save password and user name in dbms, but in system file instead? How will verification process in encryption case and PBKDF2 with salt differ?
public class PasswordEncryption {
public static final String AES = "AES";
public static String encrypt(String value, File keyFile)
throws GeneralSecurityException, IOException {
if (!keyFile.exists()) {
KeyGenerator keyGen = KeyGenerator
.getInstance(PasswordEncryption.AES);
keyGen.init(128);
SecretKey sk = keyGen.generateKey();
FileWriter fw = new FileWriter(keyFile);
fw.write(byteArrayToHexString(sk.getEncoded()));
fw.flush();
fw.close();
}
SecretKeySpec sks = getSecretKeySpec(keyFile);
Cipher cipher = Cipher.getInstance(PasswordEncryption.AES);
cipher.init(Cipher.ENCRYPT_MODE, sks, cipher.getParameters());
byte[] encrypted = cipher.doFinal(value.getBytes());
return byteArrayToHexString(encrypted);
}
public static String decrypt(String message, File keyFile)
throws GeneralSecurityException, IOException {
SecretKeySpec sks = getSecretKeySpec(keyFile);
Cipher cipher = Cipher.getInstance(PasswordEncryption.AES);
cipher.init(Cipher.DECRYPT_MODE, sks);
byte[] decrypted = cipher.doFinal(hexStringToByteArray(message));
return new String(decrypted);
}
private static SecretKeySpec getSecretKeySpec(File keyFile)
throws NoSuchAlgorithmException, IOException {
byte[] key = readKeyFile(keyFile);
SecretKeySpec sks = new SecretKeySpec(key, PasswordEncryption.AES);
return sks;
}
private static byte[] readKeyFile(File keyFile)
throws FileNotFoundException {
#SuppressWarnings("resource")
Scanner scanner = new Scanner(keyFile).useDelimiter("\\Z");
String keyValue = scanner.next();
scanner.close();
return hexStringToByteArray(keyValue);
}
private static String byteArrayToHexString(byte[] b) {
StringBuffer sb = new StringBuffer(b.length * 2);
for (int i = 0; i < b.length; i++) {
int v = b[i] & 0xff;
if (v < 16) {
sb.append('0');
}
sb.append(Integer.toHexString(v));
}
return sb.toString().toUpperCase();
}
private static byte[] hexStringToByteArray(String s) {
byte[] b = new byte[s.length() / 2];
for (int i = 0; i < b.length; i++) {
int index = i * 2;
int v = Integer.parseInt(s.substring(index, index + 2), 16);
b[i] = (byte) v;
}
return b;
}
public static void main(String[] args) throws Exception {
final String KEY_FILE = "/Users/xxx/key";
final String PASSWORD_FILE = "/Users/xxx/properties";
String openPwd = "my password is datasecurity";
String openUser = "a user is ME";
Properties p1 = new Properties();
String encryptedPwd = PasswordEncryption.encrypt(openPwd, new File(
KEY_FILE));
String encryptedUser = PasswordEncryption.encrypt(openUser, new File(
KEY_FILE));
p1.put("password",encryptedPwd);
p1.put("user",encryptedUser);
p1.store(new FileWriter(PASSWORD_FILE),"");
// ==================
Properties p2 = new Properties();
p2.load(new FileReader(PASSWORD_FILE));
encryptedPwd = p2.getProperty("password");
encryptedUser = p2.getProperty("user");
System.out.println(encryptedPwd);
System.out.println(encryptedUser);
System.out.println(PasswordEncryption.decrypt(encryptedPwd, new File(
KEY_FILE)));
System.out.println(PasswordEncryption.decrypt(encryptedUser, new File(
KEY_FILE)));
}
}
There are two simple ways of doing this. The first would be to create a static class level variable in your first class that contains the value of the encryptedPwd. To make a class level variable you would define it like this:
public class FirstClass {
public static String encryptedPwd = "";
public static void main(String[] args){
...
FirstClass.encryptedPwd = encryptedPwd; //Set the class level variable equal to the encrypted password
...
}
}
Then you could access it from your Authenticate class using:
if (FirstClass.encryptedPwd.equals(inputHash)) //Getting the password variable in Authenticate class
or you could create a static method to access it as well which would allow you to keep the variable private.
public static String getPassword(){ //Static Method inside your first class that returns the encrypted password
return encryptedPwd;
}
if(FirstClass.getPassword().equals(inputHash)) //Method call in Authenticate class
There are other options too, but it depends on what your doing and the design you want for your project
I have an API documentation that requires encrypting a key to authenticate,
I managed to build and compile their sample code, but the results on windows are different than linux.
When I run and test from Windows, all seems to be correct and works with the API.
That same test on Linux outputs a different result. I need it working on Linux since that's the main server.
I am using & running the same jar file on both environments.
This is the key I am trying to encrypt (it's a dynamic key):
2136230$486B91E1BEA5D082BA3601CD803585CE$20140409$20140409$$ABCDEFGH$Reserved$CTC
This is the correct output on Windows (it's obviously quite longer):
F7BE2B7E0CEAD9D09135FCF2A8AEB11E2937D26B33CCBC9B8132A29A3534040C9737B2A8E3F271A9DF6454696CF890F7886223AE9C86F81EF58E41AEAA3D34A80F7089154E64F4FD36E75C25A7C2DA7FF03D21F57DA950F5
This is the wrong output from Linux:
F66D4CE1238B30EE54ABC74966D7AC3064FEA3ADFB9D37548E41509CE4FED9CB1D146651B491F2433169999A85F73DAF9ACD07A090DF3D85477BE4201ADC9E1A0181EA7CB763050A
What is causing this and how to correct it ?
This is the source code of the program to use as we received from the API company:
public class DESUtil
{
private static final String Algorithm = "DESede/ECB/PKCS5Padding";// DESede/ECB/PKCS5Padding;DESede
private static final String DESede = "DESede";
public static byte[] encrypt(byte[] keybyte, byte[] src)
throws NoSuchAlgorithmException, NoSuchPaddingException, Exception
{
SecretKey deskey = new SecretKeySpec(keybyte, DESede);
Cipher c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.ENCRYPT_MODE, deskey);
return c1.doFinal(src);
}
public static byte[] decrypt(byte[] keybyte, byte[] src)
throws NoSuchAlgorithmException, NoSuchPaddingException, Exception
{
SecretKey deskey = new SecretKeySpec(keybyte, DESede);
Cipher c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.DECRYPT_MODE, deskey);
return c1.doFinal(src);
}
public static String byte2hex(byte[] b)
{
StringBuffer hs = new StringBuffer();
String stmp = "";
for (int n = 0; n <b.length; n++)
{
stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
if (stmp.length() == 1)
hs.append("0").append(stmp);
else
hs.append(stmp);
}
return hs.toString().toUpperCase(Locale.getDefault());
}
public static byte[] hex2byte(String hexStr)
{
if (hexStr.length() % 2 != 0)
{
AppLogger.error("hex2bytes's hexStr length is not even.");
return null;
}
byte[] toBytes = new byte[hexStr.length() / 2];
for (int i = 0, j = 0; i <hexStr.length(); j++, i = i + 2)
{
int tmpa = Integer.decode(
"0X" + hexStr.charAt(i) + hexStr.charAt(i + 1)).intValue();
toBytes[j] = (byte) (tmpa & 0XFF);
}
return toBytes;
}
public static void main(String[] args)
{
Security.addProvider(new com.sun.crypto.provider.SunJCE());
final byte[] rawKey = "db90e7eb".getBytes();
final byte[] keyBytes = new byte[24];
for (int i = 0; i <rawKey.length; i++)
{
keyBytes[i] = rawKey[i];
}
for (int i = rawKey.length; i <keyBytes.length; i++)
{
keyBytes[i] = (byte)0;
}
String szSrc = "20926330$AD75B1697FB5EB6345B2D412124030D2$10086$10086$10.164.111$ABCDEFGH$Reserved$CTC";
System.out.println("string before encrypt:" + szSrc);
byte[] encoded = null;
try
{
encoded = encrypt(keyBytes, szSrc.getBytes());
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println("string after encrypt::" + byte2hex(encoded));
byte[] srcBytes = null;
try
{
srcBytes = decrypt(keyBytes, encoded);
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println("string before decode: :" + (new String(srcBytes)));
}
}
Almost certainly your use of szSrc.getBytes() which uses the platform's default character encoding.
Try szSrc.getBytes("ISO-8859-1") as a starter if it's working on Windows, but if this string comes from an external service you should determine the encoding scheme dynamically (eg. if it comes through a Servlet use httpRequest.getCharacterEncoding()).
I generate a key and use the doFinal() from the cipher class to encrypt the password/username, now, when the user wants to login he inputs UN and PW then I take them what is the process I need to do so I compare the input to the database I saved the encrypted data in?
Writing this question I feel stupid but the truth is I am really new to this and my information could be remote from right so please move on to explaining and pass the what are you talking about part.
now the code I used :
public class Safety {
public static Users encryptUser(Users user){
Users usera=user;
try {
KeyGenerator kg = KeyGenerator.getInstance("AES/CBC/PKCS5Padding");
Key key=kg.generateKey();
Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
String fNE=new String(cipher.doFinal(user.getFirstname().getBytes()),"UTF-8");
String lNE=new String(cipher.doFinal(user.getLastname().getBytes()) , "UTF-8");
String userNameE= new String(cipher.doFinal(user.getUsername().getBytes()),"UTF-8");
String passWordE= new String(cipher.doFinal(user.getPassword().getBytes()),"UTF-8");
String eME= new String(cipher.doFinal(user.getEmail().getBytes()),"UTF-8");
String sQE= new String(cipher.doFinal(user.getsQ().getBytes()),"UTF-8");
String sAE= new String(cipher.doFinal(user.getsA().getBytes()),"UTF-8");
Users usere=new Users(fNE, lNE, userNameE, passWordE, eME, sQE, sAE, user.getUserID());
return usere;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
catch(Exception e){
e.printStackTrace();
}
return usera;
}
public static String decryptuser(Users user){
//what should I do here exactly?
}
}
after a little of research and work this is what i have come up with :
public class Safety {
public static final String algorithm = "PBKDF2WithHmacSHA1";
public static final int saltbytesize = 24;
public static final int hashbytesize = 24;
public static final int iterations = 1000;
public static final int iIndex = 0;
public static final int sIndex = 1;
public static final int pbkIndex = 2;
public static Users passwordHash(Users user) throws NoSuchAlgorithmException, InvalidKeySpecException{
SecureRandom sR=new SecureRandom();
byte[] pws=new byte[saltbytesize];
sR.nextBytes(pws);
byte[] pwh=pbkdf2(user.getPassword().toCharArray(),pws,iterations,hashbytesize);
user.setPassword(toHex(pwh));
byte[] sas=new byte[saltbytesize];
sR.nextBytes(sas);
byte[] sah=pbkdf2(user.getsA().toCharArray(),sas,iterations,hashbytesize);
user.setsA(toHex(sah));
user.setUserhash(pws);
user.setSahash(sas);
return user;
}
public static boolean hashpassword(String username,String password,Users user) throws NoSuchAlgorithmException, InvalidKeySpecException{
byte[] pws=user.getUserhash();
byte[] pwh=pbkdf2(password.toCharArray(),pws,iterations,hashbytesize);
String searcher=toHex(pwh)+username;
String searched=user.getPassword()+user.getUsername();
if(searcher.equals(searched)){
return true;
}
return false;
}
private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int bytes)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8);
SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);
return skf.generateSecret(spec).getEncoded();
}
private static String toHex(byte[] array)
{
BigInteger bi = new BigInteger(1, array);
String hex = bi.toString(16);
int paddingLength = (array.length * 2) - hex.length();
if(paddingLength > 0)
return String.format("%0" + paddingLength + "d", 0) + hex;
else
return hex;
}
}
and this is great for now how ever id like to make it work with SHA512 how can i do that?
You should not encrypt the password, you should hash it with the user name and a salt.
See Why should I hash passwords?
Can someone figure out why the output of these (php and java) snippets of code don't return the same SHA512 for the same input?
$password = 'whateverpassword';
$salt = 'ieerskzcjy20ec8wkgsk4cc8kuwgs8g';
$salted = $password.'{'.$salt.'}';
$digest = hash('sha512', $salted, true);
echo "digest: ".base64_encode($digest);
for ($i = 1; $i < 5000; $i++) {
$digest = hash('sha512', $digest.$salted, true);
}
$encoded_pass = base64_encode($digest);
echo $encoded_pass;
This is the code on the android application:
public String processSHA512(String pw, String salt, int rounds)
{
try {
md = MessageDigest.getInstance("SHA-512");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException("No Such Algorithm");
}
String result = hashPw(pw, salt, rounds);
System.out.println(result);
return result;
}
private static String hashPw(String pw, String salt, int rounds) {
byte[] bSalt;
byte[] bPw;
String appendedSalt = new StringBuilder().append('{').append(salt).append('}').toString();
try {
bSalt = appendedSalt.getBytes("ISO-8859-1");
bPw = pw.getBytes("ISO-8859-1");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Unsupported Encoding", e);
}
byte[] digest = run(bPw, bSalt);
Log.d(LCAT, "first hash: " + Base64.encodeBytes(digest));
for (int i = 1; i < rounds; i++) {
digest = run(digest, bSalt);
}
return Base64.encodeBytes(digest);
}
private static byte[] run(byte[] input, byte[] salt) {
md.update(input);
return md.digest(salt);
}
The library for base64 encoding is this: base64lib
This java code is actually some modified code I found around another question in StackOverflow.
Although the Android code is running fine it doesn't match with the output from the php script. It doesn't even match the first hash!
Note 1: On php hash('sha512',$input, $raw_output) returns raw binary output
Note 2: On java I tried to change the charset (UTF-8, ASCII) but it also didn't work.
Note 3: The code from the server can not be changed, so I would appreciate any answer regarding how to change my android code.
The first hash should be the same on the server and in Java. But then in the loop what gets appended to the digest is password{salt} in the PHP code, but only {salt} in the Java code.
For the lazy ones, one example better than a thousand words ;). I finally understood what was happening. The method update appends bytes to the digest, so when you append $password.{$salt} is the same as doing mda.update(password bytes) and the mda.digest("{$salt}" bytes. I do that answer because I was going crazy finding why it was not working and it was all in this answer.
Thanks guys.
This is the example that works in a Java Server:
public static String hashPassword(String password, String salt) throws Exception {
String result = password;
String appendedSalt = new StringBuilder().append('{').append(salt).append('}').toString();
String appendedSalt2 = new StringBuilder().append(password).append('{').append(salt).append('}').toString();
if(password != null) {
//Security.addProvider(new BouncyCastleProvider());
MessageDigest mda = MessageDigest.getInstance("SHA-512");
byte[] pwdBytes = password.getBytes("UTF-8");
byte[] saltBytes = appendedSalt.getBytes("UTF-8");
byte[] saltBytes2 = appendedSalt2.getBytes("UTF-8");
byte[] digesta = encode(mda, pwdBytes, saltBytes);
//result = new String(digesta);
System.out.println("first hash: " + new String(Base64.encode(digesta),"UTF-8"));
for (int i = 1; i < ROUNDS; i++) {
digesta = encode(mda, digesta, saltBytes2);
}
System.out.println("last hash: " + new String(Base64.encode(digesta),"UTF-8"));
result = new String(Base64.encode(digesta));
}
return result;
}
private static byte[] encode(MessageDigest mda, byte[] pwdBytes,
byte[] saltBytes) {
mda.update(pwdBytes);
byte [] digesta = mda.digest(saltBytes);
return digesta;
}