体验.NET Core使用IKVM对接Java
【導(dǎo)讀】與第三方對(duì)接最麻煩的是語(yǔ)言不同,因語(yǔ)言不同內(nèi)置實(shí)現(xiàn)相關(guān)標(biāo)準(zhǔn)加密算法還是略微有所差異
對(duì)接單點(diǎn)登錄場(chǎng)景再尋常不過,由于時(shí)間緊迫且對(duì)接方使用Java,所以留給我對(duì)接開發(fā)和聯(lián)調(diào)的時(shí)間本就不多,于是乎,在熬夜發(fā)版后,繼而開始提前研究對(duì)接方所提供的加密方式大致處理
方案一(C#實(shí)現(xiàn))
數(shù)據(jù)對(duì)接加密算法采用RSA SHA1 1024位、同時(shí)呢,在Java中對(duì)于1024或其他位數(shù),對(duì)密文有長(zhǎng)度限制,所以利用了分段加密,密文長(zhǎng)度為117,解密長(zhǎng)度為128,如此通用處理方式,網(wǎng)上肯定是可以搜索到的,截取加密部分片段,如下:
public?static?byte[]?encryptByPublicKey(byte[]?data,?String?publicKey)?throws?Exception?{byte[]?keyBytes?=?Base64.getDecoder().decode(publicKey);X509EncodedKeySpec?x509KeySpec?=?new?X509EncodedKeySpec(keyBytes);KeyFactory?keyFactory?=?KeyFactory.getInstance(KEY_ALGORITHM);Key?publicK?=?keyFactory.generatePublic(x509KeySpec);Cipher?cipher?=?Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE,?publicK);int?inputLen?=?data.length;ByteArrayOutputStream?out?=?new?ByteArrayOutputStream();int?offSet?=?0;byte[]?cache;int?i?=?0;while?(inputLen?-?offSet?>?0)?{if?(inputLen?-?offSet?>?117)?{cache?=?cipher.doFinal(data,?offSet,?117);}?else?{cache?=?cipher.doFinal(data,?offSet,?inputLen?-?offSet);}out.write(cache,?0,?cache.length);i++;offSet?=?i?*?117;}byte[]?encryptedData?=?out.toByteArray();out.close();return?encryptedData;}當(dāng)然對(duì)于密鑰在從證書中導(dǎo)出來(lái)肯定是二進(jìn)制的,那么各個(gè)對(duì)接方最后轉(zhuǎn)換為字符串方式有多種,比如base64、再比如轉(zhuǎn)換為16進(jìn)制等等,大同小異,這里就不展開了
了解完Java完整代碼實(shí)現(xiàn),我們需要對(duì)相關(guān)業(yè)務(wù)參數(shù)利用對(duì)接方所提供的公鑰進(jìn)行加密從而形成簽名,以此請(qǐng)求時(shí),將我們本地生成的公鑰傳遞過去,在響應(yīng)后進(jìn)行驗(yàn)簽,然后通過私鑰解密
好了,講到這里,我們假設(shè)已經(jīng)本地生成證書,然后我們導(dǎo)出RSA公鑰和私鑰,偽代碼如下:
var?certificate?=?new?X509Certificate2("pfx_path",?"password",?X509KeyStorageFlags.Exportable);var?rsa?=?certificate.GetRSAPrivateKey();var?privateKey?=?rsa.ExportRSAPrivateKey();var?publicKey?=?rsa.ExportRSAPublicKey();那么我們?nèi)绾卫脤?duì)接方公鑰進(jìn)行加密呢?接下來(lái)在.NET Core中實(shí)現(xiàn)就需要解決上述加密算法出現(xiàn)的兩個(gè)問題
1. Java中可以通過RSA密鑰(公鑰或私鑰)字符串轉(zhuǎn)換為RSA密鑰類,.NET Core提供了?
2. 獲取到RSA密鑰類,調(diào)用對(duì)應(yīng)實(shí)例doFinal方法進(jìn)行分段加密,那么是否可以通過.NET Core中的RSA加密方法,也分段加密,結(jié)果是否一致?對(duì)接方通過公鑰字符串加載RSA 公鑰,代碼如下:
public?static?RSAPublicKey?loadPublicKeyByStr(String?publicKeyStr)?{byte[]?buffer?=?Util.hexToByte(publicKeyStr);KeyFactory?keyFactory?=?KeyFactory.getInstance("RSA");X509EncodedKeySpec?keySpec?=?new?X509EncodedKeySpec(buffer);return?(RSAPublicKey)?keyFactory.generatePublic(keySpec);}然后稍微查看了下加載類的解釋
所以我依圖索驥,于是乎,大致有了如下模樣
好了,目前通過導(dǎo)入公鑰主題信息貌似拿到了RSA,接下來(lái)則是分段加密,上述方法中cipher.doFinal,應(yīng)該是指定算法實(shí)例的加密處理,那我們首先截取對(duì)應(yīng)數(shù)據(jù)的分段,然后調(diào)用rsa的Encrypt方法,那加密填充模式是否一致,不得而知,默認(rèn)如下提供為PKCS1?
var?servicePublicKey?=?"123456";var?plainTextData?=?Encoding.UTF8.GetBytes("jeffcky");var?rsa?=?RSA.Create();rsa.ImportSubjectPublicKeyInfo(Encoding.UTF8.GetBytes(servicePublicKey),?out?_);var?outputStream?=?new?MemoryStream(); var?inputLen?=?plainTextData.Length; int?offSet?=?0; int?i?=?0; while?(inputLen?-?offSet?>?0) {Span<byte>?bytes?=?plainTextData;byte[]?encryptData;if?(inputLen?-?offSet?>?117){Span<byte>?slicedBytes?=?bytes.Slice(start:?offSet,?length:?117);encryptData?=?rsa.Encrypt(slicedBytes.ToArray(),?RSAEncryptionPadding.Pkcs1);}else{Span<byte>?slicedBytes?=?bytes.Slice(start:?offSet,?length:?inputLen?-?offSet);encryptData?=?rsa.Encrypt(slicedBytes.ToArray(),?RSAEncryptionPadding.Pkcs1);}outputStream.Write(encryptData,?0,?encryptData.Length);i++;offSet?=?i?*?117; }一頓不知其結(jié)果的操作后,經(jīng)調(diào)用對(duì)接方接口,響應(yīng)驗(yàn)簽失敗,反復(fù)改了幾版后,依然失敗
方案二(IKVM)
不再過多深究其細(xì)節(jié)實(shí)現(xiàn)差異,采用穩(wěn)妥方式借用IKVM直接在C#中復(fù)制對(duì)接方Java代碼應(yīng)該可以搞定(https://github.com/ikvm-revived/ikvm)
根據(jù)經(jīng)驗(yàn)來(lái)看,我只用到加密,應(yīng)該只需要用到IKVM.OpenJDK.Core和IKVM.OpenJDK.Security兩個(gè)庫(kù),于是我們?cè)趎uget上下載.NET Framework實(shí)現(xiàn)版本,我使用的是.NET Framework 4.7.2,想想.NET Framework 4.6+可以適配.NET Standard,那是否也可以經(jīng)過編譯后,通過.NET Core添加程序集引用呢?
在.NET Framework 4.7.2引入上述核心庫(kù)后,在控制臺(tái)測(cè)試驗(yàn)證加密、驗(yàn)簽一點(diǎn)問題都么有,好了,接下來(lái)則是將其編譯,在.NET Core 3.1中添加程序集進(jìn)行調(diào)用,加載程序集方法時(shí)直接拋出大致如下異常
FileNotFoundException: Could not load file or assembly 'System.Configuration.ConfigurationManager, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
繼續(xù)添加對(duì)應(yīng)版本程序集,版本過低,在nuget上根本找不到,涉及到.NET Core基礎(chǔ)設(shè)施,看是否在github runtimes倉(cāng)庫(kù)能否找到對(duì)應(yīng)issue
解決了上述程序集問題,接下來(lái)再次運(yùn)行,又來(lái)其他異常,.NET Core版本IO加載文件該方法已被剔除
坑一波接著一波,看來(lái)使用.NET Core引用.NET Framework程序集此路行不通,而且這僅僅只是在windows下測(cè)試,發(fā)布到linux上出現(xiàn)的問題無(wú)法預(yù)知,我再次翻了下,居然發(fā)現(xiàn)了.NET Core分支,驚喜不驚喜,查看分支就可以知道已有老外在處理遷移到.NET Core版本,只是還處于未發(fā)布狀態(tài)
適配.NET Core鏈接《(https://github.com/ams-ts-ikvm/ikvm-bin/tree/net_core_compat/bin)》
如果只是用到相關(guān)加密,只需引用上述鏈接bin目錄下,如下庫(kù)即可
最后,添加包以及版本(System.Configuration.ConfigurationManager),如下:
經(jīng)過上述一番折騰過程,終于對(duì)接上,耗時(shí)一天多,真尼瑪是不容易,搞完一個(gè)字,累的一p
💡?使用還未發(fā)布適配.NET Core的IKVM,在僅有時(shí)間內(nèi),快速對(duì)接上了Java加密,如若后續(xù)再遇到類似比較耗時(shí)耗力的加密方式,還不如使用IKVM,將更多時(shí)間花在處理業(yè)務(wù)邏輯上才是正道
總結(jié)
以上是生活随笔為你收集整理的体验.NET Core使用IKVM对接Java的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Win11推送加速!
- 下一篇: 无需Windbg | 使用VS 2019