go包:crypto-rsa非對稱加密

1. 維基百科釋義

RSA加密算法是一種非對稱加密算法蹦浦,在公開密鑰加密電子商業(yè)中被廣泛使用寞射。RSA是由羅納德·李維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和[倫納德·阿德曼(Leonard Adleman)在1977年一起提出的。當時他們?nèi)硕荚赱麻省理工學院工作橄仍。RSA 就是他們?nèi)诵帐祥_頭字母拼在一起組成的诬垂。

2.生成密鑰

RSA私鑰存在PKCS1PKCS8兩種格式,通過openssl生成的私鑰格式為PKCS1,公鑰格式為PKCS8慷彤。

2.1 使用openssl命令

1.生成私鑰(PKCS1格式)
# 生成私鑰
? openssl genrsa -out private_ssl.pem 1024
Generating RSA private key, 1024 bit long modulus
.......++++++
.............................................++++++
e is 65537 (0x10001)
# 查看私鑰
? cat private_ssl.pem
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDSgkiwisLr7yTuKnn6jANvRXRfnA9PINojpPiegMkv/mnScEvM
czP8OZjpFrsjSKFnlc6OX04O+4G3GuBMjc75wQw79auM4WMJtSh3PAWiBGu6Woto
AqZFbWRnIzk2Wjw1xSJxpOUa0ed1plU/jut1dKgDTi4q+BDqGizI2JeJdQIDAQAB
AoGAFij24/bHjDSxi4zXKGPi3KzQElyIVAkeTZBJR85A35eFpkyB/jTGbS/XA/qL
mqxDqXbgtqYbvoIFZrQilox7FCi5AzxhQDB3wD67y5OjuSWhTKypq5UOj/6y9zkC
Gbzi4zIBlOZIskfj81a+WBg7vi6FCaCg105nDJOCDs0IYiECQQDpZNBoolQGgsmR
M/x699WXhG1xYV9bTDhBKpsW/O0mRjiK/6pCbDjRWGxeB+BmFmRofYwWRj2stzkg
We1if8jNAkEA5uYFWBqHpKpFUULM7fqoyixrTXz+3h22vcKc4s/xhSCfM8yCS/ad
7S4tzpEGAenLPWYERhm6Cm/0yVavtYBjSQJBAN0MBG71P0ujVzDU4c29KGiGnfkC
VgPsHmNp7NVK23iijS7okeKzCOUNMCWmpBtMHfDw51q5T/Ri3BIN2cyuZgkCQQCV
Hz2YVxn/mRBHmRLtJ5PXbrSmSPH51crt50CXo6DiT91CAPStxsrcIZTn8fWlSq8+
KiLce0UR9JhtaBT27cIxAkEArozPsVt273/UkAru4LgBURK5ZEaHful/oK0xRDdg
fq+Ij4rs24CVPlNXfycZEDrKYMS9ScZrraf8JsTSEBx++w==
-----END RSA PRIVATE KEY-----
2.生成公鑰(PKCS8格式)
# 生成公鑰
? openssl rsa -in private_ssl.pem -pubout -out public_ssl.pem
writing RSA key
# 查看公鑰
? cat public_ssl.pem
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSgkiwisLr7yTuKnn6jANvRXRf
nA9PINojpPiegMkv/mnScEvMczP8OZjpFrsjSKFnlc6OX04O+4G3GuBMjc75wQw7
9auM4WMJtSh3PAWiBGu6WotoAqZFbWRnIzk2Wjw1xSJxpOUa0ed1plU/jut1dKgD
Ti4q+BDqGizI2JeJdQIDAQAB
-----END PUBLIC KEY-----
3. 私鑰PKCS1轉(zhuǎn)PKCS8
? openssl pkcs8 -topk8 -inform pem -in private_ssl.pem -outform PEM -nocrypt
-----BEGIN PRIVATE KEY-----
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANKCSLCKwuvvJO4q
efqMA29FdF+cD08g2iOk+J6AyS/+adJwS8xzM/w5mOkWuyNIoWeVzo5fTg77gbca
4EyNzvnBDDv1q4zhYwm1KHc8BaIEa7pai2gCpkVtZGcjOTZaPDXFInGk5RrR53Wm
VT+O63V0qANOLir4EOoaLMjYl4l1AgMBAAECgYAWKPbj9seMNLGLjNcoY+LcrNAS
XIhUCR5NkElHzkDfl4WmTIH+NMZtL9cD+ouarEOpduC2phu+ggVmtCKWjHsUKLkD
PGFAMHfAPrvLk6O5JaFMrKmrlQ6P/rL3OQIZvOLjMgGU5kiyR+PzVr5YGDu+LoUJ
oKDXTmcMk4IOzQhiIQJBAOlk0GiiVAaCyZEz/Hr31ZeEbXFhX1tMOEEqmxb87SZG
OIr/qkJsONFYbF4H4GYWZGh9jBZGPay3OSBZ7WJ/yM0CQQDm5gVYGoekqkVRQszt
+qjKLGtNfP7eHba9wpziz/GFIJ8zzIJL9p3tLi3OkQYB6cs9ZgRGGboKb/TJVq+1
gGNJAkEA3QwEbvU/S6NXMNThzb0oaIad+QJWA+weY2ns1UrbeKKNLuiR4rMI5Q0w
JaakG0wd8PDnWrlP9GLcEg3ZzK5mCQJBAJUfPZhXGf+ZEEeZEu0nk9dutKZI8fnV
yu3nQJejoOJP3UIA9K3GytwhlOfx9aVKrz4qItx7RRH0mG1oFPbtwjECQQCujM+x
W3bvf9SQCu7guAFRErlkRod+6X+grTFEN2B+r4iPiuzbgJU+U1d/JxkQOspgxL1J
xmutp/wmxNIQHH77
-----END PRIVATE KEY-----

3.讀取密鑰

3.1 代碼

// 讀取PKCS1格式私鑰
func ReadRSAPKCS1PrivateKey(path string) (*rsa.PrivateKey, error) {
    // 讀取文件
    context, err := ioutil.ReadFile(path)
    if err != nil {
        return nil, err
    }
    // pem解碼
    pemBlock, _ := pem.Decode(context)
    // x509解碼
    privateKey, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
    return privateKey, err
}
// 讀取公鑰(包含PKCS1和PKCS8)
func ReadRSAPublicKey(path string) (*rsa.PublicKey, error) {
    var  err error
    // 讀取文件
    readFile, err := ioutil.ReadFile(path)
    if err != nil {
        return nil, err
    }
    // 使用pem解碼
    pemBlock, _ := pem.Decode(readFile)
    var pkixPublicKey interface{}
    if pemBlock.Type == "RSA PUBLIC KEY" {
        // -----BEGIN RSA PUBLIC KEY-----
        pkixPublicKey, err = x509.ParsePKCS1PublicKey(pemBlock.Bytes)
    } else if pemBlock.Type == "PUBLIC KEY" {
        // -----BEGIN PUBLIC KEY-----
        pkixPublicKey, err = x509.ParsePKIXPublicKey(pemBlock.Bytes)
    }
    if err != nil {
        return nil,err
    }
    publicKey := pkixPublicKey.(*rsa.PublicKey)
    return publicKey, nil
}

3.2 測試

// 讀取密鑰
func TestReadKey(t *testing.T) {
    // pkcs1格式-私鑰
    privatePKCS1KeyPath := "../../tmp/private_ssl.pem"
    privatePKCS1Key, err := crypto.ReadRSAPKCS1PrivateKey(privatePKCS1KeyPath)
    if err != nil {
        t.Error(err)
    }
    fmt.Printf("PKCS1私鑰: %#v\n",privatePKCS1Key)
    // pkcs8格式-公鑰
    publicPKCS8KeyPath := "../../tmp/public_ssl.pem"
    publicPKCS8Key, err := crypto.ReadRSAPublicKey(publicPKCS8KeyPath)
    if err != nil {
        t.Error(err)
    }
    fmt.Printf("PKCS8公鑰: %#v\n",publicPKCS8Key)
}

4.加密

4.1 代碼

// 加密(使用公鑰加密)
func RSAEncrypt(data, publicKeyPath string) (string, error) {
    // 獲取公鑰
  // ReadRSAPublicKey代碼在 【3.讀取密鑰】
    rsaPublicKey, err := ReadRSAPublicKey(publicKeyPath)
    if err != nil {
        return "", err
    }
    // 加密
    encryptPKCS1v15, err := rsa.EncryptPKCS1v15(rand.Reader, rsaPublicKey, []byte(data))
    if err != nil {
        return "",err
    }
    // 把加密結(jié)果轉(zhuǎn)成Base64
    encryptString := base64.StdEncoding.EncodeToString(encryptPKCS1v15)
    return encryptString, err
}

4.2 測試

// 加密測試
func TestRsaEncrypt(t *testing.T) {
    publicKeyPath := "../../tmp/public_ssl.pem"
    data := "123456"
    encrypt, err := crypto.RSAEncrypt(data, publicKeyPath)
    if err != nil {
        t.Error(err)
    }
    fmt.Printf("加密結(jié)果:%v \n",encrypt)
}
/** 輸出
=== RUN   TestRsaEncrypt
加密結(jié)果:SRYyBXd4p+wUeTZ5478g+hW2P3OvqhYMyPwW/j91SappgxMWC/O3vCG2aVTcAHknUkK2oEs6e28deKuOvOkjSWl/jnXFDCkXklgbgnXJtfu2FjP9jXhG2b6/Eo3okxLvLXZtkaRAgZKNbbKkeiNASUO4IidkoNrnI4aOuuuVIOY= 
--- PASS: TestRsaEncrypt (0.00s)
PASS
*/

5.解密

5.1 代碼

// 解密(使用私鑰解密)
func RSADecrypt(base64data,privateKeyPath string) (string,error) {
    // data反解base64
    decodeString, err := base64.StdEncoding.DecodeString(base64data)
    if err != nil {
        return "", err
    }
    // 讀取密鑰
    rsaPrivateKey, err := ReadRSAPKCS1PrivateKey(privateKeyPath)
    if err != nil {
        return "", err
    }
    // 解密
    decryptPKCS1v15, err := rsa.DecryptPKCS1v15(rand.Reader, rsaPrivateKey, decodeString)
    return string(decryptPKCS1v15),err
}

5.2 測試

// 解密測試
func TestRsaDecrypt(t *testing.T) {
    privateKeyPath := "../../tmp/private_ssl.pem"
    data := "pUYa4set6XkBshfio5g2hzPx1tA67sxEvJBpJiuK3McJ9cPJAXzuRkWIy4s6cDQOhrPUaNXhr3M3WLHH19/eaqcNZz1yOFZwgGKmkWtdmygtLB/wrDant9uRfXrvzlV9iMq+cUlqsrwuCa0wcGEBNHRhIJOQSTs+SxaRTeoRCbU="
    encrypt, err := crypto.RSADecrypt(data, privateKeyPath)
    if err != nil {
        t.Error(err)
    }
    fmt.Printf("解密結(jié)果:%v \n",encrypt)
}
/** 輸出
=== RUN   TestRsaDecrypt
解密結(jié)果:123456 
--- PASS: TestRsaDecrypt (0.00s)
PASS
*/

6.數(shù)據(jù)簽名

6.1 加簽

a. 代碼

// 對數(shù)據(jù)進行數(shù)字簽名
func GetRSASign(data, privateKeyPath string) (string, error) {
    // 讀取私鑰
    privateKey, err := ReadRSAPKCS1PrivateKey(privateKeyPath)
    if err != nil {
        return "", err
    }
    // 計算Sha1散列值
    hash := sha256.New()
    hash.Write([]byte(data))
    sum := hash.Sum(nil)
    // 從1.5版本規(guī)定娄蔼,使用RSASSA-PKCS1-V1_5-SIGN 方案計算簽名
    signPKCS1v15, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, sum)
    // 結(jié)果轉(zhuǎn)成base64
    toString := base64.StdEncoding.EncodeToString(signPKCS1v15)
    return toString, err
}

b. 測試

// 數(shù)據(jù)加簽
func TestAddSign(t *testing.T) {
    privateKeyPath := "../../tmp/private_ssl.pem"
    data := "123456"
    sign, err := crypto.GetRSASign(data,privateKeyPath)
    if err != nil {
        t.Error(err)
    }
    fmt.Printf("數(shù)據(jù)簽名: %v \n",sign)
}
/** 輸出
=== RUN   TestAddSign
數(shù)據(jù)簽名: QnGqGbIqoHjJG1l+JiaOKWBdX+h00lnKCoO2rTYKIro9hoaDj7nqmu+Mxsuo+2jumicvCNBZNOpMzYryjZf0x7Q4ycLBtqtCWuFRasiInUO7Avy19LRTjdMf2xw9968vilB/xEAQ53JXIDUVvCsMxTfpHI9oRiWEGXWNkhfkjkQ= 
--- PASS: TestAddSign (0.00s)
PASS
*/

6.2 驗簽

a. 代碼

// 驗證簽名
func VerifyRsaSign(data, publicKeyPath, base64Sign string) (bool, error) {
    // 反解base64
    sign,err := base64.StdEncoding.DecodeString(base64Sign)
    if err != nil {
        return false, err
    }
    // 獲取公鑰
    publicKey, err := ReadRSAPublicKey(publicKeyPath)
    if err != nil {
        return false, err
    }
    // 計算Sha1散列值
    hash := sha256.New()
    hash.Write([]byte(data))
    bytes := hash.Sum(nil)
    err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, bytes, sign)
    return err == nil, err
}

b. 測試

// 數(shù)據(jù)簽名驗證
func TestVaSign(t *testing.T) {
    publicKeyPath := "../../tmp/public_ssl.pem"
    data := "123456"
    sign := "QnGqGbIqoHjJG1l+JiaOKWBdX+h00lnKCoO2rTYKIro9hoaDj7nqmu+Mxsuo+2jumicvCNBZNOpMzYryjZf0x7Q4ycLBtqtCWuFRasiInUO7Avy19LRTjdMf2xw9968vilB/xEAQ53JXIDUVvCsMxTfpHI9oRiWEGXWNkhfkjkQ="
    verifyRsaSign,err := crypto.VerifyRsaSign(data, publicKeyPath, sign)
    if err != nil {
        fmt.Printf("驗簽失敗: %v \n",err)
    }
    fmt.Printf("驗簽結(jié)果: %v \n",verifyRsaSign)
}
/** 輸出
=== RUN   TestVaSign
驗簽結(jié)果: true 
--- PASS: TestVaSign (0.00s)
PASS
*/
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市底哗,隨后出現(xiàn)的幾起案子岁诉,更是在濱河造成了極大的恐慌,老刑警劉巖跋选,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涕癣,死亡現(xiàn)場離奇詭異,居然都是意外死亡前标,警方通過查閱死者的電腦和手機坠韩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門距潘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人只搁,你說我怎么就攤上這事音比。” “怎么了氢惋?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵洞翩,是天一觀的道長。 經(jīng)常有香客問我明肮,道長菱农,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任柿估,我火速辦了婚禮循未,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘秫舌。我一直安慰自己的妖,他們只是感情好,可當我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布足陨。 她就那樣靜靜地躺著嫂粟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪墨缘。 梳的紋絲不亂的頭發(fā)上星虹,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天,我揣著相機與錄音镊讼,去河邊找鬼宽涌。 笑死,一個胖子當著我的面吹牛蝶棋,可吹牛的內(nèi)容都是我干的卸亮。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼玩裙,長吁一口氣:“原來是場噩夢啊……” “哼兼贸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起吃溅,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤溶诞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后决侈,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體螺垢,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了甩苛。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蹂楣。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖讯蒲,靈堂內(nèi)的尸體忽然破棺而出痊土,到底是詐尸還是另有隱情,我是刑警寧澤墨林,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布赁酝,位于F島的核電站,受9級特大地震影響旭等,放射性物質(zhì)發(fā)生泄漏酌呆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一搔耕、第九天 我趴在偏房一處隱蔽的房頂上張望隙袁。 院中可真熱鬧,春花似錦弃榨、人聲如沸菩收。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽娜饵。三九已至,卻和暖如春官辈,著一層夾襖步出監(jiān)牢的瞬間箱舞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工拳亿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留晴股,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓风瘦,卻偏偏與公主長得像队魏,于是被迫代替她去往敵國和親公般。 傳聞我的和親對象是個殘疾皇子万搔,可洞房花燭夜當晚...
    茶點故事閱讀 43,494評論 2 348

推薦閱讀更多精彩內(nèi)容