我正在用JSP/Servlets/MySQL和RSA算法开发一个登录模块。注册新用户后,我将公钥保存到MySQL中并用它加密密码。
当用户尝试登录时,我检索该公钥并用相应的公钥加密刚刚键入的密码,并将其与先前保存的加密密码进行比较,但它总是返回不同的密码文本。
我不明白为什么每次我都得到不同的加密密码。我做错什么了吗?它是否每次运行“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)

最佳答案

当您不指定完整的转换时,您将得到提供者的默认值,对于RSA来说,这很可能RSA/ECB/PKCS1Padding
PKCS1Padding(参见Padding schemes)意味着添加随机数据以确保对同一明文加密两次将生成不同的密文。
密码用于加密和解密。因为你不打算解密密码,所以密码对你来说不是正确的选择。
对于单向“加密”,请使用message digest,也称为Cryptographic hash function。它们的工作方式与JavahashCode()方法类似,通过生成纯文本的散列/摘要,但是与hashCode()不同,摘要要复杂得多,以确保不能从摘要值推断出纯文本。
因为它是单向算法,所以可以将密钥和摘要值存储在一起。摘要的目的是确保始终从相同的纯文本/键组合中获得相同的摘要值。
您甚至可以对所有密码使用相同的密钥。记住它是不可逆的,只要摘要算法足够强大,例如SHA-256

10-08 20:09