7 Go密码学(四) 非对称加密之RSA

一、非对称加密概述

对称加密有非常好的安全性,其加解密计算的性能也较高,但其有两个重要缺点:

  • 加密的安全性依赖于秘钥的长度及复杂度;
  • 秘钥分发问题。

在如今开放的信息社会,秘钥的管理愈加困难,非公开的秘钥机制虽然破解较难,但还是有遭到攻击的可能性,由于对称加密需要加解密双方共同握有私钥,所有生成秘钥的一方必须分发给另一方才能进行安全通行,这就难免秘钥在网络中传输,网络是不可靠的,其有可能被拦截或篡改。于是就产生了公开秘钥体制,即服务方根据特定算法产生一对钥匙串,自己持有私钥小心保存,而公钥公开分发,在通信中,由公钥加密进行网络传输,而传输的信息只能由私钥解密,这就解决了秘钥分发的问。公开秘钥体制就是非对称加密,非对称加密一般有两种用途:

  • 安全信息传输:客户方持有公钥,通过公钥加密后发送给服务方,服务方通过私钥解密看到信息。
  • 数字签名:服务方持有公钥,客户方持有私钥,由服务方使用公钥进行数字签名,发送到客户方只能由私钥解密,这就保证了信息发送方来源安全的问题。

如今的非对称加密比较可靠的有RSA算法和ECC算法(椭圆曲线算法),RSA的受众最多,但近年来随着比特币、区块链的兴起,ECC加密算法也越来越受到青睐。下面我们先介绍一下RSA加密算法的使用,ECC我们下一讲展开。

二、RSA加解密算法概述

RSA公开密钥密码体制。所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,由于无法计算出大数n的欧拉函数phi(N),所以不能根据PK计算出SK。
正是基于这种理论,1978年出现了著名的RSA算法,它通常是先生成一对RSA 密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可在网络服务器中注册。为提高保密强度,RSA密钥至少为500位长,一般推荐使用1024位。这就使加密的计算量很大。为减少计算量,在传送信息时,常采用传统加密方法与公开密钥加密方法相结合的方式,即信息采用改进的DES或IDEA密钥加密,然后使用RSA密钥加密对话密钥和信息摘要。对方收到信息后,用不同的密钥解密并可核对信息摘要。
RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操作。RSA是被研究得最广泛的公钥算法,从提出到现今的三十多年里,经历了各种攻击的考验,逐渐为人们接受,截止2017年被普遍认为是最优秀的公钥方案之一。

RSA加解密图解

公钥密码体系都是要基于一个困难问题来保证其安全性的,RSA是基于大数分解,将一个即使是计算机也无能为力的数学问题作为安全壁垒是现代密码学的实现原理。讲述这类数学问题需要庞杂的数论基础,此相关部分在此不再展开,感兴趣的请出门右拐搜索欧几里得证明、欧拉函数等数论部分知识。

三、Go中使用RSA加解密

Go标准库中crypto/rsa包实现了RSA加解密算法,并通过crypto/x509包实现私钥序列化为ASN.1的DER编码字符串的方法,我们还使用编解码包encoding/pem(实现了PEM数据编码,该格式源自保密增强邮件协议,目前PEM编码主要用于TLS密钥和证书。)将公私钥数据编码为pem格式的证书文件。

X.509是一种非常通用的证书格式。所有的证书都符合ITU-T X.509国际标准,因此(理论上)为一种应用创建的证书可以用于任何其他符合X.509标准的应用。

PEM是存储证书和密钥的文件格式。PEM实质上是Base64编码的二进制内容

1.生成RSA公私钥文件
import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "encoding/pem"
    "os"
)

const (
    PRIVATEFILE = "src/cryptography/myRSA/privateKey.pem"
    PUBLICFILE  = "src/cryptography/myRSA/publicKey.pem"
)

//生成公钥和私钥文件

func GenerateKey(bits int) error {
    //生成私钥
    //使用rsa中的GenerateKey方法生成私钥
    privateKey, err := rsa.GenerateKey(rand.Reader, bits)
    if err != nil {
        return err
    }

    //通过x509标准将得到的ras私钥序列化为ASN.1的DER编码字符串
    PKCS1PrivateBytes := x509.MarshalPKCS1PrivateKey(privateKey)

    //将私钥字符串设置到pem格式块中
    privateBlock := pem.Block{
        Type:  "RSA Private Key",
        Bytes: PKCS1PrivateBytes,
    }

    //通过pem将设置好的数据进行编码,并写入磁盘文件
    privateFile, err := os.Create(PRIVATEFILE)
    if err != nil {
        return err
    }
    defer privateFile.Close()
    err = pem.Encode(privateFile, &privateBlock)
    if err != nil {
        return err
    }

    //生成公钥
    //从得到的私钥对象中将公钥信息取出
    publicKey := privateKey.PublicKey

    //通过x509标准将得到的ras公钥序列化为ASN.1的DER编码字符串
    PKCS1PublicBytes, err := x509.MarshalPKIXPublicKey(&publicKey)
    if err != nil {
        return err
    }

    //将公钥字符串设置到pem格式块中
    publicBlock := pem.Block{
        Type:  "RSA Public Key",
        Bytes: PKCS1PublicBytes,
    }

    //通过pem将设置好的数据进行编码,并写入磁盘文件
    publicFile, err := os.Create(PUBLICFILE)
    if err != nil {
        return err
    }
    defer publicFile.Close()
    err = pem.Encode(publicFile, &publicBlock)
    if err != nil {
        return err
    }

    return nil
}

2.实现公钥加密,私钥解密的加密通信机制
//公钥加密
func LockWithPublicKey(src []byte, pubKeyFile string) ([]byte, error) {
    var err error
    //将公钥文件中的公钥读出,得到使用pem编码的字符串
    file, err := os.Open(pubKeyFile)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    fileInfo, err := file.Stat()
    if err != nil {
        return nil, err
    }

    buffer := make([]byte, fileInfo.Size())
    _, err = file.Read(buffer)
    if err != nil {
        return nil, err
    }
    //将得到的字符串解码
    block, _ := pem.Decode(buffer)

    //使用x509将编码之后的公钥解析出来
    pubInner, err := x509.ParsePKIXPublicKey(block.Bytes)
    if err != nil {
        return nil, err
    }

    publicKey := pubInner.(*rsa.PublicKey)

    //使用得到的公钥通过rsa进行数据加密
    encryptBytes, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, src)

    return encryptBytes, nil
}
//私钥解密
func UnlockWithPrivateKey(src []byte, privateKeyFile string) ([]byte, error) {
    //将私钥文件中的私钥读出,得到使用pem编码的字符串
    file, err := os.Open(privateKeyFile)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    fileInfo, err := file.Stat()
    if err != nil {
        return nil, err
    }
    size := fileInfo.Size()
    buffer := make([]byte, size)
    _, err = file.Read(buffer)
    if err != nil {
        return nil, err
    }
    //将得到的字符串解码
    block, _ := pem.Decode(buffer)

    //使用x509将编码之后的私钥解析出来
    privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        return nil, err
    }

    //使用得到的私钥通过rsa进行数据解密
    decryptBytes, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, src)

    return decryptBytes, nil
}

使用以上加解密方法:

//测试RSA非对称加解密信息,公钥加密,私钥解密
func TestRSA() {
    //生成钥匙对
    err := myRSA.GenerateKey(4096)
    if err != nil {
        fmt.Println(err)
    }

    srcInfo := "GO 密码学 —— RSA非对称加解密测试"

    //公钥加密
    encryptBytes, err := myRSA.LockWithPublicKey([]byte(srcInfo), myRSA.PUBLICFILE)
    if err != nil {
        fmt.Println(err)
    }

    //私钥解密
    decryptBytes, err := myRSA.UnlockWithPrivateKey(encryptBytes, myRSA.PRIVATEFILE)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println("测试非对称加密结果:")
    fmt.Println("元数据:", srcInfo)
    encryptHex := hex.EncodeToString(encryptBytes)
    fmt.Println("公钥加密数据:", encryptHex)
    fmt.Println("私钥解密数据:", string(decryptBytes))

}

//首先会在规定的目录生成钥匙对文件:privateKey.pem、publicKey.pem

OUTPUT:
测试非对称加密结果:
元数据: GO 密码学 —— RSA非对称加解密测试
公钥加密数据: 582a4c0a2acdfb61cf2ee28bf6e85696b11415c5d84b515548268d15789752da50cc82dade81062bdbaccfeee227120eaf0cf4fcc46d174ccd1187a0a1318c987cc5f722bc8abeb9f425d3b890d6842dcda6731e9527528e9bdbbbe84220d972fb07049c1b7c5615731d5b61b148f42800d7c30ef5812da80d7b54bdea1ef93388d4eab33ccccb518da205672e3e9d9a2196b41cb000fc53c21e6a75f34ba2d5d941aac4f6cec9cdfd2ed443fe3207f32d636b4973ed94cc9d12362c55e399eea8163f253210ac8ff05b456046e643bdc26ca50648c2337b56399b5f4296903ca58fb0149fbbfb4ecf9c88d7d8b0beb2e0ea60fa2d3df2b7ffd0987259e720627f7f51070412a2d1e4da75c3dc7de2b9010b3f45e7b40c4f681621fd5aa686081e91fc00d578c0b7c8c41738c3d9b7655abc9963fd2d72f4006d0ad0af4e6e832868296fbe36098c8f226c6bc4557250039e6d631234bf7dabf7df9352d0b42e04cce8dc0d24961e927b996b99d87cf786cc48e865e4c093fc65f5fc047fea2141e5fc3648ae30ef7fc51837e4494954d7535512109ed7ed59e3fbf4e39b1e38a0bef1a771bcba656e77e1d6e522bf813cbf11715e1e781dd0e99f1c8ed5dce856ef1468e3a519c191c476ab778147a6ea9a6c311a9bf17beca2d80712180564d0986c6d02022e3640b8128f1cc4ea473aec79f5c7bd865b4de5c9e33cd9909d
私钥解密数据: GO 密码学 —— RSA非对称加解密测试

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355

推荐阅读更多精彩内容