1. 程式人生 > >Java加密杏彩源碼搭建出售加簽算法到php的坑

Java加密杏彩源碼搭建出售加簽算法到php的坑

file 什麽 char com encrypt code func 操作 正常

寫代碼的經歷中,總少不了與外部的程序對接,一旦有這樣的事,往往周期會很長,很麻煩,因為你要考慮的事會多了很多,其中安全性的加密解密就是重要的一項。寫代碼,可以出Bug,但逼格不能弱。什麽是逼格?和別人對接一下,連加密解密都沒有,連驗證簽名都沒有,別人一眼就望穿你,這就是眼界的問題了。 這次的故事是對接一個大的支付系統,對方也是第一個對接我們,然後定了接口和加解密算法,給了個Java的Demo,問了聲,有沒有PHP的,沒有,歇菜,自己來吧。 代碼說多不多,說少不少,為了先說事,代碼放在最後面。 第一個坑:加密算法多多,你到底要鬧咋樣? 碼農兄弟們可以先下去看一眼代碼,然後說說它用了啥算法? 接口傳輸的安全性算法,首先要區分杏彩源碼搭建出售企娥3266397597是加簽名還是加密?區別是,簽名+原文可以驗證收到的信息是否被篡改,不過別指望有了簽名就可以還原出原文來。加密就是不讓別人看到原文是啥,然後給把鑰匙,要讓接收的人解密看出原文來。兩者的算法基本上來說,就是完全不同的。 加密還分對稱非對稱。對稱有:DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK、AES等,非對稱有:RSA、Elgamal、背包算法、Rabin、D-H、ECC(橢圓曲線加密算法) 還有,你以為拿個公鑰就夠了?當然不是,還要一對。更坑的是,可能有不同的格式。對方給了我一個keystore格式的,發覺php完全不支持,想辦法轉成了pem格式的。 常見的密鑰格式:jks,jce,p12,pfx,bks,ubr等等 常見的證書文件格式:cer,crt,rsa,p7b,p7r,p7c,pem,p10,csr等等 最後還有一點,這次碰到的算法具體的參數。 我這次遇到的是3DES加密,AlGORITHM = "DESede/ECB/PKCS5Padding";
,後面的類型和填充方式都不能差一點。 第二個坑:到底什麽是密鑰? 你會說這個很簡單啊 Java裏就是像這樣:?PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, password.toCharArray());? php裏就是像這樣:?$privateKey=openssl_pkey_get_private(file_get_contents($this->privatePemFilePath));? 你以為你以為的就是你以為的嗎?前面說了,即使算法一樣,密鑰格式不一樣,開發語言一樣,用法也完全不一樣。 上面的只是格式不同,下面的還有編碼的不同: 看起來我從代碼裏讀出的密碼是這個,但其實送入算法中的可不是,還要做一個Base64轉換,如果你送入了錯誤的,會永遠困在迷惘中。 1 $this->dESCORPKey = C(‘lakala_encrypt_key‘); 2 $key = $this->$dESCORPKey; 3 $encryptData = self::encrypt($key, $signedReq); 4 ... 5 public function encrypt($key,$data){ 6 $decode_key = base64_decode($key);//此處需要BASE64解碼(變為2進制) 7 $encData = openssl_encrypt($data, ‘DES-EDE3‘, $decode_key, OPENSSL_RAW_DATA); 8 $encData = base64_encode($encData); 9 return $encData; 10 } ? PS:網上有在線加密解密算法的工具,往往和代碼出來的結果不一致,除了各種參數都需要寫對以外,特別註意密碼(密鑰)的輸入格式,要不要Base64編碼或者解碼。 第三個坑:帶中文的字符串格式 看一眼下面的代碼,你就會知道,php裏有很多json_encode,json_decode,java代碼裏有很多getByte()這樣轉換成字節的操作,一個經典的問題就來了,你如果傳入了中文,中文按什麽格式進行編碼?編碼不同,決定了加密算法操作時二進制的不同,也決定了最終輸出的不同。 在寫代碼的時候查閱了java的getByte()方法,默認值竟然是讀取機器的字符格式!!!所以,寫代碼的時候一定要註意,最好加上具體格式,不要用默認值,要這麽寫:getByte("UTF-8")
,否則換了機器表現不一樣,你會死的很難看。 第四個坑:語言的問題 雖然上帝說人人平等,但現實遠遠復雜的多。 雖然加密解密本質上說就是一種運算變換,什麽語言都可以實現的,可你不會從底層開始搞的,那就涉及語言的問題。 最簡單的例子:java裏具體運算時都會把String轉換成byte進行操作。PHP就不行。 加密算法這個玩意雖然復雜,不過前人已經給我們造了很多輪子了,網上隨便一搜就可以找到很多資料,問題是沒有成系統,特別各個語言間的輪子差異還蠻大的。如何做適配,在網上的資料非常的難找。 PHP裏加密方法還有mcrypt和openssl兩套,互相之間的寫法還差異蠻大的,讓人頭疼。 舉個栗子(這裏的Java解析使用了fastjson): 1 java中: 2 CommReq req = JSON.parseObject(jsonStr, CommReq.class, Feature.OrderedField); 3 PHP中: 4 $req = json_decode(trim($jsonStr), true); 5 ksort($req); ? 看起來很像了吧?才不是呢!以下是輸入的Json { "head": { "serviceSn": "B5D79F38B96040B7B992B6BE329D9975", "serviceId": "MPBF001", "channelId": "05", "inputSource": "I002", "opId": "", "requestTime": "20180628142105", "versionId": "1.0.0", "businessChannel": "LKLZFLLF" }, "request": { "userId":"40012345678", "userName": "AA", "userMobile": "18675529912", "idNo": "110101198609096078" } } ? 問題出在具體的類型定義,以及Json解析的深度 JAVA中有定義具體按哪個類型解析 1 public class CommReq implements Serializable { 2 private static final long serialVersionUID = 1L; 3 private CommReqHead head; 4 private String request; 5 } JAVA這種強類型語言,必須定義類型,將request定義成String型,導致JSON解析出來的結果: "request":"{\"userId\":\"40012345678\",\"userName\": \"AA\", \"userMobile\": \"18675529912\", \"idNo\": \"110101198609096078\" } "; 而PHP是弱類型語言,直接嵌套進去也解析出來了 "request": {"userId":"40012345678","userName": "AA", "userMobile": "18675529912", "idNo": "110101198609096078" } } 如果PHP要和JAVA真正保持一致(因為一旦不一致,加密結果就不一樣了) 1 $req = json_decode(trim($jsonStr), true); 2 ksort($req); 3 req[‘request‘]=json_encode(req[‘request‘]); ? 前面也提到了密鑰類型的問題,其實也和語言有關,PHP只支持PEM格式,所以,還用工具對keystore進行了轉換,轉換之後發現幾個密碼都已經不需要了。生成公鑰PEM和私鑰PEM加上加密解密Key就可以了。 小結 回顧來看,其實只是解決了很小的一個問題,將一段JAVA代碼轉換成了PHP代碼,甚至中間復雜的算法細節都調用原來就有的模塊,更不用懷疑這些模塊寫的算法的正確性,但調試這樣一個東西,卻的的確確花費了非常大的精力。技術沒有任何中間地帶,只有行或者不行,容不得半分作假。開發必須要註重細節,細節到位了才不會出Bug,這點在加密解密這件事上,尤其的明顯,輸入差一個字符,輸出完全不同。開發沒有很容易的事,只有我做過,我熟悉的事。 ? 代碼在這裏哦。鑰匙就不提供了,這樣直接copy代碼跑不起來是正常的。哈哈

Java加密杏彩源碼搭建出售加簽算法到php的坑