AES_DECRYPT不能在linux上运行:可能与Hibernate有关

时间:2015-01-16 16:23:02

标签: java mysql hibernate aes environment

我在我的数据库中加密了数据,我正在尝试执行一个请求,该请求允许我在phpmyadmin中以明文显示值。

我使用以下请求:

 SELECT CAST(AES_DECRYPT(`my_encrypted_colum`, UNHEX('pass_in_hexa') AS CHAR) AS clear_value 
 FROM `my_table`

当我在开发环境(windows)上使用它时,运行良好。但是一旦我在pre-prod环境(linux)上使用它,我会为所有值获得 NULL

我很确定它与不同的环境有关,但我无法弄清楚是什么。我甚至不知道哪个功能没有按预期运行:UNHEX或AES_DECRYPT(我的猜测是UNHEX)?

以下是我的dev和preprod环境的配置:

开发

Serveur : localhost via TCP/IP
Type de serveur : MySQL
Version du serveur : 5.6.15-log - MySQL Community Server (GPL)
Version du protocole : 10
Utilisateur : root@localhost
Jeu de caractères du serveur : UTF-8 Unicode (utf8)

Apache/2.2.25 (Win32) PHP/5.3.19
Version du client de base de données : libmysql - mysqlnd 5.0.8-dev -     20102224 - $Id: 65fe78e70ce53d27a6cd578597722950e490b0d0 $
Extension PHP : mysqli 

Preprod

Serveur: Localhost via UNIX socket
Logiciel: MySQL
Version du logiciel: 5.6.14 - MySQL Community Server (GPL)
Version du protocole: 10
Utilisateur: root@localhost
Jeu de caractères du serveur: UTF-8 Unicode (utf8)

Apache/2.2.15 (CentOS)
Version du client de base de données: libmysql - 5.1.72
Extension PHP: mysqli 

编辑

我继续我的研究,它接缝方法AES_DECRYPT和UNHEX 无罪。 实际上,如果我直接在phpMyAdmin表中添加加密值,如下所示:

 INSERT INTO `my_table` (`my_encrypted_column`) VALUES (AES_ENCRYPT('blabla', UNHEX('pass_in_hexa'))

然后我设法使用之前的SELECT请求检索正确数据。

这意味着问题必须来自我首先插入数据的方式。 为此,我使用 Hibernate 和nullSafeSet方法。

困扰我的是:如果我保存数据的方式有问题,那么在Windows上工作但在Linux上工作怎么样?

以下是我的nullSafeSet和nullSafeGet

的实现
private static final String CIPHER_ALGORITHM = "AES";

// nullSafeSet
protected void noNullSet(PreparedStatement st, Object value, int index, SessionImplementor si) throws SQLException {
    byte[] clearText = ((String) value).getBytes(Charset.forName("UTF-8"));

    try {
        Cipher encryptCipher = Cipher.getInstance(CIPHER_ALGORITHM);
        encryptCipher.init(Cipher.ENCRYPT_MODE, getKey(cle));
        st.setBytes(index, encryptCipher.doFinal(clearText));
    } 
    catch (GeneralSecurityException e) {
        throw new RuntimeException("should never happen", e);
    }
}

@Override
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor si, Object owner) throws HibernateException, SQLException {
    byte[] bytes = rs.getBytes(names[0]);
    try {
        Cipher decryptCipher = Cipher.getInstance(CIPHER_ALGORITHM);
        decryptCipher.init(Cipher.DECRYPT_MODE, getKey(cle));
        if (bytes != null) {
            return new String(decryptCipher.doFinal(bytes), Charset.forName("UTF-8"));
        } 
        else {
            return new String();
        }

    } 
    catch (GeneralSecurityException e) {
        throw new RuntimeException("Mauvaise clé");
    }
}

private static SecretKeySpec getKey(String secretKey) {
    final byte[] finalKey = new byte[16];
    int i = 0;
    for (byte b : secretKey.getBytes()) {
        // XOR
        finalKey[i++ % 16] ^= b;
    }
    return new SecretKeySpec(finalKey, "AES");
}

您知道可能导致问题的原因吗?

4 个答案:

答案 0 :(得分:1)

我认为您的系统之间可能存在链接/填充差异,因为未明确设置它们。尝试

private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";

用于获取Cipher实例,因为它应该是MySql使用的实现here

如果你的密码短于8个字符(字节),mysql会使用自己的实现,根据建议从中生成AES 128位密钥 here。它可能与密钥Java在密码短于8个字节时使用的密钥不同。

答案 1 :(得分:1)

检查:

  • 如果您在这些数据库中有相同的数据。从您的开发人员连接到preprod数据库并检查它是否有效。从preprod连接到您的开发数据库并检查它是否有效。这样你就可以缩小问题范围:db vs environment
  • jvm加密权限。也许你的开发jvm可以使用强加密而preprod不能
  • 区分大小写:一些DB(不确定mysql)在文件中存储表。 windows不区分大小写,linux不是。我在过去看到过类似的问题

答案 2 :(得分:1)

您可能遇到字符集问题。如果您的某个MySQL数据库使用latin1字符集运行,则插入UTF-8数据将导致数据混乱。

要检查相关表格上的字符集,请在两个系统上运行此命令:

mysql> show create table foo
| foo | CREATE TABLE `foo` (
  `FLD1` int(11) DEFAULT NULL,
  `FLD2` int(11) DEFAULT NULL,
  `FLD3` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 |

它将显示该特定表正在使用的字符集。如果它不是UTF8,那么它就不会与您的代码匹配,您将遇到数据损坏问题。

如果这实际上是问题,您可以通过运行ALTER语句来更改字符集,如下所示:

ALTER TABLE foo CONVERT TO CHARACTER SET utf8

答案 3 :(得分:0)

所以我终于设法指出了问题所在。

在应用程序启动时,我将密钥存储在Configuration对象中。密钥存储为字符串,执行String cle = new String(key.getEncoded());

这在Windows上工作正常,并按照键返回:

*£Ðtôµ•Ã

但是在Linux上,特殊字符没有正确投射

*��t����

这导致加密/解密在linux上使用错误的密钥完成,因此我无法使用"更正"做" SELECT"时的关键值在MySQL中