2015-11-07 4 views
0

Я разрабатываю модуль входа в систему с помощью JSP/Servlets/MySQL с алгоритмом RSA. Как только я зарегистрирую нового пользователя, я сохраняю PublicKey в MySQL и шифрую с ним пароль.Java RSA, почему каждый раз зашифрованный текст?

Когда пользователь пытается войти в систему, я извлекаю этот PublicKey и шифрую только что введенный пароль с соответствующим PublicKey и сравниваю его с ранее сохраненным зашифрованным паролем, но он всегда возвращает другой шифрованный текст ,

Я не могу понять, почему я получаю разные зашифрованные пароли каждый раз. Есть ли что-то, что я делаю неправильно? Создает ли он новый PublicKey каждый раз, когда он запускает «keyFactory.generatePublic»?

Спасибо за вашу помощь

Мой метод для создания открытого ключа является:

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; 

Мой метод шифрования пароля:

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; 

Мой метод хранить зашифрованный пароль и открытый ключ в таблице MySQL:

(.....................) 
    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) 

Мой метод для проверки, если пользователь является действительным:

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) 

Мой метод, чтобы получить массив байтов из MySQL таблицы:

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) 
+0

Вы генерируете пару ключей RSA только для того, чтобы выбросить закрытый ключ и по существу сделать шифрование улицей с односторонним движением. Существуют более простые альтернативы, такие как использование PBKDF2 со случайной солью и много итераций. На [security.se]: [Как безопасно использовать хэш-пароли?] (http://security.stackexchange.com/q/211/45523) –

ответ

1

Когда ты не указывайте полное преобразование, вы получаете настройки поставщика по умолчанию, что для RSA, вероятно, RSA/ECB/PKCS1Padding.

PKCS1Padding (см. Padding schemes) означает, что случайные данные добавляются для обеспечения того, чтобы шифрование одного и того же открытого текста дважды создавало другой зашифрованный текст.

Шифры предназначены для шифрования и дешифрования. Поскольку вы не собираетесь расшифровывать пароль, шифр не подходит для вас.

Для одностороннего шифрования используйте message digest, также называемый Cryptographic hash function. Они работают подобно методу Java hashCode(), создавая хэш/дайджест открытого текста, но в отличие от hashCode(), дайджест намного сложнее, чтобы гарантировать, что открытый текст не может быть выведен из значения дайджеста.

Поскольку это односторонний алгоритм, вы можете хранить ключ и значение дайджеста вместе. Цель дайджеста гарантирует, что вам гарантировано всегда получать одно и то же значение дайджест из той же комбинации открытого текста/ключа.

Вы можете использовать один и тот же ключ для всех паролей. Помните, что это необратимо, если алгоритм дайджеста достаточно силен, например. SHA-256.

+0

Для паролей недостаточно одного вызова хэш-функции. Схемы, такие как PBKDF2, bcrypt, scrypt, должны использоваться в таком случае. –

+0

Спасибо большое! Я должен лучше понять мир шифрования и перепроектировать мой модуль входа. –

+0

Я нашел эту ссылку после отправки ответа. Очень информативно: https://crackstation.net/hashing-security.htm – Andreas

Смежные вопросы