在與第三方平臺進行接入的時候,一般會存在一些簽名或者加密的處理,在進行開發的時候,由於語言的
不一樣,須要按照規範進行相應處理。golang
DES:https://en.wikipedia.org/wiki/Data_Encryption_Standardsegmentfault
golang中的標準庫crypto/des中有DES的實現,可是golang庫的描述比較簡單,若是不熟悉DES的加密規則,是不容易
進行相應代碼編寫的,與第三方進行不一樣語言之間的加密與解密時,也容易混淆,出現錯誤。app
DES區分爲CBC和EBC加密模式,而且有不一樣的填充方式。ide
CBC(等):https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
Padding:https://en.wikipedia.org/wiki/Padding_(cryptography)函數
注意 PKCS#5 padding is identical to PKCS#7 padding加密
因此對不一樣的平臺與語言進行DES加解密對接時,須要知道對方的是採用何種加密模式以及何種填充方式:code
Windows 默認是CBC模式,CryptSetKeyParam函數,openssl 函數名中直接代表orm
Java 中若是Cipher.getInstance()中不填寫,默認是DES/ECB/PKCS5Paddingip
C# 中默認是CBC模式,PKCS7Padding(PKCS5Padding)ssl
golang默認提供的是CBC模式,因此對於ECB模式,須要本身編寫代碼
PKCS5Padding與PKCS5Unpadding
func PKCS5Padding(ciphertext []byte, blockSize int) []byte { padding := blockSize - len(ciphertext)%blockSize padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(ciphertext, padtext...) } func PKCS5Unpadding(origData []byte) []byte { length := len(origData) unpadding := int(origData[length-1]) return origData[:(length - unpadding)] }
ECB加密模式
block, err := des.NewCipher(key) if err != nil { ... } bs := block.BlockSize() src = PKCS5Padding(src, bs) if len(src)%bs != 0 { .... } out := make([]byte, len(src)) dst := out for len(src) > 0 { block.Encrypt(dst, src[:bs]) src = src[bs:] dst = dst[bs:] } ... }
ECB下的解密
block, err := des.NewCipher(key) if err != nil { ... } out := make([]byte, len(src)) dst := out bs := block.BlockSize() if len(src)%bs != 0 { ... } for len(src) > 0 { block.Decrypt(dst, src[:bs]) src = src[bs:] dst = dst[bs:] } out = PKCS5UnPadding(out)
與其餘語言默認有更高級的封裝不一樣,golang中須要依據不一樣的概念,本身組合進行封裝處理,爲此,須要先理解幾個不一樣的概念。
PEM: https://en.wikipedia.org/wiki/Privacy-enhanced_Electronic_Mail,一般是以.pem結尾的文件,在密鑰存儲和X.509證書體系中使用比較多,下面是一個X509證書下的PEM格式:
-----BEGIN CERTIFICATE----- base64 -----END CERTIFICATE-----
PKCS:https://en.wikipedia.org/wiki/PKCS,這是一個龐大的體系,不一樣的密鑰採用不一樣的pkcs文件格式。如私鑰採用pkcs8。
X.509:https://en.wikipedia.org/wiki/X.509,這是一個公鑰管理基礎(public key infrastructure, pki),在IETF中一般對應PKIX。
說明:
使用 openssl(如openssl genrsa -out rsa_private_key.pem 1024
)生成的pem文件,就是符合PEM格式的,以-----BEGIN RSA PRIVATE KEY-----
開頭,-----END RSA PRIVATE KEY-----
結尾。
也能夠轉換爲pkcs8:
openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt
注意,雖然數據格式pkcs8格式,可是-outform也代表了,文件格式仍舊是符合PEM格式的,只是兩個PEM文件是存在差別的。
清楚了上面幾種概念與格式以後,編寫golang對應的公鑰與私鑰加解密方式,就相對容易一些,首先是將pem文件解碼,而後進行對應的密碼解碼爲golang支持的結構體,再進行相應的處理。
如對於私鑰,能夠進行以下操做進行簽名:
block, _ := pem.Decode([]byte(key)) if block == nil { // 失敗狀況 .... } private, err := x509.ParsePKCS8PrivateKey(block.Bytes) if err != nil { ... } h := crypto.Hash.New(crypto.SHA1) h.Write(data) hashed := h.Sum(nil) // 進行rsa加密簽名 signedData, err := rsa.SignPKCS1v15(rand.Reader, private.(*rsa.PrivateKey), crypto.SHA1, hashed) ...
經過私鑰進行解密,代碼格式以下;
block, _ := pem.Decode([]byte(key)) if block == nil { // 失敗狀況 .... } private, err := x509.ParsePKCS8PrivateKey(block.Bytes) if err != nil { ... } v, err := rsa.DecryptPKCS1v15(rand.Reader, private, data) ...
對於公鑰對數據進行加密:
block, _ := pem.Decode([]byte(key)) if block == nil { // 失敗狀況 .... } pub, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { ... } encryptedData, err := rsa.EncryptPKCS1v15(rand.Reader, pub.(*rsa.PublicKey), data) ...
搞清楚具體的加密方式,而後再在golang裏面編寫,代碼仍是很清晰也不難看懂。
文章發佈於 http://www.javashuo.com/article/p-kwksquys-cz.html,做者:Damon