【问题标题】:Coldfusion ENCRYPT and MySQL AES_DECRYPT Working together?Coldfusion ENCRYPT 和 MySQL AES_DECRYPT 一起工作?
【发布时间】:2013-05-16 06:44:00
【问题描述】:

我正在使用 ColdFusion 9 和 MySQL 5.1。我正在尝试对齐 ColdFusion 加密/解密函数和 mySQL AES_ENCRYPT/AES_DECRYPT,以便我可以根据情况互换使用它们。没有太多运气。

首先我用 ColdFusion 创建了一个 AES 字符串:

    <cfset theKey = generateSecretKey("AES") />
    <cfoutput>#theKey#</cfoutput>

示例键:4OFWUiuqFEkGrSRFm8sLlg==

我使用此密钥与 MySQL 进行加密。注意,encrypt_test 是现有表,fld 是 varchar 列。

    INSERT INTO encrypt_test 
    SET fld = aes_encrypt('the text to encrypt', '4OFWUiuqFEkGrSRFm8sLlg==')

接下来我尝试用 ColdFusion 解密:

    <cfset theKey = "4OFWUiuqFEkGrSRFm8sLlg=="
    <cfset theAlgorithm  = "AES" />

然后运行cfquery获取数据(表中只有1条记录),

    <cfquery name="testDecrypt">
        SELECT fld FROM encrypt_test
    </cfquery`

最后解密

    <cfoutput>#Decrypt(testDecrypt.fld, theKey, theAlgorithm)#</cfoutput>

这会产生Null。我怀疑它是填充问题或其他一些不匹配,有人知道我做错了什么,或者如何使它工作?

【问题讨论】:

    标签: mysql encryption coldfusion


    【解决方案1】:

    我知道这个帖子很旧,但答案出现了on a recent thread。所以我将它发布给后代。作为explained in this blog entry,产生差异的原因是:

    .. MySQL 算法只是或是给定密码的字节 如果密码长于 16 个字符,则针对前面的字节,并且 当密码短于 16 个字符时,将它们保留为 0。

    因此,您需要对键值执行相同的操作,然后再将其传递给encrypt/decrypt

    【讨论】:

      【解决方案2】:

      我会坚持只使用 CF 的功能。通过这种方式,您可以添加各种安全流程层,包括迭代和多个密钥等内容,从而轻松构建自定义解决方案。它增加的开销也并不多。

      【讨论】:

      • 这就是我想做的,但是这使得在数据库中的加密字段上使用 WHERE 或 ORDER BY 子句进行简单查询成为问题。我必须获取所有记录,然后对结果进行 QofQ。处理数万条记录时效率不高。
      • 无论您使用什么,我都无法想象加密数以万计的值是有效的。但这个要求听起来有点奇怪。您认为需要解密以进行过滤的内容是什么?
      • 我需要加密一个现有的客户数据库(不是所有的表和字段,但它们可能包含 40k - 50k 条记录),我必须能够对其执行 WHERE 子句。我需要解密 where 子句中的字段: WHERE AES_DECRYPT(fld, key) = 'some value'
      • 通常你不会仅仅为了过滤而解密(),因为它通过以纯文本发送数据来降低安全性。您还可以阅读有关加密函数的 mySQL 文档,并了解此警告是否也适用于 AES 函数:“...可能最终记录在服务器日志或历史文件(如 ~/.mysql_history)中,这意味着任何有权读取该信息的人都可以读取明文密码。” dev.mysql.com/doc/refman/5.5/en/encryption-functions.html
      • Leigh,好点,谢谢!没有仔细阅读这个,这是一个问题。我将在 CF 中进行加密/解密,并尽可能避免加密 ORDER BY 字段。还要感谢 Bob。
      【解决方案3】:

      为什么不使用 ColdFusion 的加密功能来代替 MySQL 的呢?

      事实上,这是测试问题所在的一种方法:尝试同时输出数据库中的加密值以及 CF 的加密函数会产生什么,看看它们是否相同。

      或者,只需在查询中使用 aes_decrypt 函数,而不是使用 ColdFusion 的解密。

      嗯,来自docs

      由于 AES 是块级算法,填充用于编码不均匀长度的字符串,因此可以使用以下公式计算结果字符串长度:

      16 * (trunc(string_length / 16) + 1)

      如果 AES_DECRYPT() 检测到无效数据或错误填充,则返回 NULL。

      所以假设 CFML 不做那个填充,你必须自己找出相反的东西。

      【讨论】:

        【解决方案4】:

        我知道这是一篇相当老的帖子,但你应该这样做:

        在存储到数据库之前:

        <cfset crypt_fld = #encrypt('the text to encrypt', thekey, 'AES')#>
        

        然后:

        INSERT INTO encrypt_test 
        SET fld = crypt_fld
        

        它对我有用

        【讨论】:

          【解决方案5】:

          使用jBCrypt :: bCrypt 是可用的最强大的加密......在 Mark Mandel 的 Fantastic JavaLoader 的帮助下 在 ColdFusion 中实现 jBCrypt 是一件轻而易举的事……

          就密码字段而言,您使用哪种数据库实际上并不重要...如果您也处理语言环境支持,该字段可能是 varchar(60) 或 nvarchar(60)。 .

          <cfcomponent title="bcrypt (strong; recommended)" hint="I encode passwords using a popular secure password hashing algorithm called bcrypt. I am very slow, but that makes me very secure!" extends="PasswordHash"
          alias="bcrypt" seq="9001" workFactor="10">
          
          <cfset variables.loadPaths = [expandPath( "/PATHTOLIBDIR/lib/jbcrypt/jbcrypt-0.3m.jar" )]/>
          
          <cffunction name="init" access="public" output="true" returntype="any" hint="constructor">
          
              <cfset super.init( )/>
          
              <!--- Allow java loader to fail silently: we can report the failure via isAvailable() --->
              <cftry>
                  <cfset variables.oBCryptClass = createJavaClass( "org.mindrot.jbcrypt.BCrypt" )/>
                  <cfcatch></cfcatch>
              </cftry>
          
              <cfreturn this/>
          </cffunction>
          
          <cffunction name="isAvailable" hint="Is the hashing agorithm available in this environment?" access="public" returntype="boolean">
              <cfreturn structKeyExists( variables, "oBCryptClass" )/>
          </cffunction>
          
          <cffunction name="matchesHashFormat" hint="Does the string match the format for this hash?" access="public" returntype="boolean">
              <cfargument name="input" type="string" hint="String that may be a password hash" required="true"/>
          
              <cfreturn REFind( "^\$2a\$\d+\$[\./A-Za-z0-9]+$", arguments.input )/>
          </cffunction>
          
          <cffunction name="encode" hint="Convert a clear password to its encoded value" access="public" returntype="string">
              <cfargument name="password" type="string" hint="Input password" required="true"/>
          
              <cfset var salt = variables.oBCryptClass.gensalt( JavaCast( "int", this.workFactor ) )/>
              <cfreturn variables.oBCryptClass.hashpw( arguments.password, salt )/>
          </cffunction>
          
          <cffunction name="getHashWorkFactor" hint="Retrieve the work factor from a hashed string" access="public" returntype="numeric">
              <cfargument name="hashedPassword" type="string" hint="Previously encoded password string" required="true"/>
          
              <cfset var stMatch = ReFind( "^\$2a\$(\d+)\$([\./A-Za-z0-9]+)$", arguments.hashedPassword, 1, "true" )/>
              <cfif stMatch.pos[1] eq 0>
                  <cfreturn 0>
                  <cfelse>
                  <cfreturn mid( arguments.hashedPassword, stMatch.pos[2], stMatch.len[2] )>
              </cfif>
          </cffunction>
          
          <cffunction name="passwordMatch" hint="Compare a plain password against an encoded string" access="public" returntype="boolean">
              <cfargument name="password" type="string" hint="Input password" required="true"/>
              <cfargument name="hashedPassword" type="string" hint="Previously encoded password string" required="true"/>
              <cfargument name="bCheckHashStrength" type="boolean" default="false" hint="If true, the hash strength of the hashed password must also match those generated by encode()"/>
          
              <cfset var bMatch = variables.oBCryptClass.checkpw( arguments.password, arguments.hashedPassword )/>
          
              <cfif bMatch and bCheckHashStrength>
                  <!--- Hash matched but we also need to match the bCrypt work factor --->
                  <cfreturn getHashWorkFactor( arguments.hashedPassword ) eq this.workFactor/>
                  <cfelse>
                  <cfreturn bMatch/>
              </cfif>
          </cffunction>
          

          PasswordHash.cfc ...

          <cfcomponent hint="I am an abstract component for encoding passwords for storage and comparing passwords against previously encoded strings">
          
          <!--- Array of Java class paths required for this component. Leave empty if no special Java libraries are needed. --->
          <cfset variables.loadPaths = []/>
          
          <cffunction name="init" access="public" output="true" returntype="any" hint="constructor">
          
              <cfset var stMetadata = getMetadata( this )/>
              <cfset var attr = ""/>
          
              <cfloop condition="not structisempty(stMetadata)">
                  <!--- Get attributes --->
                  <cfloop collection="#stMetadata#" item="attr">
                      <cfif issimplevalue( stMetadata[attr] ) and not listcontains( "bindingname,extends,fullname,functions,hint,name,namespace,output,path,porttypename,serviceportname,style,type,wsdlfile", attr ) and not structkeyexists( this, attr )>
                          <cfset this[attr] = stMetadata[attr]/>
                      </cfif>
                  </cfloop>
          
                  <!--- Do the same for ancestors --->
                  <cfif structkeyexists( stMetadata, "extends" )>
                      <cfset stMetadata = stMetadata.extends/>
                      <cfelse>
                      <cfset stMetadata = structnew( )/>
                  </cfif>
              </cfloop>
          
              <cfset stMetadata = getMetadata( this )/>
          
              <!--- If key isn't specified, use the name of the component --->
              <cfif not structkeyexists( this, "alias" )>
                  <cfset this.alias = listlast( stMetadata.name, "." )/>
              </cfif>
          
              <!--- If title isn't specified, use the displayname --->
              <cfif not structkeyexists( this, "title" )>
                  <cfset this.title = this.displayname/>
              </cfif>
          
              <!--- If seq isn't specified, use 9999 --->
              <cfif not structkeyexists( this, "seq" )>
                  <cfset this.seq = 9999/>
              </cfif>
          
              <cfreturn this/>
          </cffunction>
          
          <cffunction name="isAvailable" hint="Is the hashing agorithm available in this environment?" access="public" returntype="boolean">
              <cfreturn true/>
          </cffunction>
          
          <cffunction name="matchesHashFormat" hint="Does the string match the format for this hash?" access="public" returntype="boolean">
              <cfargument name="input" type="string" required="true" hint="String that may be an encoding of a password"/>
          
              <cfthrow message="The #this.alias# password encoding needs to implement the matchesHashFormat function"/>
              <cfreturn ""/>
          </cffunction>
          
          <cffunction name="encode" hint="Convert a clear password to its encoded value" access="public" returntype="string">
              <cfargument name="password" type="string" required="true" hint="Input password"/>
          
              <cfthrow message="The #this.alias# password encoding needs to implement the encode function"/>
              <cfreturn ""/>
          </cffunction>
          
          <cffunction name="passwordMatch" hint="Compare a plain password against an encoded string" access="public" returntype="boolean">
              <cfargument name="password" type="string" required="true" hint="Input password"/>
              <cfargument name="hashedPassword" type="string" required="true" hint="Previously encoded password string"/>
              <cfargument name="bCheckHashStrength" type="string" default="false" hint="If true, the hash strength of the hashed password must also match those generated by encode()"/>
          
              <cfthrow message="The #this.alias# password encoding needs to implement the passwordMatch function"/>
              <cfreturn false/>
          </cffunction>
          
          <!--- Private Java library helper functions --->
          
          <cffunction access="private" name="getJavaLoader" returntype="any" output="false">
          
              <!--- Lazy-loading the JavaLoader makes it easier for plugins/projects to add custom crypto libraries --->
              <cfif not structKeyExists( variables, "loader" )>
                  <cfset variables.loader = createObject( "component", "PATH.TO.JavaLoader" ).init( variables.loadPaths )/>
              </cfif>
              <cfreturn variables.loader/>
          </cffunction>
          
          <cffunction access="private" name="createJavaClass" returntype="any" output="false" hint="Return a java class from the crypto libraries">
              <cfargument name="className" type="string" required="true"/>
          
              <cfreturn getJavaLoader( ).create( arguments.className )/>
          </cffunction>
          

          ...亚达亚达...更多代码...

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2023-03-10
            • 2017-05-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-01-12
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多