2012-06-07 24 views
1

我正在爲Xero API編寫包裝器,使用oAuth和雙腿認證。這是一個「私人」應用程序,正如Xero所稱,它需要RSA-SHA1簽名。 Coldfusion oAuth包裝器不具有在RSA-SHA1中進行加密的功能,只有HMAC-SHA1。我們在CF9上。Xero包裝器的ColdFusion oAuth RSA-SHA1授權

因此,在運行的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. 

任何人都可以解釋這一點嗎?

編輯 ----

enter image description here

有一個鏈接,上傳的公共證書,我做到了。這也是一個說明:「注意,對於私人應用程序,消費者令牌和祕密也被用作訪問令牌和祕密。」所以我假設我需要顯示那裏的「消費者機密」值以簽署請求。既然如此,我如何將該密鑰值轉換爲簽名的RSA-SH1格式?

+0

你是如何生成密鑰的? – Leigh

+0

我們使用的是oauth庫http://oauth.riaforge.org/。請注意,在我的示例中,我用「x」s屏蔽了大部分密鑰 – user460114

+0

我相信您需要生成您自己的'RSA'私鑰。然後將「base64格式的PKCS8私鑰」字符串提供給上面的函數。 [Google Oauth文檔](https://developers.google.com/gdata/docs/auth/oauth#GeneratingKeyCert)描述了一種方法,另一種方法[此處顯示](http://www.houseoffusion.com/groups /cf-talk/thread.cfm/threadid:62277)。 – Leigh

回答

1

(摘要從註釋)

根據their API私人應用程序必須生成RSA公共/私有對(一個時間事件)。然後,您將公開的證書上載到其服務器,並使用私鑰使用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"); 

注意如果你發佈你的實際私鑰這裏(或在另一個論壇),它就會大打折扣。所以我強烈建議生成新的密鑰。

+0

是的,終於得到了一個GET操作返回數據。非常感謝。 – user460114