4

这更像是我做错了什么而不是关键任务的练习,但我仍然想看看我犯了什么(可能很简单)错误。

我正在使用 mysql (5.1.x) AES_ENCRYPT 来加密字符串。我正在使用 CF 的 generateSecretKey('AES') 来制作密钥(我已经尝试过默认为 128 和 256 位长度)。

因此,假设我的代码如下所示:

    <cfset key = 'qLHVTZL9zF81kiTnNnK0Vg=='/>
    <cfset strToEncrypt = '4111111111111111'/>
    <cfquery name="i" datasource="#dsn#">
        INSERT INTO table(str) 
            VALUES AES_ENCRYPT(strToEncrypt,'#key#');
    </cfquery>

这可以正常工作,我可以使用 SELECT AES_DECRYPT(str,'#key#') AS... 选择它,完全没有问题。

我似乎无法做的是让 CF 使用以下方法对其进行解密:

    <cfquery name="s" datasource="#dsn#">
        SELECT str
          FROM table
    </cfquery>
    <cfoutput>#Decrypt(s.str,key,'AES')#</cfoutput>

或者

    <cfoutput>#Decrypt(toString(s.str),key,'AES')#</cfoutput>

我不断收到“输入和输出编码不同”(包括 toString() - 否则我会收到二进制数据错误)。db 中加密字符串的字段类型是 blob。

4

1 回答 1

5

此条目说明 mySQL 处理 AES-128 密钥的方式与您预期的略有不同:

.. 如果密码长于 16 个字符,MySQL 算法只是给定密码短语的字节与前一个字节,当密码短于 16 个字符时,将它们保留为 0。

没有经过高度测试,但这似乎产生了相同的结果(以十六进制表示)。

<cfscript>
    function getMySQLAES128Key( key ) {
        var keyBytes   = charsetDecode( arguments.key, "utf-8" );
        var finalBytes = listToArray( repeatString("0,", 16) );

        for (var i = 1; i <= arrayLen(keyBytes); i++) {
            // adjust for base 0 vs 1 index
            var pos = ((i-1) % 16) + 1;
            finalBytes[ pos ] = bitXOR(finalBytes[ pos ], keyBytes[ i ]);
        }

        return binaryEncode( javacast("byte[]", finalBytes ), "base64" );
    }

    key     = "qLHVTZL9zF81kiTnNnK0Vg==";
    input   = "4111111111111111";

    encrypted = encrypt(input, getMySQLAES128Key(key), "AES", "hex");
    WriteDump("encrypted="& encrypted);

    // note: assumes input is in "hex". either convert the bytes 
    // to hex in mySQL first or use binaryEncode
    decrypted = decrypt(encrypted, getMySQLAES128Key(key), "AES", "hex");
    WriteDump("decrypted="& decrypted);
</cfscript>

注意:如果您使用 mySQL 进行加密,请务必查看其文档,其中提到纯文本可能会出现在各种日志中 (复制、历史记录等),并且“任何人都可以读取该信息”。


更新:事情可能已经改变,但根据这个 2004 年的错误报告,该.mysql_history文件仅在 Unix 上。(记住可能还有其他日志文件)清除.mysql_history的详细说明可以在手册中找到,但总结如下:

  • MYSQL_HISTFILE变量设置为 /dev/null(在每次登录时)
  • 创建 .mysql_history 作为 /dev/null 的符号链接(仅一次)
于 2012-06-07T06:10:01.957 回答