非對稱加密之RSA(go語言)

1. 簡介

在對稱密碼中缠沈,由于加密和解密的密鑰是相同的,因此必須向接收者配送密鑰。用于解密的密鑰必須被配送給
接收者饲趋,這一問題稱為密鑰配送問題拐揭。如果使用非對稱加密也可以稱為公鑰密碼,則無需向接收者配送用于解
密的密鑰奕塑,這樣就解決了密鑰配送問題堂污。可以說非對稱加密是密碼學(xué)歷史上最偉大的發(fā)明爵川。

非對稱加密中敷鸦,密鑰分為加密密鑰和解密密鑰兩種。發(fā)送者用加密密鑰對消息進(jìn)行加密寝贡,接收者用解密密鑰對
密文進(jìn)行解密扒披。要理解公鑰密碼,清楚地區(qū)分加密密鑰和解密密鑰是非常重要的圃泡。加密密鑰是發(fā)送者加密時使
用的碟案,而解密密鑰則是接收者解密時使用的。

仔細(xì)思考一下加密密鑰和解密密鑰的區(qū)別颇蜡,我們可以發(fā)現(xiàn):

  • 發(fā)送者只需要加密密鑰
    • 接收者只需要解密密鑰
    • 解密密鑰不可以被竊聽者獲取
  • 加密密鑰被竊聽者獲取也沒問題

也就是說价说,解密密鑰從一開始就是由接收者自己保管的,因此只要將加密密鑰發(fā)給發(fā)送者就可以解決密鑰配送
問題了风秤,而根本不需要配送解密密鑰鳖目。

RSA是一種非對稱加密算法,它的名字是由它的三位開發(fā)者缤弦,即RonRivest领迈、AdiShamir和LeonardAdleman 的姓氏 的首字母組成的(Rivest-Shamir-Leonard)。

2. RSA加密

在RSA中碍沐,明文狸捅、密鑰和密文都是數(shù)字。RSA的 加密過程可以用下列公式來表達(dá)累提,如下尘喝。

密文 = 明文^E mod N

也就是說,RSA的密文是對代表明文的數(shù)字的E次方求modN的結(jié)果斋陪。換句話說朽褪,就是將明文自己做E次乘法,然 后將其結(jié)果除以N求余數(shù)无虚,這個余數(shù)就是密文鞍匾。

加密公式中出現(xiàn)的兩個數(shù)一一一E和N,到底都是什么數(shù)呢?RSA的加密是求明文的E次方modN骑科,因此只 要知道E和N這兩個數(shù)橡淑,任何人都可以完成加密的運(yùn)算。所以說咆爽,E和N是RSA加密的密鑰梁棠,也就是說置森, E和N的組 合就是公鑰 。

不過符糊,E和N并不是隨便什么數(shù)都可以的凫海,它們是經(jīng)過嚴(yán)密計算得出的。

有一個很容易引起誤解的地方需要大家注意一一E和N這兩個數(shù)并不是密鑰對(公鑰和私鑰的密鑰對)男娄。E和N兩 個數(shù)才組成了一個公鑰行贪,因此我們一般會寫成 “公鑰是(E,N)” 或者 “公鑰是{E, N}" 這樣的形式模闲,將E和N用括號 括起來建瘫。

3. RSA解密

RSA的解密和加密一樣簡單,可以用下面的公式來表達(dá)

明文 = 密文^D mod N

也就是說尸折,對表示密文的數(shù)字的D次方求modN就可以得到明文啰脚。換句話說,將密文自己做D次乘法实夹,再對其結(jié)果 除以N求余數(shù)橄浓,就可以得到明文。

這里所使用的數(shù)字N和加密時使用的數(shù)字N是相同的亮航。 數(shù)D和數(shù)N組合起來就是RSA的解密密鑰荸实,因此D和N的組合 就是私鑰 。只有知道D和N兩個數(shù)的人才能夠完成解密的運(yùn)算缴淋。

在RSA中准给,加密和解密的形式是相同的。加密是求 "E次方的mod N”宴猾,而解密則是求 "D次 方的modN” 。

當(dāng)然叼旋,D也并不是隨便什么數(shù)都可以的仇哆,作為解密密鑰的D,和數(shù)字E有著相當(dāng)緊密的聯(lián)系夫植。否則讹剔,用E加密的結(jié) 果可以用D來解密這樣的機(jī)制是無法實(shí)現(xiàn)的。


RSA加密解密.png

4. Go中生成公鑰和私鑰

  • 生成私鑰操作流程概述:
  1. 使用rsa中的GenerateKey方法生成私鑰
  2. 通過x509標(biāo)準(zhǔn)將得到的ras私鑰序列化為ASN.1 的 DER編碼字符串
  3. 將私鑰字符串設(shè)置到pem格式塊中
  4. 通過pem將設(shè)置好的數(shù)據(jù)進(jìn)行編碼, 并寫入磁盤文件中
  • 生成公鑰操作流程:
  1. 從得到的私鑰對象中將公鑰信息取出
  2. 通過x509標(biāo)準(zhǔn)將得到 的rsa公鑰序列化為字符串
  3. 將公鑰字符串設(shè)置到pem格式塊中
  4. 通過pem將設(shè)置好的數(shù)據(jù)進(jìn)行編碼, 并寫入磁盤文件
  • 生成公鑰和私鑰的源代碼:
/*
 * 生成RSA公鑰和私鑰并保存在對應(yīng)的目錄文件下
 * 參數(shù)bits: 指定生成的秘鑰的長度, 單位: bit
 */

func RsaGenKey(bits int, privatePath,pubulicPath string) error {
    // 1. 生成私鑰文件
    // GenerateKey函數(shù)使用隨機(jī)數(shù)據(jù)生成器random生成一對具有指定字位數(shù)的RSA密鑰
    privateKey, err := rsa.GenerateKey(rand.Reader, bits)
    if err != nil {
        return err
    }
    // 2. MarshalPKCS1PrivateKey將rsa私鑰序列化為ASN.1 PKCS#1 DER編碼
    derPrivateStream := x509.MarshalPKCS1PrivateKey(privateKey)

    // 3. Block代表PEM編碼的結(jié)構(gòu), 對其進(jìn)行設(shè)置
    block := pem.Block{
        Type:  "RSA PRIVATE KEY",
        Bytes: derPrivateStream,
    }

    // 4. 創(chuàng)建文件
    privateFile, err := os.Create(privatePath)
    defer privateFile.Close()

    if err != nil {
        return err
    }

    // 5. 使用pem編碼, 并將數(shù)據(jù)寫入文件中
    err = pem.Encode(privateFile, &block)
    if err != nil {
        return err
    }

    // 1. 生成公鑰文件
    publicKey := privateKey.PublicKey
    derPublicStream, err := x509.MarshalPKIXPublicKey(&publicKey)
    if err != nil {
        return err
    }

    block = pem.Block{
        Type:  "RSA PUBLIC KEY",
        Bytes: derPublicStream,
    }

    publicFile, err := os.Create(pubulicPath)
    defer publicFile.Close()

    if err != nil {
        return err
    }

    // 2. 編碼公鑰, 寫入文件
    err = pem.Encode(publicFile, &block)
    if err != nil {
        panic(err)
        return err
    }
    return nil
}

測試代碼:

func testGenRSA()  {
    rsa.RsaGenKey(2048, "privateKey.pem","pubulicKey.pem")
}

5. Go中使用RSA

5.1. 操作步驟

  • 公鑰加密
  1. 將公鑰文件中的公鑰讀出, 得到使用pem編碼的字符串
  2. 將得到的字符串解碼
  3. 使用x509將編碼之后的公鑰解析出來
  4. 使用得到的公鑰通過rsa進(jìn)行數(shù)據(jù)加密
  • 公鑰解密
  1. 將私鑰文件中的私鑰讀出, 得到使用pem編碼的字符串
  2. 將得到的字符串解碼
  3. 使用x509將編碼之后的私鑰解析出來
  4. 使用得到的私鑰通過rsa進(jìn)行數(shù)據(jù)解密

5.2. 代碼實(shí)現(xiàn)

  • RSA公鑰加密
/*
 * RSA公鑰加密
 */
func RSAEncrypt(src []byte, filename string) ([]byte, error)  {
    // 根據(jù)文件名讀出文件內(nèi)容
    file, err := os.Open(filename)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    info, _ := file.Stat()
    buf := make([]byte, info.Size())
    file.Read(buf)

    // 從數(shù)據(jù)中找出pem格式的塊
    block, _ := pem.Decode(buf)
    if block == nil {
        return nil, err
    }

    // 解析一個der編碼的公鑰
    publicKey, err := x509.ParsePKCS1PublicKey(block.Bytes)
    if err != nil {
        return nil, err
    }

    // 公鑰加密
    result, _ := rsa.EncryptPKCS1v15(rand.Reader, publicKey, src)
    return result, nil

}
  • RSA私鑰解密
/*
 * RSA私鑰解密
 */
func RSADecrypt(src []byte, filename string) ([]byte, error) {
    // 根據(jù)文件名讀出內(nèi)容
    file, err := os.Open(filename)
    if err != nil {
        return nil,err
    }
    defer file.Close()

    info, _ := file.Stat()
    buf := make([]byte, info.Size())
    file.Read(buf)

    // 從數(shù)據(jù)中解析出pem塊
    block, _ := pem.Decode(buf)
    if block == nil {
        return nil,err
    }

    // 解析出一個der編碼的私鑰
    privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)


    // 私鑰解密
    result, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, src)
    if err != nil {
        return nil,err
    }
    return result,nil
}
  • 測試代碼:
func testRSA()  {
    msg := "二愣子抗日"
    cipherText, _:= rsa.RSAEncrypt([]byte(msg), "publicKey.pem")
    fmt.Println(string(cipherText))

    plainText, _:= rsa.RSADecrypt(cipherText, "privateKey.pem")
    fmt.Println(string(plainText))
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末详民,一起剝皮案震驚了整個濱河市延欠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌沈跨,老刑警劉巖由捎,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異饿凛,居然都是意外死亡狞玛,警方通過查閱死者的電腦和手機(jī)软驰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來心肪,“玉大人锭亏,你說我怎么就攤上這事∮舶埃” “怎么了慧瘤?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長固该。 經(jīng)常有香客問我锅减,道長,這世上最難降的妖魔是什么蹬音? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任上煤,我火速辦了婚禮,結(jié)果婚禮上著淆,老公的妹妹穿的比我還像新娘劫狠。我一直安慰自己,他們只是感情好永部,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布独泞。 她就那樣靜靜地躺著,像睡著了一般苔埋。 火紅的嫁衣襯著肌膚如雪懦砂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天组橄,我揣著相機(jī)與錄音荞膘,去河邊找鬼。 笑死玉工,一個胖子當(dāng)著我的面吹牛羽资,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播遵班,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼屠升,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了狭郑?” 一聲冷哼從身側(cè)響起腹暖,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎翰萨,沒想到半個月后脏答,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年以蕴,在試婚紗的時候發(fā)現(xiàn)自己被綠了糙麦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡丛肮,死狀恐怖赡磅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宝与,我是刑警寧澤焚廊,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站习劫,受9級特大地震影響咆瘟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜诽里,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一袒餐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谤狡,春花似錦灸眼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至捕仔,卻和暖如春匕积,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背榜跌。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工闪唆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人钓葫。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓悄蕾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瓤逼。 傳聞我的和親對象是個殘疾皇子笼吟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評論 2 355