1

I'm developing a login module with JSP/Servlets/MySQL with the RSA algorithm. Once I register a new user, I save the PublicKey into MySQL and encrypt a password with it.

When the user tries to log-in, I retrieve that PublicKey and encrypt the just-typed-in-password with the corresponding PublicKey and compare it with the previously saved-encrypted-password but it always returns a different cipher text.

I can't figure out why I get different encrypted passwords every time. Is there anything I'm doing wrong? Does it generate a new PublicKey everytime it runs the "keyFactory.generatePublic"?

Thanks for your help

My method to generate a public key is:

    public byte[] generateBytePublicKey() throws Exception {
        byte[] pk = null;

        try {
            final KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);
            keyGen.initialize(1024);
            pk = keyGen.generateKeyPair().getPublic().getEncoded();
        } (...... etc etc)
        return pk;

My method to encrypt a password:

    public byte[] encryptBytes(String pwd, byte[] key) throws Exception {

        byte[] cipherText = null;
        PublicKey pk;

        try {
            byte[] dataBytes = pwd.getBytes();
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            pk = keyFactory.generatePublic(new X509EncodedKeySpec(key));
            final Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pk);
            cipherText = cipher.doFinal(dataBytes);
        } (..... etc etc)
            return cipherText;

My method to store encrypted password and Public Key into a MySQL table:

    (.....................)
    try {
        Statement stmt = null; 
        ResultSet rs = null;
        byte[] bytePublicKey;
        byte[] cipherPwd;

        bytePublicKey = generateBytePublicKey();
        cipherPwd = encryptBytes(password, bytePublicKey);

        String query = "INSERT INTO Users (email, pwd, publickey) VALUES ('" + email + "', ?, ?)";
        PreparedStatement ps;
        ps = conn.getConexion().prepareStatement(query);
        ps.setBytes(1, cipherPwd);
        ps.setBytes(2, bytePublicKey);
        resultSet = ps.executeUpdate();
   } (............. etc etc)

My method for checking if a user is valid:

   public boolean isUserValid (String email, String typedPassword) throws Exception {

    byte[] storedBytesPassword;
    byte[] storedBytesPublicKey;
    byte[] typedPwdtoBytes;

    try {
        storedBytesPublicKey = getByteArrays(email, "publicKey");
        storedBytesPassword = getByteArrays(email, "pwd");

        typedPwdtoBytes = encryptBytes(typedPassword, storedBytesPublicKey);

        return Arrays.equals(typedPwdtoBytes, storedBytesPassword);
   } (............. etc etc)

My method to get the Byte Arrays from the MySQL table:

  public byte[] getByteArrays (String email, String byteArray) throws SQLException {

    (..............)

    try {
        Statement stmt=null; 
        ResultSet rs=null;

        query = "SELECT " + byteArray + " FROM Users WHERE email = '" + email + "'";

        try {
            stmt = (conn.getConexion()).createStatement(); 
            rs = stmt.executeQuery(query);
            while (rs.next() ) {
                bytesArr = rs.getBytes(1);
        } (.................. etc etc)
1
  • 1
    You're generating an RSA key pair only to throw away the private key and essentially make the encryption a one-way street. There are easier alternatives such as using PBKDF2 with a random salt and a lot of iterations. On Information Security: How to securely hash passwords? Commented Nov 7, 2015 at 11:19

1 Answer 1

3

When you don't specify the full transformation, you get the provider defaults, which for RSA is likely RSA/ECB/PKCS1Padding.

PKCS1Padding (see Padding schemes) means that random data is added to ensure that encrypting the same plaintext twice will generate different ciphertext.

Ciphers are for encrypting and decrypting. Since you don't intend to ever decrypt a password, a cipher is not the right choice for you.

For one-way "encryption", use a message digest, also called a Cryptographic hash function. They work like the Java hashCode() method by generating a hash/digest of the plaintext, but unlike hashCode(), a digest is much more complex in order to ensure that the plaintext cannot be inferred from the digest value.

Since it's a one-way algorithm, you can store the key and the digest value together. The purpose of a digest ensure that you're guaranteed to always get the same digest value from the same plaintext/key combination.

You can even use the same key for all passwords. Remember that it's irreversible, as long as the digest algorithm is strong enough, e.g. SHA-256.

Sign up to request clarification or add additional context in comments.

3 Comments

A single invocation of a hash function is not enough for passwords. Schemes like PBKDF2, bcrypt, scrypt should be used in such a case.
Thanks a lot! I got to understand better the encryption world and will redesign my login module.
I found this link after posting answer. Very informative: crackstation.net/hashing-security.htm

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.