I am currently making a new password storage program. To do this I am using MySQL and Java. I will be storing it into a portable (SQLite) database. However my problem is when making my security more secure it is failing. Before I put my password into a database I encrypt it for security I then add a more secure string to the end (right now) of the encryption. I know I probably shouldn't be telling you this but I will be changing it after I have had some help. My problem is when I add the two strings together it works. I then try and take away the second string (for decrypting) except the bytes does not equal 16 so I can't decrypt my password. I know there are several questions for converting strings to bytes except this one is different. My code is below.
public static String upload(String password, String username, String website) throws Exception, GeneralSecurityException{
//Generates the encryption
String key = "dcW2znalixOYi7jt";
byte[] encrypted = Encryption.encrypt(key, password);
String encryption = "syfs8yy48y3483434tg4";
String encryptionfinal = encrypted + encryption;
if(encryptionfinal.contains(encryption)){
System.out.println("LOL FAILURE");
System.out.println(encrypted);
String test = encryptionfinal.replace(encryption, "");
System.out.println(encryptionfinal);
System.out.println(test);
byte[] atest = test.getBytes();
System.out.println("Length Of Byte From Test:");
System.out.println(atest.length);
System.out.println("Length Of Byte From Key:");
System.out.println(key.length());
System.out.println("Length Of String Test:");
System.out.println(test.length());
System.out.println("Length Of Encryption:");
System.out.println(encrypted.length);
System.out.println("Length Of EncryptionFinal:");
System.out.println(encryptionfinal.length());
System.out.println("Length of encryption addon:");
System.out.println(encryption.length());
System.out.println("Length of encryption final - encryption addon:");
System.out.println(encryptionfinal.length() - encryption.length());
String decrypted = Encryption.decrypt(key, atest);
System.out.println(decrypted);
}
String sDriverName = "org.sqlite.JDBC";
Class.forName(sDriverName);
String sTempDb = "passwords.db";
String sJdbc = "jdbc:sqlite";
String sDbUrl = sJdbc + ":" + sTempDb;
Connection conn = DriverManager.getConnection(sDbUrl);
String sql = "INSERT INTO information " + "VALUES ("+null+",'"+encryptionfinal+"', '"+username+"', '"+website+"');";
String insert = "CREATE TABLE IF NOT EXISTS 'information' ('id' INTEGER DEFAULT '0' PRIMARY KEY AUTOINCREMENT,'password' TEXT NOT NULL,'username' TEXT NOT NULL,'website' TEXT NOT NULL);";
try {
Statement stmt = conn.createStatement();
stmt.executeUpdate(insert);
stmt.executeUpdate(sql);
stmt.close();
}
finally{
}
return null;
}
The problem with this is when I run it, it says
> LOL FAILURE
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
[B@2b8898c5
[B@2b8898c5syfs8yy48y3483434tg4
[B@2b8898c5
Length Of Byte From Test:
11
Length Of Byte From Key:
16
Length Of String Test:
11
Length Of Encryption:
16
Length Of EncryptionFinal:
31
Length of encryption addon:
20
Length of encryption final - encryption addon:
11
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:913)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
at javax.crypto.Cipher.doFinal(Cipher.java:2121)
at me.thomasjcf21.SecurePassword.Encryption.decrypt(Encryption.java:38)
at me.thomasjcf21.SecurePassword.MySQL.upload(MySQL.java:37)
at me.thomasjcf21.SecurePassword.Program$3.actionPerformed(Program.java:90)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$400(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Please ignore the "LOL Failure" that was a test to see if it was working earlier on.
When you persist real user passwords (which I assume is what you are doing) for authentication you only need to store the password hash, and you should add the salt before the encryption, not after. Bellow is an example with MD5 but there are other algorithms for hash generation avaible for Java.
String saltedPassword = password + salt;
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(saltedPassword .getBytes());
byte byteData[] = md.digest();
A general good practice is to create a individual salt for each user. You never decrypt a hash, you only compare it again when the user inputs the password for validation.
Now, if you are encrypting and storing a password that needs to be retrieved, like a database password, or even for a real user why not, you dont need salt. A symmetric or asymmetric algorithm will be enough. I personally always use AES 256 when I need it, and it is supported by Java as well.
To store and retrieve it properly you will need to encoded the generated bytes returned by the algorith/Java API, and personally I always use Base64 for it.
The official Base64 came in Java 8, but it is avaible in ealier releases as well. You can use Apache implementation if you want too.
Base64.getEncoder().encodeToString(encryptedPasswordArray);
I think this can lead you to solve your problem, but if you have any further questions please let us know.