Converting plaintext passwords to bycrypt in MySQL and/or java - java

I inherited a project where the passwords are in plaintext in a table in the db. If I was converting to MD5 I'd just do something like
UPDATE users SET encrypted_password = MD5(password);
I'm using the java BCrypt class instead of MD5. The table has ~3 million users. Is there a optimal way to bcrypt each plaintext password into the new 'encrypted_password' column.
The only way I can think of is to loop through a ResultSet of each user, SELECT the plaintext password, bcrypt it, and then UPDATE the row. Something tells me this will take half an eternity. Anything quicker?

I think it might be the only way, and it did take forever, but I ended up just writing a simple class to iterate through each row and BCrypt the plaintext password and store it. Just for sanity, I checked if the match was good after BCrypting: I never got any mismatches. The Encryption class is just a fragment of an actual class I'm using with a lot of other encryption methods, I just included the relevant methods for clarity. If it helps anyone, here's the code:
public class Bcrypter {
public static void main(String args []) {
int lower = Integer.parseInt(args[0]);
int upper = Integer.parseInt(args[1]);
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
int row = 0;
try {
conn = Database.getConnection();
pstmt = conn.prepareStatement("SELECT id, user_pass, user_pass_bcrypt FROM users ORDER BY id LIMIT ?, ?",
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
pstmt.setInt(1, lower);
pstmt.setInt(2, upper);
rs = pstmt.executeQuery();
while (rs.next()) {
String user_pass = rs.getString("user_pass");
String user_pass_encrypted = Encryption.encrypt(user_pass);
if (Encryption.isMatch(user_pass, user_pass_encrypted)) {
rs.updateString("user_pass_bcrypt", user_pass_encrypted);
rs.updateRow();
if (++row % 10000 == 0) {
System.out.println(row);
}
} else {
System.out.println("Mismatch " + user_pass);
}
}
System.out.print("DONE");
} catch (SQLException e) {
e.printStackTrace();
System.out.print(e);
} finally {
Database.closeConnection(conn, pstmt, rs);
}
}
}
public final class Encryption {
private Encryption() {
// can't instantiate
}
/**
* Encrypts a password. The gensalt() method's default param is
* 10 but it's lowered here, assuming better performance.
*/
public static String encrypt (String plainPassword) {
return BCrypt.hashpw(plainPassword, BCrypt.gensalt(5));
}
/**
* Checks whether a plaintext password matches one that has been
* hashed previously
*/
public static Boolean isMatch(String plainPassword, String hashedPassword) {
return (BCrypt.checkpw(plainPassword, hashedPassword));
}
}

Related

Can I use setMaxRows() with try-with-resouces?

I am attempting to write a method that selects 2 entries into an employee database and removes them (Based on a salary field), I am currently using a counter to accomplish this, however I tried using setMaxRows() so my result set would only have two entries, thus eliminating the need for the counter. I am using try-with-resources to create my statement and that seems to be causing an issue.
public void downSize(Connection con) {
String sql = "SELECT * FROM " + schemaName + "."+tableName+" WHERE EMPLOYEE_SALARY>200000";
try (
PreparedStatement statement = con.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = statement.executeQuery();
)
{
int counter = 0;
System.out.println("Now pruning workforce...");
while(rs.next() && counter<2) {
String name = rs.getString("EMPLOYEE_NAME");
rs.deleteRow();
counter++;
System.out.println(name+" was laid off.");
}
} catch(Exception e) {
e.printStackTrace();
System.out.print("Sql exception happened");
}
}

Printing a query from a database

I am trying to access a database and print off a query.
I am trying to access a DEVICE table and print off the DEVICE_ID, but i am unsuccessful so far.
Here is my code at the moment;
public static void main(String[] args) throws FileNotFoundException {
try {
Class.forName("org.hsqldb.jdbc.JDBCDriver");
Preferences sysRoot = Preferences.systemRoot();
Preferences prefs = sysRoot.node("com/davranetworks/zebu");
url = prefs.get("dburl", "jdbc:hsqldb:E:\\eem\\eemdb");
} catch (Exception e) {
e.printStackTrace();
}
Connection c = getConnection();
try {
c.setAutoCommit(true);
Statement s = c.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = s.executeQuery("SELECT * FROM eem_db.device");
ResultSet deviceId = s.executeQuery("select device_id from eem_db.device");
System.out.println(deviceId);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
Connection c = null;
try {
c = DriverManager.getConnection(url);
} catch (SQLException e) {
System.out.println("Error initialising connection" + e);
}
return c;
}
The returned value is org.hsqldb.jdbc.JDBCResultSet#1d3d68df.
I don't know what this value relates to as I was expecting 3 integer values.
Can anyone help me on this?
You have to iterate over the rows contained in the ResultSet and for each row get the column you want:
ResultSet deviceIdRS = s.executeQuery("select device_id from eem_db.device");
while(deviceIdRS.next()) {
System.out.println(deviceIdRS.getString("device_id"));
}
You must use the ResultSet getXXX method that correspond with your column type, for example, getInt, getString, getDate...
That ResultSet deviceId is actually an object contains rows of result from your sql, so you only can see the memory address when you print it out.
You need something like:
while(deviceId.next()){
System.out.print(deviceId.getInt(1));
}
s.executeQuery("select device_id from eem_db.device"); is returning a resultSet, you must find out the value from result set.
like
int device_id = resultset["deviceId"];
while (deviceId.next())
{
// Printing results to the console
System.out.println("device_id- "+ deviceId.getInt("device_id");
}
iterate object using resultset.
You are printing object of ResultSet, it won't give you the right values.
You need to iterate the loop like below
while(deviceId.next()) {
int integerValue = deviceId.getInt(1);
System.out.println("content" + integerValue)
}
deviceId.close();
s.close();

Encrypting password causes MySQL unknown column in 'where clause' [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
OK so I am trying to create user authentication for a little Java project of mine and I've run into a bit of a road block.
I have a table called user_info with 3 columns; id, user and password.
I realized that I should probably have some form of encryption, so I used Java's MessageDigest to encrypt the password with SHA1. Since I don't yet have a website for people to register (and have PHP enter the encrypted PW into the database), I simply encrypted a test password and replaced the unencrypted password in the database with the encrypted one.
For example, a user with username test and password test has an encrypted password of:
895df4f75b316de68d167ed2e83adb0bedbbde17
So my database has an entry with id 0, user test and password 895df4f75b316de68d167ed2e83adb0bedbbde17.
Now my Java code to check if the person provided valid details had no issue until I started using encrypted passwords.
Here is the login code for my Java application:
public int doLogin(String username, String pass) {
EncryptionHandler e = new EncryptionHandler();
String userToLogIn = username;
String userToLogInPassword = pass;
try {
String fixedUser = prepString(userToLogIn);
String fixedPass = e.doEncryptPassword(prepString(userToLogInPassword));
System.out.println(fixedPass);
con = DriverManager.getConnection(url, user, password);
st = con.createStatement();
rs = st.executeQuery("SELECT * FROM `user_info` WHERE `user` = " + fixedUser + " AND `password` = " + fixedPass);
if (rs.next()) {
//System.out.println("ID: " + rs.getString(1) + ", USER: " + rs.getString(2) + ", PASSWORD: " + rs.getString(3));
return 1;
} else {
System.out.println("Username or password is invalid!");
return 0;
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
} finally {
try {
if (rs != null) {
rs.close();
}
if (st != null) {
st.close();
}
if (con != null) {
con.close();
}
} catch (SQLException ex) {
}
}
return 0;
}
private String prepString(String s) {
return new StringBuilder().append("'").append(s).append("'").toString();
}
and in case it's needed, my encryption method:
public String doEncryptPassword(String s) {
MessageDigest sha1;
try {
sha1 = MessageDigest.getInstance("SHA1");
byte[] digest = sha1.digest((s).getBytes());
return bytes2String(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return s;
}
private static String bytes2String(byte[] bytes) {
StringBuilder string = new StringBuilder();
for (byte b : bytes) {
String hexString = Integer.toHexString(0x00FF & b);
string.append(hexString.length() == 1 ? "0" + hexString : hexString);
}
return string.toString();
}
Again, using unencrypted passwords works just fine, but as soon as I encrypt the password I get the unknown column error. In this example (user test, password test), passing the unencrypted password receives no error, but using the encrypted password 895df4f75b316de68d167ed2e83adb0bedbbde17 provides me the error:
Unknown column '895df4f75b316de68d167ed2e83adb0bedbbde17' in 'where clause'
Ignoring that this isn't encryption, you have invalid SQL because of quoting problems. As #Leigh notes in the comments, you put quotes at the beginning and end of your password string ... then hash it. Your quotes are now dearly departed.
Of course you should never create SQL like this in the first place. Use prepared statements -> Oracle Prepared Statements Tutorial
Get rid of any of your own home-grown string quoting then simply do:
String sqlString = "SELECT * FROM user_info WHERE user = ? AND password = ?";
PreparedStatement ps = con.prepareStatement(sqlString);
ps.setString(1, username);
ps.setString(2, hashedPassword);
ResultSet rs = ps.executeQuery();
You need to do your prepString thingy as well for the password:
String fixedPass = prepString(e.doEncryptPassword(userToLogInPassword));
But it isn't a good idea to build statements this way.
Use prepared statements.

getting text from password field

Hello I am trying to create a login form in java netbeans IDE. My aim is to create multiple user ID's and their respective passwords. I have given textfields to userID and passwordField for passwords to get the values but the problem is i want to get the text from the password field and i am unable to get it its showing some error i think there is some problem with syntax my research is as follows can there be any solution? Need your help
private void lb_loginMouseClicked(java.awt.event.MouseEvent evt) {
DBUtil util = new DBUtil();
String value1=tb_uid.getText();
String value2=tb_pwd.getPassword();
String user1="";
String pass1="";
try {
Connection con = util.getConnection();
PreparedStatement stmt = con.prepareStatement("SELECT * FROM login where username='"+value1+"' && password='"+value2+"'");
ResultSet res = stmt.executeQuery();
res = stmt.executeQuery();
while (res.next()) {
user1 = res.getString("username");
pass1 = res.getString("password");
}
if (value1.equals(user1) && value2.equals(pass1)) {
JOptionPane.showMessageDialog(this,"correct");
}
else{
JOptionPane.showMessageDialog(this,"Incorrect login or password","Error",JOptionPane.ERROR_MESSAGE);
}
JOptionPane.showMessageDialog(null, "COMMITED SUCCESSFULLY!");
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, ex.getMessage());
}
}
String pwd = new String(jPasswordField1.getPassword());
Option 1:
jTextField1.setText(""+pwd);
Option 2:
System.out.println(""+pwd);
Use this code:
String password = String.valueOf(jPasswordField.getPassword());
The JPasswordField is encrypted but if you use String.valueOf it will converted Char to String.
value2 is char array so doing String concatenation would result in the String representation of the array rather then the String content itself ending up in the SQL. You could replace
PreparedStatement stmt = con.prepareStatement("SELECT * FROM login where username='"+value1+"' && password='"+value2+"'");
with
PreparedStatement stmt = con.prepareStatement("SELECT * FROM login where username='"+value1+"' AND password='" + new String(value2) + "'");
Similarly
if (value1.equals(user1) && value2.equals(pass1)) {
would need to be
if (value1.equals(user1) && pass1.equals(new String(value2)) {
Better use the PreparedStatement placeholders however, to protect against SQL injection attack:
PreparedStatement stmt = con.prepareStatement("SELECT * FROM login where username=? AND password=?);
stmt.setString(1, value1);
stmt.setString(2, new String(value2));
Note: This is not a secure way do to a password lookup, a hashed comparison would be relatively safer.
From http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/String.html#equals%28java.lang.Object%29:
equals
public boolean equals(Object anObject)
Compares this string to the specified object. The result is true if
and only if the argument is not null and is a String object that
represents the same sequence of characters as this object.
Your code:
char[] value2=tb_pwd.getPassword();
...
String pass1="";
...
...&& value2.equals(pass1)...
Seems like you'd want to convert your char array into String then retry the conversion. If you're still getting an error please post it along with relevant input so we can see what is being received.
You want to convert your char[] to a String. When you envoke tb_pwd.getPassword() a char[] (character array) is returned. If you want to compare this password you must convert it to a String, and for this you can use this method:
String final_pass = "";
for(char x : passwordAsChar[]) {
final_pass += x;
}
As for comparing passwords in databases you should never store them in plain-text, unencrypted. You could store an MD5 string in your database, and the convert your password inputted by the user to a String, and then envoke the following method on it. Then compare the returned String with the one from the database. If they match, the user has entered a correct password.
Example:
char[] pass = tb_pwd.getPassword();
String final_pass = "";
for (char x : pass) {
final_pass += x;
}
String md5_encrypted_pass_userInput = encrypt(final_pass);
if (md5_encrypted_pass.equals(pass1)) { /* pass1 = the password from the database */
// Correct password
}
A method to use for encrypting Strings to MD5 is:
public static final String encrypt(String md5) {
try {
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
byte[] array = md.digest(md5.getBytes());
StringBuffer sb = new StringBuffer();
for (int i = 0; i < array.length; ++i) {
sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1,3));
}
return sb.toString();
} catch (java.security.NoSuchAlgorithmException e) {}
return null;
}

Using PreparedStatement template issue

Here's my static utility:
//String sqlQuery = "select count(name) as num from tbname where name = ?"
//String name = "testString";
private static int correct(Connection connection, String sqlQuery, String name) {
int result = 0;
PreparedStatement statatement = null;
ResultSet rs = null;
try {
statatement = connection.prepareStatement(sqlQuery);
statatement.setString(1, name);
rs = statatement.executeQuery();
while (rs.next()) {
result = rs.getInt("num");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
rs.close();
statatement.close();
} catch (SQLException e) {
throw new RuntimeException(e.getMessage());
}
return result;
}
}
The method above returns 0 (incorrect result), but the following one returns '1' (it works OK, it the same sql query):
//String sqlQuery = "select count(name) as num from tbname where name = 'testString'"
private static int correct(Connection connection, String sqlQuery, String name) {
int result = 0;
PreparedStatement statatement = null;
ResultSet rs = null;
try {
statatement = connection.prepareStatement(sqlQuery);
rs = statatement.executeQuery();
while (rs.next()) {
result = rs.getInt("num");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
rs.close();
statatement.close();
} catch (SQLException e) {
throw new RuntimeException(e.getMessage());
}
return result;
}
}
Could you please give me any advise, so I could resolve the problem.
PS: I'm not sure if it does matter, but the actual streetName - has a name in windows-1251 encoding (Russian) text.
PPS: The database is Oracle 10.
It might be a character set issue. According to the Oracle JDBC Drivers release 10.1.0.2.0 (10g) README:
The following is a list of known
problems/limitations:
If the database character set is AL32UTF8, you may see errors under the
following circumstances:
accessing LONG and VARCHAR2 datatypes.
binding data with setString() and setCharacterStream().
So if your database character set is AL32UTF8, you might have to get it changed to something else.
Also, what is the datatype of your column? VARCHAR2?
It seems the encoding conflict with the one which you set in your DB encoding charset and the the String you are passing..
You can do these 2 tries
Set the DB encoding to UTF-8 and then give a try. If this does not work you may go with following 2nd option
Set DB encoding charset to UTF-8 and also set the String by using this String constructor String(byte[] bytes, String charsetName)

Categories