我正在使用oAuth和双腿身份验证为Xero API编写包装器。它是一个“私有”应用程序,正如Xero所称,它需要RSA-SHA1签名。 Coldfusion oAuth包装器在RSA-SHA1中没有加密功能,只有HMAC-SHA1。我们在CF9上。
因此,在运行GET请求的过程中,我收到以下错误:
signature_method_rejected
Private applications must use the RSA-SHA1 signature method
因此,看起来GET调用正在运行,但问题在于签名方法。我发现了我认为看起来像某人创建的解决方案,如下所示:
<cffunction name="rsa_sha1" returntype="string" access="public" descrition="RSA-SHA1 computation based on supplied private key and supplied base signature string.">
<cfargument name="signKey" type="string" required="true" hint="base64 formatted PKCS8 private key">
<cfargument name="signMessage" type="string" required="true" hint="msg to sign">
<cfargument name="sFormat" type="string" required="false" default="UTF-8">
<cfset var jKey = JavaCast("string", arguments.signKey)>
<cfset var jMsg = JavaCast("string",arguments.signMessage).getBytes(arguments.sFormat)>
<cfset var key = createObject("java", "java.security.PrivateKey")>
<cfset var keySpec = createObject("java","java.security.spec.PKCS8EncodedKeySpec")>
<cfset var keyFactory = createObject("java","java.security.KeyFactory")>
<cfset var b64dec = createObject("java", "sun.misc.BASE64Decoder")>
<cfset var sig = createObject("java", "java.security.Signature")>
<cfset var byteClass = createObject("java", "java.lang.Class")>
<cfset var 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)>
<!--- keyBytes = 48-111-10345-125-5349-114-581835-28-330-3984120-2848-4384-1-43 --->
<cfset sig = sig.getInstance("SHA1withRSA", "SunJSSE")>
<!--- error occurs on the line below --->
<cfset sig.initSign(keyFactory.getInstance("RSA").generatePrivate(keySpec.init(keyBytes)))>
<cfset sig.update(jMsg)>
<cfset signBytes = sig.sign()>
<cfreturn ToBase64(signBytes)>
</cffunction>
它收到以下参数:
SFORMAT UTF-8
SIGNKEY 0JxxxxxxxxxxxxxxxxxxxP&
SIGNMESSAGE GET&https%3A%2F%2Fapi.xero.com%2Fapi.xro%2F2.0%2FContacts&contactid%3D%26contactnumber%3D%26name%3D7-Eleven%26oauth_consumer_key%3Dxxxxxxxxxxxxxxxx%26oauth_nonce%3Dxxxxxxxxxxxxxxxx%26oauth_signature_method%3DRSA-SHA1%26oauth_timestamp%3D1339055484%26oauth_version%3D1.0
但是,这会产生以下错误:
Could not read BER data.(ASN1Lengths.determineLengthLen: length greater than 0x7FFF,FFFF.)
ColdFusion cannot determine the line of the template that caused this error. This is often caused by an error in the exception handling subsystem.
任何人都可以对此有所了解吗?
修改 ----
我上传了公共证书的链接。这也是一个说明:“注意,对于私人应用程序,消费者令牌和秘密也被用作访问令牌和秘密。”所以我假设我需要在那里显示“Consumer Secret”值才能签署请求。在这种情况下,如何将该秘密密钥值转换为签名的RSA-SH1格式?
答案 0 :(得分:1)
(评论摘要)
根据their API,私人申请必须生成RSA公共/私人对(一次性事件)。然后,将 public 证书上传到其服务器,并使用私钥使用RSA-SHA1对所有请求进行签名。如果您按照其链接中的说明操作,您的私钥将采用PEM
格式,这只是在base64中编码的键值,包含在BEGIN / END包装器中:
-----BEGIN RSA PRIVATE KEY-----
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
....
-----END RSA PRIVATE KEY-----
在将密钥与PKCS8EncodedKeySpec
一起使用之前,您需要在包装器之间提取部分。至少有三种方法可以做到这一点。最简单的选择是使用字符串函数:
// read in the key file and remove the wrapper
pathToKey = "c:/path/to/file/privateKey.pem";
rawKey = FileRead( pathToKey );
rawKey = replace( rawKey, "-----BEGIN RSA PRIVATE KEY-----"& chr(10), "" );
rawKey = replace( rawKey, "-----END RSA PRIVATE KEY-----", "" );
yourMessage = "GET&https%3A%2F%2Fapi.xero.com%2Fapi.xro%2F2.0%2F...";
signature = rsa_sha1( rawKey, yourMessage, "utf-8" );
另一种选择是使用BouncyCastle PEMReader类。它为您完成所有操作(并且还支持受密码保护的密钥)。
pathToKey = "c:/path/to/file/privateKey.pem";
provider = createObject("java", "org.bouncycastle.jce.provider.BouncyCastleProvider").init();
security = createObject("java", "java.security.Security").addProvider( provider );
fileReader = createObject("java", "java.io.FileReader").init( pathToKey );
keyReader = createObject("java", "org.bouncycastle.openssl.PEMReader").init( fileReader);
privateKey = keyReader.readObject().getPrivate();
rawKey = binaryEncode( privateKey.getEncoded(), "base64" );
yourMessage = "GET&https%3A%2F%2Fapi.xero.com%2Fapi.xro%2F2.0%2FContacts&....";
signature = rsa_sha1( rawKey, yourMessage, "utf-8" );
另一种选择是convert the key to DER format with openssl
$ openssl pkcs8 -topk8 -in privateKey.pem -outform DER -nocrypt -out privateKey.pk8
pathToKey = "c:/path/to/file/privateKey.pk8";
bytes = binaryEncode( fileReadBinary(pathToKey), "base64");
yourMessage = "GET&https%3A%2F%2Fapi.xero.com%2Fapi.xro%2F2.0%2F...";
signature = rsa_sha1(rawKey, testMessage, "utf-8");
注意如果您在此处(或在其他论坛上)发布了您的实际私钥,则会受到损害。所以我强烈建议生成新密钥。