Golang 實現RSA 加密解密(附帶php)

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

安全總是很重要的,各個語言對於通用的密碼編譯演算法都會有實現。前段時間,用Go實現了RSA和DES的加密解密,在這分享一下。(對於RSA和DES密碼編譯演算法本身,請查閱相關資料)

在PHP中,很多功能經常是一個函數解決;而Go中的卻不是。本文會通過PHP加密,Go解密;Go加密,PHP解密來學習Go的RSA和DES相關的API。

該文討論Go RSA加密解密。所有操作在linux下完成。

一、概要

這是一個非對稱式加密演算法,一般通過公開金鑰加密,私密金鑰解密。

在加解密過程中,使用openssl生產密鑰。執行如下操作:

1)建立私密金鑰:

openssl genrsa -out private.pem 1024 //密鑰長度,1024覺得不夠安全的話可以用2048,但是代價也相應增大

2)建立公開金鑰:

openssl rsa -in private.pem -pubout -out public.pem

這樣便生產了密鑰。

一般地,各個語言也會提供API,用於產生密鑰。在Go中,可以查看encoding/pem包和crypto/x509包。具體怎麼產生,可查看《GO加密解密RSA番外篇:產生RSA密鑰》。

加密解密這塊,涉及到很多標準,個人建議需要的時候臨時學習一下。

二、Go RSA加密解密

1、rsa加解密,必然會去查crypto/ras這個包

Package rsa implements RSA encryption as specified in PKCS#1.

這是該包的說明:實現RSA加密技術,基於PKCS#1規範。

對於什麼是PKCS#1,可以查閱相關資料。PKCS(公開金鑰密碼標準),而#1就是RSA的標準。可以查看:PKCS系列簡介

從該包中函數的名稱,可以看到有兩對加解密的函數。

EncryptOAEP和DecryptOAEPEncryptPKCS1v15和DecryptPKCS1v15

這稱作加密方案,詳細可以查看,PKCS #1 v2.1 RSA 演算法標準

可見,當與其他語言互動時,需要確定好使用哪種方案。

PublicKey和PrivateKey兩個類型分別代表公開金鑰和私密金鑰,關於這兩個類型中成員該怎麼設定,這涉及到RSA密碼編譯演算法,本文中,這兩個類型的執行個體通過解析文章開頭產生的密鑰得到。

2、解析密鑰得到PublicKey和PrivateKey的執行個體
這個過程,我也是花了好些時間(主要對各種加密的各種東東不熟):怎麼將openssl產生的密鑰檔案解析到公開金鑰和私密金鑰執行個體呢?

在encoding/pem包中,看到了—–BEGIN Type—–這樣的字樣,這正好和openssl產生的密鑰形式差不多,那就試試。

在該包中,一個block代表的是PEM編碼的結構,關於PEM,請查閱相關資料。我們要解析密鑰,當然用Decode方法:

func Decode(data []byte) (p *Block, rest []byte)

這樣便得到了一個Block的執行個體(指標)。

解析來看crypto/x509。為什麼是x509呢?這又涉及到一堆概念。先不管這些,我也是看encoding和crypto這兩個包的子包摸索出來的。
在x509包中,有一個函數:

func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error)

從該函數的說明:ParsePKIXPublicKey parses a DER encoded public key. These values are typically found in PEM blocks with “BEGIN PUBLIC KEY”。可見這就是解析PublicKey的。另外,這裡說到了PEM,可以上面的encoding/pem對了。(PKIX是啥東東,查看這裡 )

而解析私密金鑰的,有好幾個方法,從上面的介紹,我們知道,RSA是PKCS#1,剛好有一個方法:

func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error)

返回的就是rsa.PrivateKey。

3、解密解密實現
通過上面的介紹,Go中RSA的解密解密實現就不難了。代碼如下:

// 加密

func RsaEncrypt(origData []byte) ([]byte, error) {    block, _ := pem.Decode(publicKey)    if block == nil {        return nil, errors.New("public key error")    }    pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)    if err != nil {        return nil, err    }    pub := pubInterface.(*rsa.PublicKey)    return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)}

// 解密

func RsaDecrypt(ciphertext []byte) ([]byte, error) {    block, _ := pem.Decode(privateKey)    if block == nil {        return nil, errors.New("private key error!")    }    priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)    if err != nil {        return nil, err    }    return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)}

其中,publicKey和privateKey是openssl產生的密鑰,我產生的如下:

// 公開金鑰和私密金鑰可以從檔案中讀取

var privateKey = []byte(`-----BEGIN RSA PRIVATE KEY-----MIICXQIBAAKBgQDZsfv1qscqYdy4vY+P4e3cAtmvppXQcRvrF1cB4drkv0haU24Y7m5qYtT52Kr539RdbKKdLAM6s20lWy7+5C0DgacdwYWd/7PeCELyEipZJL07Vro7Ate8Bfjya+wltGK9+XNUIHiumUKULW4KDx21+1NLAUeJ6PeW+DAkmJWF6QIDAQABAoGBAJlNxenTQj6OfCl9FMR2jlMJjtMrtQT9InQEE7m3m7bLHeC+MCJOhmNVBjaMZpthDORdxIZ6oCuOf6Z2+Dl35lntGFh5J7S34UP2BWzF1IyyQfySCNexGNHKT1G1XKQtHmtc2gWWthEg+S6ciIyw2IGrrP2Rke81vYHExPrexf0hAkEA9Izb0MiYsMCB/jemLJB0Lb3Y/B8xjGjQFFBQT7bmwBVjvZWZVpnMnXi9sWGdgUpxsCuAIROXjZ40IRZ2C9EouwJBAOPjPvV8Sgw4vaseOqlJvSq/C/pIFx6RVznDGlc8bRg7SgTPpjHG4G+M3mVgpCX1a/EU1mB+fhiJ2LAZ/pTtY6sCQGaW9NwIWu3DRIVGCSMm0mYh/3X9DAcwLSJoctiODQ1Fq9rreDE5QfpJnaJdJfsIJNtX1F+L3YceeBXtW0Ynz2MCQBI89KP274Is5FkWkUFNKnuKUK4WKOuEXEO+LpR+vIhs7k6WQ8nGDd4/mujoJBr5mkrwDPwqA3N5TMNDQVGv8gMCQQCaKGJgWYgvo3/milFfImbp+m7/Y3vCptarldXrYQWOAQjxwc71ZGBFDITYvdgJM1MTqc8xQek1FXn1vfpy2c6O-----END RSA PRIVATE KEY-----`) var publicKey = []byte(`-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZsfv1qscqYdy4vY+P4e3cAtmvppXQcRvrF1cB4drkv0haU24Y7m5qYtT52Kr539RdbKKdLAM6s20lWy7+5C0DgacdwYWd/7PeCELyEipZJL07Vro7Ate8Bfjya+wltGK9+XNUIHiumUKULW4KDx21+1NLAUeJ6PeW+DAkmJWF6QIDAQAB-----END PUBLIC KEY-----`)

4、使用例子

package main import (    "fmt")func main() {    data, err := RsaEncrypt([]byte("git@github.com/mrkt"))    if err != nil {        panic(err)    }    origData, err := RsaDecrypt(data)    if err != nil {        panic(err)    }    fmt.Println(string(origData))}

該例子是加密完git@github.com/mrkt後立馬解密

三、跨語言加解密

語言內部正常,還得看看和其他語言是否一致,即:其他語言加密,Go語言得正確解密;Go語言加密,其他語言正確解密

1、PHP RSA加解密
這裡,我選擇PHP,使用的是openssl擴充。PHP中加解密很簡單,如下兩個方法(這裡只考慮用公開金鑰加密,私密金鑰解密):

bool openssl_public_encrypt ( string $data , string &$crypted , mixed
$key [, int $padding = OPENSSL_PKCS1_PADDING ] ) bool
openssl_private_decrypt ( string $data , string &$decrypted , mixed
$key [, int $padding = OPENSSL_PKCS1_PADDING ] )

最後一個參數是加密方案(補齊方式)。由於Go中使用的是PKCS1而不是OAEP,所以,使用預設值即可。

PHP代碼如下:

$privateKey = '-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDZsfv1qscqYdy4vY+P4e3cAtmvppXQcRvrF1cB4drkv0haU24Y
7m5qYtT52Kr539RdbKKdLAM6s20lWy7+5C0DgacdwYWd/7PeCELyEipZJL07Vro7
Ate8Bfjya+wltGK9+XNUIHiumUKULW4KDx21+1NLAUeJ6PeW+DAkmJWF6QIDAQAB
AoGBAJlNxenTQj6OfCl9FMR2jlMJjtMrtQT9InQEE7m3m7bLHeC+MCJOhmNVBjaM
ZpthDORdxIZ6oCuOf6Z2+Dl35lntGFh5J7S34UP2BWzF1IyyQfySCNexGNHKT1G1
XKQtHmtc2gWWthEg+S6ciIyw2IGrrP2Rke81vYHExPrexf0hAkEA9Izb0MiYsMCB
/jemLJB0Lb3Y/B8xjGjQFFBQT7bmwBVjvZWZVpnMnXi9sWGdgUpxsCuAIROXjZ40
IRZ2C9EouwJBAOPjPvV8Sgw4vaseOqlJvSq/C/pIFx6RVznDGlc8bRg7SgTPpjHG
4G+M3mVgpCX1a/EU1mB+fhiJ2LAZ/pTtY6sCQGaW9NwIWu3DRIVGCSMm0mYh/3X9
DAcwLSJoctiODQ1Fq9rreDE5QfpJnaJdJfsIJNtX1F+L3YceeBXtW0Ynz2MCQBI8
9KP274Is5FkWkUFNKnuKUK4WKOuEXEO+LpR+vIhs7k6WQ8nGDd4/mujoJBr5mkrw
DPwqA3N5TMNDQVGv8gMCQQCaKGJgWYgvo3/milFfImbp+m7/Y3vCptarldXrYQWO
AQjxwc71ZGBFDITYvdgJM1MTqc8xQek1FXn1vfpy2c6O
-----END RSA PRIVATE KEY-----'; $publicKey = '-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZsfv1qscqYdy4vY+P4e3cAtmv
ppXQcRvrF1cB4drkv0haU24Y7m5qYtT52Kr539RdbKKdLAM6s20lWy7+5C0Dgacd
wYWd/7PeCELyEipZJL07Vro7Ate8Bfjya+wltGK9+XNUIHiumUKULW4KDx21+1NL
AUeJ6PeW+DAkmJWF6QIDAQAB
-----END PUBLIC KEY-----';

function rsaEncrypt($data){    global $publicKey;    openssl_public_encrypt($data, $crypted, $publicKey);    return $crypted;}function rsaDecrypt($data){    global $privateKey;    openssl_private_decrypt($data, $decrypted, $privateKey);    return $decrypted;}function main(){    $crypted = rsaEncrypt("git@github.com/mrk");    $decrypted = rsaDecrypt($crypted);    echo "encrypt and decrypt:" . $decrypted;}

main();
這裡也是用PHP加解密git@github.com/mrkt

2、Go和PHP一起工作
這裡要注意的一點是,由於加密後是位元組流,直接輸出查看會亂碼,因此,為了便於語言直接加解密,這裡將加密之後的資料進行base64編碼。

3、使用
樣本中,php和Go版本都支援-d參數傳入加密好的字串,將其解密;不傳時,會輸出加密好並base64編碼的串,可用於其他語言解密。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.