這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
之前工作主要使用C/C++與銀行/第三方支付對接,但C/C++無法滿足客戶”當天給協議明天實盤上傳“的開發速度以及現公司一些特殊情況,所以決定用go來嘗試實現。基本的架構已經按照原來C/C++非阻塞架構實現一次,內部涉及加密方式也用go重新實現一遍,但一個數位憑證加密的方式著實坑爹了一把,同時這個問題,也看到了openssl的命名混亂。
關於這個加密方式的描述是:發送方用私密金鑰進行rsa加密,接受方使用公開金鑰進行rsa解密。看到這樣的加密方式描述,感覺和自己的理解是有點不一樣,不知道是不是自己對這方面瞭解不夠深入,自己的理解是(之前使用過的加密方式):公開金鑰是公開的,私密金鑰是自己儲存的,用私密金鑰對資料進行簽名,用公開金鑰驗證簽名。感覺畫風不一樣,翻查一下openssl,的確也是存在這樣的函數:
RSA_private_encrypt
和RSA_public_decrypt
,參考文檔。用openssl很容易就實現這樣一個加密解密。但用純go語言實現,不可能再用cgo來調用c函數,翻查一下go的文檔,存在在類似的函數(crypt/rsa
):
func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) ([]byte, error)
和func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) ([]byte, error)
。但仔細看,這裡是使用公開金鑰進行加密,使用私密金鑰進行解密,和描述剛好相反。除了這兩個涉及公私密金鑰加密的函數外,似乎在go裡面找不到其他類似的函數了。
在google(科學上網lanttern)裡面,能夠搜尋到的答案似乎不多,最後在stackoverflow找到結果:Encrypt message with RSA private key (as in OpenSSL's RSA_private_encrypt。一哥們手工搞定,其代碼放在goplaygound。看了一下代碼,如果不是對go內部的資料結構非常熟悉,而且對rsa機制非常清楚,很難寫出正常代碼。難道go就沒有現成的程式碼完成這個功能?後面,有人就說,這是什麼狗屁加密,壓根就是一rsa簽名,就用crypt/rsa
裡面,func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error)
實現的。尼瑪的,測試結果還真是一樣。後來,回頭看一下openssl裡面的參考文檔說明,These functions handle RSA signatures at a low level.,這就是簽名啊,既然是簽名,為何命名encrypt/decrypt?是不是因為命名問題,廣為傳播為私密金鑰"加密"公開金鑰"解密"呢?
go不知道是不是受不了這樣私密金鑰"加密"公開金鑰"解密"這種混亂的說法,不像其他語言一樣提供類似的函數呢?至於公開金鑰"解密",網上搜尋不到滿意答案,不過,既然私密金鑰"加密"是rsa簽名,那麼公開金鑰"解密"那麼應該就是驗證簽名了。既然網上找不到滿意的答案,那麼只能修改一下go的func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error
函數。證實,這個想法是可行的。用openssl加密的資料,可以解密,加密的資料同時可以被openssl解密。
相關代碼:https://github.com/buf1024/golib/tree/master/crypt 只簡單匯出PrivateEncrypt
和PublicDecrypt
兩個函數。
最後,openssl的確存在一些非常混亂的命名方式,而其他語言/庫,妥協這種混亂情況,那麼混亂看起來即變為普遍。如不是非常熟悉,那麼到一個不再妥協這種混亂時,那麼及其容易使自己混亂啊。