RSA非对称加密算法实现:Golang
RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。
RSA解决了对称加密的一个不足,比如AES算法加密和解密时使用的是同一个秘钥,因此这个秘钥不能公开,因此对于需要公开秘钥的场合,我们需要在加密和解密过程中使用不同的秘钥,加密使用的公钥可以公开,解密使用的私钥要保密,这就是非对称加密的好处。
常用的开发语言来实现RSA加密:
公钥与私钥
公钥与私钥是成对的,一般的,我们认为的是公钥加密、私钥解密、私钥签名、公钥验证,有人说成私钥加密,公钥解密时不对的。
公钥与私钥的生成有多种方式,可以通过程序生成(下文具体实现),可以通过openssl工具:
# 生成一个私钥,推荐使用1024位的秘钥,秘钥以pem格式保存到-out参数指定的文件中,采用PKCS1格式
openssl genrsa -out rsa.pem 1024
# 生成与私钥对应的公钥,生成的是Subject Public Key,一般配合PKCS8格式私钥使用
openssl rsa -in rsa.pem -pubout -out rsa.pub
RSA生成公钥与私钥一般有两种格式:PKCS1和PKCS8,上面的命令生成的秘钥是PKCS1格式的,而公钥是Subject Public Key,一般配合PKCS8格式私钥使用,所以就可能会涉及到PKCS1和PKCS8之间的转换:
# PKCS1格式私钥转换为PKCS8格式私钥,私钥直接输出到-out参数指定的文件中
openssl pkcs8 -topk8 -inform PEM -in rsa.pem -outform pem -nocrypt -out rsa_pkcs8.pem
# PKCS8格式私钥转换为PKCS1格式私钥,私钥直接输出到-out参数指定的文件中
openssl rsa -in rsa_pkcs8.pem -out rsa_pkcs1.pem # PKCS1格式公钥转换为PKCS8格式公钥,转换后的内容直接输出
openssl rsa -pubin -in rsa.pub -RSAPublicKey_out
# PKCS8格式公钥转换为PKCS1格式公钥,转换后的内容直接输出
openssl rsa -RSAPublicKey_in -pubout -in rsa.pub
现实中,我们往往从pem、crt、pfx文件获取公私和私钥,crt、pfx的制作可以参考:简单的制作ssl证书,并在nginx和IIS中使用,或者使用现成的:https://pan.baidu.com/s/1MJ5YmuZiLBnf-DfNR_6D7A (提取码:c6tj),密码都是:123456
Golang实现
为了方便读取pem、crt、pfx文件中的公私和私钥,这里我使用了第三方的包:golang.org/x/crypto/pkcs12,可以使用go get安装:go get -u golang.org/x/crypto/pkcs12
安装之后,封装一个工具包rsautil.go:
package rsautil import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"fmt"
"golang.org/x/crypto/pkcs12"
"io"
"io/ioutil"
"os"
"strconv"
) //从Pem文件中读取秘钥
func ReadFromPem(pemFile string) ([]byte, error) {
buffer, err := ioutil.ReadFile(pemFile)
if err != nil {
return nil, err
} block, _ := pem.Decode(buffer)
return block.Bytes, nil
} //从pfx文件中读取公私密钥(需要安装golang.org/x/crypto/pkcs12)
func ReadFromPfx(pfxFile, password string, usePKCS8 bool) ([]byte, []byte) {
buffer, err := ioutil.ReadFile(pfxFile)
if err != nil {
panic(err)
} privateKeyInterface, certificate, err := pkcs12.Decode(buffer, password)
if err != nil {
panic(err)
} privateKey := privateKeyInterface.(*rsa.PrivateKey)
publicKey := certificate.PublicKey.(*rsa.PublicKey) var (
privateKeyBuffer []byte
publicKeyBuffer []byte
)
if usePKCS8 {
privateKeyBuffer, err = x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
panic(err)
}
publicKeyBuffer, err = x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
panic(err)
}
} else {
privateKeyBuffer = x509.MarshalPKCS1PrivateKey(privateKey)
publicKeyBuffer = x509.MarshalPKCS1PublicKey(publicKey)
}
return publicKeyBuffer, privateKeyBuffer
} //从crt中读取公钥
func ReadPublicKeyFromCrt(crtFile string, usePKCS8 bool) ([]byte, error) {
buffer, err := ioutil.ReadFile(crtFile)
if err != nil {
return nil, err
}
certDERBlock, _ := pem.Decode(buffer)
certificate, err := x509.ParseCertificate(certDERBlock.Bytes)
if err != nil {
return nil, err
}
publicKey := certificate.PublicKey.(*rsa.PublicKey) var publicKeyBuffer []byte
if usePKCS8 {
publicKeyBuffer, err = x509.MarshalPKIXPublicKey(publicKey)
} else {
publicKeyBuffer = x509.MarshalPKCS1PublicKey(publicKey)
}
if err != nil {
return nil, err
}
return publicKeyBuffer, nil
} //将秘钥写入Pem文件
func WriteToPem(isPrivateKey bool, buffer []byte, pemFile string) error {
var _type string
if isPrivateKey {
_type = "RSA PRIVATE KEY"
} else {
_type = "RSA PUBLIC KEY"
} block := &pem.Block{
Type: _type, //这个字符串随便写
Bytes: buffer,
} file, err := os.Create(pemFile)
if err != nil {
return err
}
return pem.Encode(file, block)
} //Pkcs1转换为Pkcs8
func Pkcs1ToPkcs8(isPrivateKey bool, buffer []byte) []byte {
var (
oid = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
info interface{}
)
if isPrivateKey {
val := struct {
Version int
Algo []asn1.ObjectIdentifier
PrivateKey []byte
}{}
val.Version = 0
val.Algo = []asn1.ObjectIdentifier{oid}
val.PrivateKey = buffer
info = val
} else {
val := struct {
Algo pkix.AlgorithmIdentifier
BitString asn1.BitString
}{}
val.Algo.Algorithm = oid
val.Algo.Parameters = asn1.NullRawValue
val.BitString.Bytes = buffer
val.BitString.BitLength = 8 * len(buffer)
info = val
} b, err := asn1.Marshal(info)
if err != nil {
panic(err)
}
return b
} //Pkcs8转换为Pkcs1
func Pkcs8ToPkcs1(isPrivateKey bool, buffer []byte) []byte {
if isPrivateKey {
val := struct {
Version int
Algo pkix.AlgorithmIdentifier
PrivateKey []byte
}{}
_, err := asn1.Unmarshal(buffer, &val)
if err != nil {
panic(err)
}
return val.PrivateKey
} else {
val := struct {
Algo pkix.AlgorithmIdentifier
BitString asn1.BitString
}{} _, err := asn1.Unmarshal(buffer, &val)
if err != nil {
panic(err)
}
return val.BitString.Bytes
}
} //生成公私钥
//usePKCS8:是否使用pkcs8
func GenerateRsaKey(usePKCS8 bool) ([]byte, []byte) {
//生成私钥
privateKey, err := rsa.GenerateKey(rand.Reader, 1024) //1024位
if err != nil {
panic(err)
}
//公钥
publicKey := privateKey.PublicKey var (
privateKeyBuffer []byte
publicKeyBuffer []byte
) if usePKCS8 {
privateKeyBuffer, err = x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
panic(err)
}
publicKeyBuffer, err = x509.MarshalPKIXPublicKey(&publicKey)
if err != nil {
panic(err)
}
} else {
privateKeyBuffer = x509.MarshalPKCS1PrivateKey(privateKey)
publicKeyBuffer = x509.MarshalPKCS1PublicKey(&publicKey)
} return publicKeyBuffer, privateKeyBuffer
} func parsePkcsKey(buffer []byte, isPrivateKey, usePKCS8 bool) (interface{}, error) {
var (
err error
keyInterface interface{}
) if isPrivateKey {
if usePKCS8 {
keyInterface, err = x509.ParsePKCS8PrivateKey(buffer)
} else {
keyInterface, err = x509.ParsePKCS1PrivateKey(buffer)
}
} else {
if usePKCS8 {
keyInterface, err = x509.ParsePKIXPublicKey(buffer)
} else {
keyInterface, err = x509.ParsePKCS1PublicKey(buffer)
}
}
if err != nil {
return nil, err
}
return keyInterface, nil
} //RSA加密
func RsaEncrypt(value string, publicKey []byte, usePKCS8 bool) (string, error) {
keyInterface, err := parsePkcsKey(publicKey, false, usePKCS8)
if err != nil {
return "", err
}
rsaPublicKey := keyInterface.(*rsa.PublicKey)
buffer, err := rsa.EncryptPKCS1v15(rand.Reader, rsaPublicKey, []byte(value))
if err != nil {
return "", err
} //以hex格式数值输出
encryptText := fmt.Sprintf("%x", buffer)
return encryptText, nil
} //RSA解密
func RsaDecrypt(value string, privateKey []byte, usePKCS8 bool) (string, error) {
//将hex格式数据转换为byte切片
valueBytes := []byte(value)
var buffer = make([]byte, len(valueBytes)/2)
for i := 0; i < len(buffer); i++ {
b, err := strconv.ParseInt(value[i*2:i*2+2], 16, 10)
if err != nil {
return "", err
}
buffer[i] = byte(b)
} keyInterface, err := parsePkcsKey(privateKey, true, usePKCS8)
if err != nil {
return "", err
}
key := keyInterface.(*rsa.PrivateKey)
buffer, err = rsa.DecryptPKCS1v15(rand.Reader, key, buffer)
return string(buffer), nil
} //RSA签名
func Sign(value string, privateKey []byte, hash crypto.Hash, usePKCS8 bool) (string, error) {
keyInterface, err := parsePkcsKey(privateKey, true, usePKCS8)
if err != nil {
return "", err
}
key := keyInterface.(*rsa.PrivateKey) var _hash = hash.New()
if _, err := io.WriteString(_hash, value); err != nil {
return "", err
} hashed := _hash.Sum(nil)
result, err := rsa.SignPKCS1v15(rand.Reader, key, hash, hashed)
if err != nil {
return "", err
} //以hex格式数值输出
encryptText := fmt.Sprintf("%x", result)
return encryptText, nil
} //RSA验证签名
func Verify(value string, publicKey []byte, signature string, hash crypto.Hash, usePKCS8 bool) error {
//将hex格式数据转换为byte切片
valueBytes := []byte(signature)
var buffer = make([]byte, len(valueBytes)/2)
for i := 0; i < len(buffer); i++ {
b, err := strconv.ParseInt(signature[i*2:i*2+2], 16, 10)
if err != nil {
return err
}
buffer[i] = byte(b)
} keyInterface, err := parsePkcsKey(publicKey, false, usePKCS8)
if err != nil {
return err
} key := keyInterface.(*rsa.PublicKey) var _hash = hash.New()
if _, err := io.WriteString(_hash, value); err != nil {
return err
} hashed := _hash.Sum(nil)
return rsa.VerifyPKCS1v15(key, hash, hashed, buffer)
}
rsautil
可以使用生成RSA的公私秘钥:
//生成Rsa
publicKey, privateKey := rsautil.GenerateRsaKey(usePKCS8)
生成秘钥后,需要保存,一般保存到pem文件中:
//保存到Pem文件,filePath是文件目录
rsautil.WriteToPem(false, publicKey, filepath.Join(filePath, "rsa.pub"))
rsautil.WriteToPem(true, privateKey, filepath.Join(filePath, "rsa.pem"))
从pem文件中读取:
//从Pem文件读取秘钥,filePath是文件目录
publicKey, _ := rsautil.ReadFromPem(filepath.Join(filePath, "rsa.pub"))
privateKey, _ := rsautil.ReadFromPem(filepath.Join(filePath, "rsa.pem"))
还可以从crt证书中读取公钥,而crt文件不包含私钥,因此需要单独获取私钥:
//从crt文件中读取公钥,filePath是文件目录
publicKey, _ := rsautil.ReadPublicKeyFromCrt(filepath.Join(filePath, "demo.crt"), usePKCS8)
privateKey, _ := rsautil.ReadFromPem(filepath.Join(filePath, "demo.key"))
pfx文件中包含了公钥和私钥,可以很方便就读取到:
//从pfx文件中读取秘钥,filePath是文件目录
publicKey, privateKey := rsautil.ReadFromPfx(filepath.Join(filePath, "demo.pfx"), "123456", usePKCS8)
有时候我们还可能需要进行秘钥的转换:
//Pkcs8格式公钥转换为Pkcs1格式公钥
publicKey = rsautil.Pkcs8ToPkcs1(false, publicKey)
// Pkcs8格式私钥转换为Pkcs1格式私钥
privateKey = rsautil.Pkcs8ToPkcs1(true, privateKey)
// Pkcs1格式公钥转换为Pkcs8格式公钥
publicKey = rsautil.Pkcs1ToPkcs8(false, publicKey)
// Pkcs1格式私钥转换为Pkcs8格式私钥
privateKey = rsautil.Pkcs1ToPkcs8(true, privateKey)
有了公钥和私钥,接下就就能实现加密、解密、签名、验证签名等操作了:
encryptText, _ := rsautil.RsaEncrypt(text, publicKey, usePKCS8)
fmt.Printf("【%s】经过【RSA】加密后:%s\n", text, encryptText) decryptText, _ := rsautil.RsaDecrypt(encryptText, privateKey, usePKCS8)
fmt.Printf("【%s】经过【RSA】解密后:%s\n", encryptText, decryptText) signature, _ := rsautil.Sign(text, privateKey, crypto.MD5, usePKCS8)
fmt.Printf("【%s】经过【RSA】签名后:%s\n", text, signature) result := rsautil.Verify(text, publicKey, signature, crypto.MD5, usePKCS8) == nil
fmt.Printf("【%s】的签名【%s】经过【RSA】验证后结果是:"+strconv.FormatBool(result), text, signature)
完整的demo代码:
package main import (
"crypto"
"demo/rsautil"
"fmt"
"os"
"path/filepath"
"strconv"
) func main() {
text := "上山打老虎"
usePKCS8 := true // usePKCS8=true表示是否成PKCS8格式的公私秘钥,否则乘车PKCS1格式的公私秘钥
path, _ := os.Executable()
filePath := filepath.Dir(path)
fmt.Printf("文件路径:%s\n", filePath) // 存放pem,crt,pfx等文件的目录 //生成Rsa
publicKey, privateKey := rsautil.GenerateRsaKey(usePKCS8)
//从Pem文件读取秘钥,filePath是文件目录
//publicKey, _ := rsautil.ReadFromPem(filepath.Join(filePath, "rsa.pub"))
//privateKey, _ := rsautil.ReadFromPem(filepath.Join(filePath, "rsa.pem"))
//从pfx文件中读取秘钥,filePath是文件目录
//publicKey, privateKey := rsautil.ReadFromPfx(filepath.Join(filePath, "demo.pfx"), "123456", usePKCS8)
//从crt文件中读取公钥,filePath是文件目录
//publicKey, _ := rsautil.ReadPublicKeyFromCrt(filepath.Join(filePath, "demo.crt"), usePKCS8)
//privateKey, _ := rsautil.ReadFromPem(filepath.Join(filePath, "demo.key")) //保存到Pem文件,filePath是文件目录
rsautil.WriteToPem(false, publicKey, filepath.Join(filePath, "rsa.pub"))
rsautil.WriteToPem(true, privateKey, filepath.Join(filePath, "rsa.pem")) //Pkcs8格式公钥转换为Pkcs1格式公钥
publicKey = rsautil.Pkcs8ToPkcs1(false, publicKey)
// Pkcs8格式私钥转换为Pkcs1格式私钥
privateKey = rsautil.Pkcs8ToPkcs1(true, privateKey)
// Pkcs1格式公钥转换为Pkcs8格式公钥
publicKey = rsautil.Pkcs1ToPkcs8(false, publicKey)
// Pkcs1格式私钥转换为Pkcs8格式私钥
privateKey = rsautil.Pkcs1ToPkcs8(true, privateKey) encryptText, _ := rsautil.RsaEncrypt(text, publicKey, usePKCS8)
fmt.Printf("【%s】经过【RSA】加密后:%s\n", text, encryptText) decryptText, _ := rsautil.RsaDecrypt(encryptText, privateKey, usePKCS8)
fmt.Printf("【%s】经过【RSA】解密后:%s\n", encryptText, decryptText) signature, _ := rsautil.Sign(text, privateKey, crypto.MD5, usePKCS8)
fmt.Printf("【%s】经过【RSA】签名后:%s\n", text, signature) result := rsautil.Verify(text, publicKey, signature, crypto.MD5, usePKCS8) == nil
fmt.Printf("【%s】的签名【%s】经过【RSA】验证后结果是:"+strconv.FormatBool(result), text, signature)
}
RSA非对称加密算法实现:Golang的更多相关文章
- RSA非对称加密算法实现:Python
RSA是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.当时他们三人都在麻省理工学院工作.RSA ...
- RSA非对称加密算法实现:C#
RSA是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.当时他们三人都在麻省理工学院工作.RSA ...
- RSA非对称加密算法实现:Java
RSA是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.当时他们三人都在麻省理工学院工作.RSA ...
- RSA—非对称加密算法
RSA:非对称加密算法加解密原理如下:已知:p,q,n,e,d,m,c其中:p与q互为大质数,n=p*q 公钥Pk(n,e):加密使用,是公开的 私钥Sk(n,d):解密使用,不公开 c:明文 m:密 ...
- SSH加密原理、RSA非对称加密算法学习与理解
首先声明一下,这里所说的SSH,并不是Java传统的三大框架,而是一种建立在应用层和传输层基础上的安全外壳协议,熟悉Linux的朋友经常使 用到一 个SSH Secure Shell Cilent的工 ...
- RSA非对称加密算法实现过程
RSA非对称加密算法实现过程 非对称加密算法有很多,RSA算法就是其中比较出名的算法之一,下面是具体实现过程 <?php /** */ class Rsa { /** * private key ...
- RSA 非对称加密算法简述
RSA概述 首先看这个加密算法的命名.很有意思,它其实是三个人的名字.早在1977年由麻省理工学院的三位数学家Rivest.Shamir 和 Adleman一起提出了这个加密算法,并且用他们三个人姓氏 ...
- .NET Core加解密实战系列之——RSA非对称加密算法
目录 简介 功能依赖 生成RSA秘钥 PKCS1格式 PKCS8格式 私钥操作 PKCS1与PKCS8格式互转 PKCS1与PKCS8私钥中提取公钥 PEM操作 PEM格式密钥读取 PEM格式密钥写入 ...
- 【转载】非对称加密过程详解(基于RSA非对称加密算法实现)
1.非对称加密过程: 假如现实世界中存在A和B进行通讯,为了实现在非安全的通讯通道上实现信息的保密性.完整性.可用性(即信息安全的三个性质),A和B约定使用非对称加密通道进行通讯,具体 ...
随机推荐
- Linux基础命令---elinks文本浏览器
elinks elinks指令是一个纯文本格式的浏览器,支持颜色.表格.鼠标.菜单操作. 此命令的适用范围:RedHat.RHEL.Ubuntu.CentOS.Fedora. 1.语法 ...
- sax方式解析XML学习笔记
原理:对文档进行顺序扫描,当扫描到文档(document)开始与结束,元素开始与结束.文档结束等地方 通知事件处理函数,由事件处理函数相应动作然后继续同样的扫描,直至文档结束. 优点:消耗资源比较少: ...
- 使用递归方法,遍历输出以.java结尾的文件
package cn.itcast.demo01;import java.io.File;/** * @author newcityman * @date 2019/7/27 - 19:17 * 题目 ...
- Mysql主从复制参数详解
目录 一.简介 二.例子 同步 修改 三.参数 一.简介 change master to配置和改变slave服务器用于连接master服务器的参数,以便slave服务器读取master服务器的bin ...
- Tableau如何绘制堆叠柱状图
一.将类别,子类别拖拽至列上 二.将度量值拖拽至行上 三.将度量名称拖拽至筛选器上,右键度量名称,编辑筛选器,选择销售额 四.将事先准备的目标销售额拖拽至度量值 五.将度量名称拖拽至标记,分别以颜色和 ...
- <转>git,github在windows上的搭建
http://www.cnblogs.com/yixiaoyang/archive/2012/01/06/2314190.html Git在源码管理领域目前占很大的比重了,而且开源的项目很多都转到Gi ...
- JS 双向数据绑定、单项数据绑定
简单的双向数据绑定 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- [BUUCTF]PWN21——ciscn_2019_s_3
[BUUCTF]PWN21--ciscn_2019_s_3 附件 步骤 例行检查,64位,开启了NX保护 试运行的时候回显是一些乱码,直接用ida打开,从main函数开始看 main函数调用了vuln ...
- CTF 自动拼图
忘记在哪个群里面看见有师傅说过这样一句加,百度搜索"CTF拼图脚本,有惊喜". 在做JUSTCTF的题时候,看到一道拼图题.就想着试一试. 先百度搜了,看到了fjh1997师傅的一 ...
- [BUUCTF]REVERSE——内涵的软件
内涵的软件 附件 例行检查,32位程序 32位ida载入,shift+f12检索程序里的字符串 看到一个很像flag的字符串,拿去尝试一下,成功 flag{49d3c93df25caad8123213 ...