Amazon web services 如何为AWS签名版本4(在ColdFusion中)派生登录密钥?

Amazon web services 如何为AWS签名版本4(在ColdFusion中)派生登录密钥?,amazon-web-services,coldfusion,amazon-kms,Amazon Web Services,Coldfusion,Amazon Kms,我正在尝试使用ColdFusion访问AmazonWeb服务(AWS),使用其当前的身份验证方法,即签名版本4。我查阅了他们的文档,其中包含的代码示例以及的伪代码。它们提供了一些测试输入值以传递给脚本的签名函数,以及一些预期结果 以下是测试输入: key = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' dateStamp = '20120215' regionName = 'us-east-1' serviceName = 'iam' 以下是预期结果:

我正在尝试使用ColdFusion访问AmazonWeb服务(AWS),使用其当前的身份验证方法,即签名版本4。我查阅了他们的文档,其中包含的代码示例以及的伪代码。它们提供了一些测试输入值以传递给脚本的签名函数,以及一些预期结果

以下是测试输入:

key = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY'
dateStamp = '20120215'
regionName = 'us-east-1'
serviceName = 'iam'
以下是预期结果:

kSecret  = '41575334774a616c725855746e46454d492f4b374d44454e472b62507852666943594558414d504c454b4559'
kDate    = '969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d'
kRegion  = '69daa0209cd9c5ff5c8ced464a696fd4252e981430b10e3d3fd8e2f197d7a70c'
kService = 'f72cfd46f26bc4643f06a11eabb6c0ba18780c19a8da0c31ace671265e3c87fa'
kSigning = 'f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d'
“kSigning”的正确值应为:

f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d
但是,对于“kSigning”,我的代码会生成以下内容:

31A84DCE0538A8B15ED68CCFBD803F17947E41BF625EFFD1AD6A67FC821F9BE2
我使用的是Railo4.2。有人能帮我解决这个问题吗,这样预期的价值就和倾销的价值相匹配了?以下是我的ColdFusion标记:

<cfsilent>

<!--- HMACSHA256 --->
<cffunction name="sign" returntype="binary" access="private" output="false" hint="Sign with NSA SHA-256 Algorithm">
   <cfargument name="signMessage" type="string" required="true" />
   <cfargument name="signKey" type="string" required="true" />

   <cfset var jMsg = JavaCast("string",arguments.signMessage).getBytes("utf-8") />
   <cfset var jKey = JavaCast("string",arguments.signKey).getBytes("utf-8") />
   <cfset var key = createObject("java","javax.crypto.spec.SecretKeySpec") />
   <cfset var mac = createObject("java","javax.crypto.Mac") />

   <cfset key = key.init(jKey,"HmacSHA256") />
   <cfset mac = mac.getInstance(key.getAlgorithm()) />
   <cfset mac.init(key) />

   <cfreturn mac.doFinal(jMsg) />
</cffunction>

<!--- Get Signature Key --->
<cffunction name="getSignatureKey" returntype="binary" access="private" output="false" hint="Derive the sign-in key">
    <cfargument name="key" type="string" required="true" />
    <cfargument name="dateStamp" type="string" required="true" />
    <cfargument name="regionName" type="string" required="true" />
    <cfargument name="serviceName" type="string" required="true" />

    <cfset var kSecret = "AWS4" & arguments.key />
    <cfset var kDate = sign( arguments.dateStamp, kSecret ) />
    <cfset var kRegion = sign( arguments.regionName, kDate ) />
    <cfset var kService = sign( arguments.serviceName, kRegion ) />
    <cfset var kSigning = sign( arguments.serviceName, kService ) />

    <cfreturn kSigning />
</cffunction>

</cfsilent><!doctype html>

<html lang="en">
<head>
    <meta charset="utf-8">
    <title>AWS Test</title>
</head>
<body>

<cfset kSecret = getSignatureKey( 
    'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY', 
    '20120215', 
    'us-east-1', 
    'iam' 
) />
<cfdump var="#BinaryEncode(kSecret, 'hex')#" label="kSecret" />

</body>
</html>

AWS测试

我看到了一个问题,当您注意到这两行有多么相似时,我希望您也会看到它:

<cfset var kService = sign( arguments.serviceName, kRegion ) />
<cfset var kSigning = sign( arguments.serviceName, kService ) />

红旗警报,hmac两次输入服务名称有意义吗

最后一步的输入是字符串文字

<cfset var kSigning = sign( "aws4_request", kService ) />

我不太惊讶代码运行时没有出错,因为
sign()
函数需要两个字符串,但代码实际上是在为第二个参数传递字节数组。(根据CF11,它会抛出一个错误)。也许有某种隐式转换正在进行? 无论如何,在稍微重构函数之后,该示例运行良好,只有一个例外。示例的最后一行使用文字字符串“aws4\u request”而不是“arguments.serviceName”。见下面的例子

话虽如此,Railo是否有一个HMAC功能,您可以使用,而不是自己滚动?我猜是这样的,正如CF10+中所包含的那样更新:Railo在中添加了
HMAC()
函数。然而,为了向后兼容,下面的java版本应该适用于大多数任何版本

示例:

result = getSignatureKey(key, dateStamp, regionName, serviceName);
writeDump( binaryEncode(result, "hex") );
F4780E2D9F65FA895F9C67B32CE1BAF0B0D8A43505A000A1A9E090D414DB404D 
<cffunction name="getSignatureKey" returntype="binary" access="private" output="false" hint="Derive the sign-in key">
    <cfargument name="key" type="string" required="true" />
    <cfargument name="dateStamp" type="string" required="true" />
    <cfargument name="regionName" type="string" required="true" />
    <cfargument name="serviceName" type="string" required="true" />

    <cfset Local.kSecret = charsetDecode("AWS4" & arguments.key, "UTF-8") />
    <cfset Local.kDate = sign( arguments.dateStamp, Local.kSecret ) />
    <cfset Local.kRegion = sign( arguments.regionName, Local.kDate ) />
    <cfset Local.kService = sign( arguments.serviceName, Local.kRegion ) />
    <cfset Local.kSigning = sign( "aws4_request", Local.kService ) />

    <cfreturn Local.kSigning />
</cffunction>




<cffunction name="sign" returntype="binary" access="private" output="false" hint="Sign with NSA SHA-256 Algorithm">
   <cfargument name="message" type="string" required="true" />
   <cfargument name="key" type="binary" required="true" />
   <cfargument name="algorithm" type="string" default="HmacSHA256" />
   <cfargument name="encoding" type="string" default="UTF-8" />

   <cfset Local.keySpec = createObject("java","javax.crypto.spec.SecretKeySpec") />
   <cfset Local.keySpec = Local.keySpec.init( arguments.key, arguments.algorithm ) />
   <cfset Local.mac = createObject("java","javax.crypto.Mac").getInstance( arguments.algorithm ) />
   <cfset Local.mac.init( Local.keySpec ) />

   <cfreturn Local.mac.doFinal( charsetDecode(arguments.message, arguments.encoding ) ) />
</cffunction>
结果:

result = getSignatureKey(key, dateStamp, regionName, serviceName);
writeDump( binaryEncode(result, "hex") );
F4780E2D9F65FA895F9C67B32CE1BAF0B0D8A43505A000A1A9E090D414DB404D 
<cffunction name="getSignatureKey" returntype="binary" access="private" output="false" hint="Derive the sign-in key">
    <cfargument name="key" type="string" required="true" />
    <cfargument name="dateStamp" type="string" required="true" />
    <cfargument name="regionName" type="string" required="true" />
    <cfargument name="serviceName" type="string" required="true" />

    <cfset Local.kSecret = charsetDecode("AWS4" & arguments.key, "UTF-8") />
    <cfset Local.kDate = sign( arguments.dateStamp, Local.kSecret ) />
    <cfset Local.kRegion = sign( arguments.regionName, Local.kDate ) />
    <cfset Local.kService = sign( arguments.serviceName, Local.kRegion ) />
    <cfset Local.kSigning = sign( "aws4_request", Local.kService ) />

    <cfreturn Local.kSigning />
</cffunction>




<cffunction name="sign" returntype="binary" access="private" output="false" hint="Sign with NSA SHA-256 Algorithm">
   <cfargument name="message" type="string" required="true" />
   <cfargument name="key" type="binary" required="true" />
   <cfargument name="algorithm" type="string" default="HmacSHA256" />
   <cfargument name="encoding" type="string" default="UTF-8" />

   <cfset Local.keySpec = createObject("java","javax.crypto.spec.SecretKeySpec") />
   <cfset Local.keySpec = Local.keySpec.init( arguments.key, arguments.algorithm ) />
   <cfset Local.mac = createObject("java","javax.crypto.Mac").getInstance( arguments.algorithm ) />
   <cfset Local.mac.init( Local.keySpec ) />

   <cfreturn Local.mac.doFinal( charsetDecode(arguments.message, arguments.encoding ) ) />
</cffunction>
功能:

result = getSignatureKey(key, dateStamp, regionName, serviceName);
writeDump( binaryEncode(result, "hex") );
F4780E2D9F65FA895F9C67B32CE1BAF0B0D8A43505A000A1A9E090D414DB404D 
<cffunction name="getSignatureKey" returntype="binary" access="private" output="false" hint="Derive the sign-in key">
    <cfargument name="key" type="string" required="true" />
    <cfargument name="dateStamp" type="string" required="true" />
    <cfargument name="regionName" type="string" required="true" />
    <cfargument name="serviceName" type="string" required="true" />

    <cfset Local.kSecret = charsetDecode("AWS4" & arguments.key, "UTF-8") />
    <cfset Local.kDate = sign( arguments.dateStamp, Local.kSecret ) />
    <cfset Local.kRegion = sign( arguments.regionName, Local.kDate ) />
    <cfset Local.kService = sign( arguments.serviceName, Local.kRegion ) />
    <cfset Local.kSigning = sign( "aws4_request", Local.kService ) />

    <cfreturn Local.kSigning />
</cffunction>




<cffunction name="sign" returntype="binary" access="private" output="false" hint="Sign with NSA SHA-256 Algorithm">
   <cfargument name="message" type="string" required="true" />
   <cfargument name="key" type="binary" required="true" />
   <cfargument name="algorithm" type="string" default="HmacSHA256" />
   <cfargument name="encoding" type="string" default="UTF-8" />

   <cfset Local.keySpec = createObject("java","javax.crypto.spec.SecretKeySpec") />
   <cfset Local.keySpec = Local.keySpec.init( arguments.key, arguments.algorithm ) />
   <cfset Local.mac = createObject("java","javax.crypto.Mac").getInstance( arguments.algorithm ) />
   <cfset Local.mac.init( Local.keySpec ) />

   <cfreturn Local.mac.doFinal( charsetDecode(arguments.message, arguments.encoding ) ) />
</cffunction>

我相信您可以在ColdFusion 10+中使用内置的HMAC()函数实现这一点,而无需创建Java对象:

function getSignatureKey(key, dateStamp, regionName, serviceName) {
    var kDate= lCase(HMAC(ARGUMENTS.dateStamp,"AWS4" & ARGUMENTS.key,"hmacsha256"));
    var kRegion= lCase(HMAC(ARGUMENTS.regionName,binaryDecode(kDate,'hex'),"hmacsha256"));
    var kService=lCase(HMAC(ARGUMENTS.serviceName,binaryDecode(kRegion,'hex'),"hmacsha256"));
    var kSigning= lCase(HMAC("aws4_request",binaryDecode(kService,'hex'),"hmacsha256"));

    return kSigning;
}

我一直想把我的脚本从2升级到4。但与此同时,这可能会给你一些进展。当你弄明白的时候,我很想看到你的结果!我花了整整72个小时试图找出aws webservice的签名版本4,我最终像代码示例一样获得了正确的令牌,当我将其发送到was服务时,我仍然得到了一个身份验证错误。在随后的几个小时里,我们一直在aws公司的分层支持(我们是一个命名帐户)中工作,工程师无法理解为什么该服务拒绝了其余的呼叫。停止下载JavaSDK并改用它。爱aws,恨他们的休息。这是一辆车。祝你好运@克里斯蒂尼-我知道这是很久以前的事了,但是我把一个。仍然非常高的alpha质量,但到目前为止似乎可以使用(使用CF11测试)。@Leigh-nice!谢谢你的提醒,我得检查一下!花了太长时间打印答案;-)lol@Leigh我讨厌这种情况发生。对于具体的错误,我们至少给出了相同的答案,但是对于详细的分析,+1。谢谢,Leigh!我在我这边也得到了同样的结果。出色的工作。顺便说一句,为了向后兼容,我认为在hmac中使用Java是很有帮助的。啊,谢谢你发布版本信息。我把它添加到了答案中,以获得更大的可视性。asker选择保留java版本(为了向后兼容),但对于使用内置HMAC函数的新代码,这是一条可行之路。