对于这篇文章的长度,我提前表示歉意。我对这个问题的了解还不够,无法正确确定具体问题实际上是什么!但无论如何,我们一直在使用 @Leigh 提供的步骤和建议来调用我们的会员 API 来查询有关我们会员的信息(加入日期、会员类型等)here https://stackoverflow.com/questions/39843768/unable-to-generate-valid-signature-for-api-using-coldfusion-and-hmac-sha1他们一直工作得很好!再次感谢 Leigh,我们的会员很高兴能够做到这一点!
现在,我想为我们的会员设置单点登录,允许他们登录我们的页面,然后转到他们已经登录该网站的会员个人资料。根据API文档 http://documentation.membersuite.com/Developer's_Guide/010_API_Overview/Getting_Started/030_Signing_Certificates,我需要做的一件事是:
“使用您的签名证书来签署登录者的门户用户名。”
我完全被困在这个问题上。我已获得以下形式的 XML 私钥(由其 .NET 应用程序生成)
<RSAKeyValue><Modulus>{stuff}</Modulus><Exponent>{stuff}</Exponent><P>... etc etc
我发现我无法直接使用这种格式,必须将其转换为 PEM 格式或类似格式。使用 OpenSSL,我想我已经做到了这一点,现在有一个格式为“-----BEGIN PRIVATE KEY-----{stuff}-----END PRIVATE KEY-----”的文件。
使用 Leigh 的解决方案确实给了我一个签名,但它与 API 文档中提供的示例不匹配。我认为这是因为它使用 HmacSHA1,而他们指出“标头中的签名使用 HMAC SHA1,而创建安全令牌的签名使用公钥/私钥对和 RSA-SHA1。不能使用相同的方法来生成两者。 ”我尝试改变
<cfset key = key.init(jKey,"HmacSHA1") />
to
<cfset key = key.init(jKey,"RSA-SHA1") />
并收到“算法 RSA-SHA1 不可用”。
我尝试过复制并粘贴其他一些建议的解决方案,但它们都不起作用。一个例子(来自12Robots.com http://www.12robots.com/index.cfm/2010/7/19/Using-Asymmetric-cryptography-in-your-coldfusion-Application--Security-Series-1610):
<!--- Create a Java Cipher object and get a mode --->
<cfset cipher = createObject('java', 'javax.crypto.Cipher').getInstance("RSA") />
<!--- The mode tells the Cipher whether is will be encrypting or decrypting --->
<cfset encMode = cipher.ENCRYPT_MODE />
<cfset encryptedValue = "" /> <!--- Return variable --->
<!--- Initialize the Cipher with the mode and the key --->
<cfset cipher.init(encMode, key) />
<!--- Convert the string to bytes --->
<cfset stringBytes = stringToSign.getBytes("UTF8") />
<!--- Perform encryption --->
<cfset encryptedValue = cipher.doFinal(stringBytes, 0, len(inputString)) />
<cfdump var="#encryptedValue#">
本例中的“Key”是我之前提到的 PEM 文本,“stringToSign”是用户名。我得到的错误是“要么没有具有指定方法名称和参数类型的方法,要么 init 方法重载了 ColdFusion 无法可靠破译的参数类型。ColdFusion 找到了 0 个与提供的参数匹配的方法。如果这是一个 Java 对象并且您验证了该方法存在,请使用 javacast 函数来减少歧义。”
我尝试过的另一件事是:
<cfset rsaPrivateKey = toBase64(key, "utf-8")>
<cfset jKey = JavaCast("string", rsaPrivateKey)>
<cfset jMsg = JavaCast("string", stringToSign).getBytes("ASCII")>
<cfset key = createObject("java", "java.security.PrivateKey")>
<cfset keySpec = createObject("java", "java.security.spec.PKCS8EncodedKeySpec")>
<cfset keyFactory = createObject("java", "java.security.KeyFactory")>
<cfset b64dec = createObject("java", "sun.misc.BASE64Decoder")>
<cfset sig = createObject("java", "java.security.Signature")>
<cfset byteClass = createObject("java", "java.lang.Class")>
<cfset byteArray = createObject("java", "java.lang.reflect.Array")>
<cfset byteClass = byteClass.forName(JavaCast("string", "java.lang.Byte"))>
<cfset keyBytes = byteArray.newInstance(byteClass, JavaCast("int", "1024"))>
<cfset keyBytes = b64dec.decodeBuffer(jKey)>
<cfset sig = sig.getInstance("SHA1withRSA", "SunJSSE")>
<cfset sig.initSign(keyFactory.getInstance("RSA").generatePrivate(keySpec.init(keyBytes)))>
<cfset sig.update(jMsg)>
<cfset signBytes = sig.sign()>
<cfset finalSig = ToBase64(signBytes)>
<cfdump var="#finalSig#">
这给了我“java.security.InvalidKeyException:无效的密钥格式”。顺便说一句,如果我将 rsaPrivateKey 设置为“key”,我会收到不同的错误,“java.security.InvalidKeyException:IOException:DerInputStream.getLength():lengthTag = 127,太大。”我很高兴收到不同的错误消息;至少有事情正在发生! :-)
同样,我不知道这些 Java 函数在做什么。我当然不明白为什么看似简单的事情最终变得如此复杂!但我怀疑,我要么错误地存储了私钥 PEM,要么错误地从数据库中读取(或两者兼而有之),这就是导致这些各种解决方案失败的原因。但我还不够了解,无法确定情况是否如此。
我欢迎任何可能对我有帮助的见解或建议!如果有人需要更多信息,我很乐意提供。提前非常感谢大家!