当前位置:网站首页>RSA 加密解密签名验签
RSA 加密解密签名验签
2022-04-23 09:04:00 【Asimov__】
api
package v1
// get请求
import "github.com/gogf/gf/v2/frame/g"
type GetKeyReq struct {
g.Meta `path:"/get_key" method:"get" summary:"获取公钥" tags:"RSA"`
Name string `json:"name" v:"required#账号" dc:"账号"`
}
type GetKeyRes struct {
//g.Meta `mime:"text/html" type:"string" example:"<html/>"`
Result string `json:"result" dc:"返回公钥"`
Public string `json:"public" dc:"公钥"`
}
type GetKeyPriReq struct {
g.Meta `path:"/get_key_pri" method:"get" summary:"获取公钥" tags:"RSA"`
}
type GetKeyPriRes struct {
//g.Meta `mime:"text/html" type:"string" example:"<html/>"`
Result string `json:"result" dc:"返回公钥"`
Public string `json:"public" dc:"公钥"`
Private string `json:"private" dc:"公钥"`
}
type PostPublicKeyReq struct {
g.Meta `path:"/push_key" method:"post" summary:"用户上传公钥" tags:"RSA"`
Public string `json:"public" v:"required#公钥" dc:"公钥"`
Name string `json:"name" v:"required#账号" dc:"账号"`
}
type PostPublicKeyRes struct {
Result string `json:"result" dc:"结果"`
}
type VerifyReq struct {
g.Meta `path:"/verify" method:"post" summary:"验签" tags:"RSA"`
Sign string `json:"sign" v:"required#签名" dc:"签名"`
Name string `json:"name" v:"required#账号" dc:"账号"`
Data string `json:"data" v:"required#签署信息" dc:"签署信息"`
}
type VerifyRes struct {
Result bool `json:"result" dc:"验签结果"`
}
type DecryptReq struct {
g.Meta `path:"/decrypt" method:"post" summary:"解密" tags:"RSA"`
Secret string `json:"secret" v:"required#密文" dc:"密文"`
Name string `json:"name" v:"required#账号" dc:"账号"`
PublicKey string `json:"publickey" v:"required#公钥" dc:"公钥"`
}
type DecryptRes struct {
Result string `json:"result" dc:"解密结果"`
}
controller
package controller
import (
"context"
"crypto"
v1 "firstproject/api/v1"
"firstproject/internal/service"
)
var (
Rsa = cRsa{}
)
type cRsa struct{}
// 获取公钥
func (c *cRsa) GetKey(ctx context.Context, req *v1.GetKeyReq) (res *v1.GetKeyRes, err error) {
//context.WithValue(ctx, "name", req.Name)
res = &v1.GetKeyRes{}
pub := service.Rsa().GetKey(ctx, req.Name, 2048)
res.Public = pub
res.Result = "success"
return
}
// 生成公私钥
func (c *cRsa) GetKeyPri(ctx context.Context, req *v1.GetKeyPriReq) (res *v1.GetKeyPriRes, err error) {
//context.WithValue(ctx, "name", req.Name)
res = &v1.GetKeyPriRes{}
pri, pub := service.Rsa().GetKeyPri(ctx, 2048)
res.Public = pub
res.Private = pri
res.Result = "success"
return
}
// push 私钥
func (c *cRsa) PushKey(ctx context.Context, req *v1.PostPublicKeyReq) (res *v1.PostPublicKeyRes, err error) {
res = &v1.PostPublicKeyRes{}
err = service.Rsa().Pushkey(ctx, req.Public, req.Name)
if err != nil {
res.Result = "push public failed"
return
} else {
res.Result = "push public success"
return
}
}
// 解密
func (c *cRsa) Decrypt(ctx context.Context, req *v1.DecryptReq) (res *v1.DecryptRes, err error) {
res = &v1.DecryptRes{}
secret := []byte(req.Secret)
if secret_, err := service.Rsa().Decrypt(secret, req.Name, req.PublicKey); err != nil {
res.Result = "Decrypt failed"
return res, err
} else {
res.Result = "Decrypt success:" + string(secret_)
return res, nil
}
}
// 验签
func (c *cRsa) Verify(ctx context.Context, req *v1.VerifyReq) (res *v1.VerifyRes, err error) {
res = &v1.VerifyRes{}
sign := []byte(req.Sign)
data := []byte(req.Data)
result := service.Rsa().Verify(data, sign, crypto.SHA256, req.Name)
res.Result = result
return
}
model
package entity
// User is the golang structure for table user.
type User struct {
Id int64 `json:"id" description:"UID"`
Name string `json:"name" description:"账号"`
Password string `json:"password" description:"MD5密码"`
Nickename string `json:"nickename" description:"昵称"`
Status int `json:"status" description:"状态0:启用 1:禁用"`
Cpublickey string `json:"cpublickey" description:""`
Sprivatekey string `json:"sprivatekey" description:""`
}
service
package service
import (
"bytes"
"context"
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"firstproject/internal/model/entity"
"firstproject/internal/service/internal/dao"
"fmt"
"github.com/gogf/gf/v2/os/gctx"
"strings"
)
// RAS管理服务
func Rsa() *sRsa {
return &sRsa{}
}
type sRsa struct {
}
/**
* 解密
*/
func (s *sRsa) Decrypt(secretData []byte, name, publicKey string) ([]byte, error) {
var (
user *entity.User
ctx = gctx.New()
)
err := dao.User.Ctx(ctx).Fields("sprivatekey").Where("name=?", name).Limit(1).Scan(&user)
if err != nil {
return nil, err
}
// 解码将找到下一个PEM格式化块(证书,私钥,etc)
block, _ := pem.Decode([]byte(user.Sprivatekey))
var rsaPrivateKey *rsa.PrivateKey
// 判断私钥类型
//pkcs1
if strings.Index(user.Sprivatekey, "BEGIN RSA") > 0 {
rsaPrivateKey, _ = x509.ParsePKCS1PrivateKey(block.Bytes)
} else { //pkcs8
privateKey, _ := x509.ParsePKCS8PrivateKey(block.Bytes)
rsaPrivateKey = privateKey.(*rsa.PrivateKey)
}
// 提取公钥
block_, _ := pem.Decode([]byte(publicKey))
publicKey_, _ := x509.ParsePKIXPublicKey(block_.Bytes)
rsaPublicKey := publicKey_.(*rsa.PublicKey)
blockLength := rsaPublicKey.N.BitLen() / 8
// 服务端用给客户端公钥对应的私钥解密(如果公钥被拦截 无法识别用户 需要用到签名)
if len(secretData) <= blockLength {
return rsa.DecryptPKCS1v15(rand.Reader, rsaPrivateKey, secretData)
}
buffer := bytes.NewBufferString("")
pages := len(secretData) / blockLength
for index := 0; index <= pages; index++ {
start := index * blockLength
end := (index + 1) * blockLength
if index == pages {
if start == len(secretData) {
continue
}
end = len(secretData)
}
chunk, err := rsa.DecryptPKCS1v15(rand.Reader, rsaPrivateKey, secretData[start:end])
if err != nil {
return nil, err
}
buffer.Write(chunk)
}
return buffer.Bytes(), nil
}
/**
* 验签 服务端用客户端事先给服务端的公钥和签名 验签 (验签完成后才会去执行解密数据)
*/
func (s *sRsa) Verify(data []byte, sign []byte, algorithmSign crypto.Hash, name string) bool {
var (
user *entity.User
ctx = gctx.New()
)
err := dao.User.Ctx(ctx).Fields("cpublickey").Where("name=?", name).Limit(1).Scan(&user)
if err != nil {
return false
}
// 提取公钥
block, _ := pem.Decode([]byte(user.Cpublickey))
publicKey, _ := x509.ParsePKIXPublicKey(block.Bytes)
rsaPublicKey := publicKey.(*rsa.PublicKey)
h := algorithmSign.New()
h.Write(data)
// 用c端用户公钥和签名做验签
// 客户公钥需要保存在服务端
return rsa.VerifyPKCS1v15(rsaPublicKey, algorithmSign, h.Sum(nil), sign) == nil
}
/**
* 生成pkcs1格式公钥私钥
*/
func (s *sRsa) CreateKeys(keyLength int) (privateKey, publicKey string) {
// 随机生成密钥对
rsaPrivateKey, err := rsa.GenerateKey(rand.Reader, keyLength)
if err != nil {
return
}
privateKey = string(pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
//pkcs1
Bytes: x509.MarshalPKCS1PrivateKey(rsaPrivateKey),
}))
derPkix, err := x509.MarshalPKIXPublicKey(&rsaPrivateKey.PublicKey)
if err != nil {
return
}
publicKey = string(pem.EncodeToMemory(&pem.Block{
Type: "PUBLIC KEY",
Bytes: derPkix,
}))
return
}
/**
* 生成pkcs8格式公钥私钥
*/
func (s *sRsa) CreatePkcs8Keys(keyLength int) (privateKey, publicKey string) {
rsaPrivateKey, err := rsa.GenerateKey(rand.Reader, keyLength)
if err != nil {
return
}
privateKey = string(pem.EncodeToMemory(&pem.Block{
Type: "PRIVATE KEY",
Bytes: s.MarshalPKCS8PrivateKey(rsaPrivateKey),
}))
derPkix, err := x509.MarshalPKIXPublicKey(&rsaPrivateKey.PublicKey)
if err != nil {
return
}
publicKey = string(pem.EncodeToMemory(&pem.Block{
Type: "PUBLIC KEY",
Bytes: derPkix,
}))
return
}
func (s *sRsa) MarshalPKCS8PrivateKey(key *rsa.PrivateKey) []byte {
info := struct {
Version int
PrivateKeyAlgorithm []asn1.ObjectIdentifier
PrivateKey []byte
}{}
info.Version = 0
info.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 1)
info.PrivateKeyAlgorithm[0] = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
info.PrivateKey = x509.MarshalPKCS1PrivateKey(key)
k, _ := asn1.Marshal(info)
return k
}
// 返回公钥及更新数据
func (s *sRsa) GetKey(ctx context.Context, name string, keyLength int) (publicKey string) {
privateKey, publicKey := s.CreatePkcs8Keys(keyLength)
dao.User.Ctx(ctx).Update(fmt.Sprintf("sprivatekey='%s'", privateKey), "name", name)
return
}
// push本地公钥
func (s sRsa) Pushkey(ctx context.Context, public, name string) error {
_, err := dao.User.Ctx(ctx).Update(fmt.Sprintf("cpublickey='%s'", public), "name", name)
return err
}
// 返回公私钥
func (s *sRsa) GetKeyPri(ctx context.Context, keyLength int) (privateKey, publicKey string) {
privateKey, publicKey = s.CreatePkcs8Keys(keyLength)
return
}
测试
package main
import (
"bytes"
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
)
func Rsa(publicKey, privateKey string) *sRsa {
rsaObj := &sRsa{
privateKey: privateKey,
publicKey: publicKey,
}
rsaObj.init()
return rsaObj
}
type sRsa struct {
privateKey string
publicKey string
// 私钥
rsaPrivateKey *rsa.PrivateKey
// 公钥
rsaPublicKey *rsa.PublicKey
}
// 初始化
func (s *sRsa) init() {
if s.privateKey != "" {
// 解码将找到下一个PEM格式化块(证书,私钥,etc)
block, _ := pem.Decode([]byte(s.privateKey))
// 判断私钥类型
//pkcs1
if strings.Index(s.privateKey, "BEGIN RSA") > 0 {
s.rsaPrivateKey, _ = x509.ParsePKCS1PrivateKey(block.Bytes)
} else { //pkcs8
privateKey, _ := x509.ParsePKCS8PrivateKey(block.Bytes)
s.rsaPrivateKey = privateKey.(*rsa.PrivateKey)
}
}
if s.publicKey != "" {
// 提取公钥
block, _ := pem.Decode([]byte(s.publicKey))
publicKey, _ := x509.ParsePKIXPublicKey(block.Bytes)
s.rsaPublicKey = publicKey.(*rsa.PublicKey)
}
}
/**
* 加密
*/
func (s *sRsa) Encrypt(data []byte) ([]byte, error) {
// 客户端用服务端给的公钥进行数据加密 (客户端调用sdk)
blockLength := s.rsaPublicKey.N.BitLen()/8 - 11
if len(data) <= blockLength {
return rsa.EncryptPKCS1v15(rand.Reader, s.rsaPublicKey, []byte(data))
}
buffer := bytes.NewBufferString("")
pages := len(data) / blockLength
for index := 0; index <= pages; index++ {
start := index * blockLength
end := (index + 1) * blockLength
if index == pages {
if start == len(data) {
continue
}
end = len(data)
}
chunk, err := rsa.EncryptPKCS1v15(rand.Reader, s.rsaPublicKey, data[start:end])
if err != nil {
return nil, err
}
buffer.Write(chunk)
}
return buffer.Bytes(), nil
}
/**
* 签名 客户端需要调用的接口,(客户本地的私钥和加密过的数据请求服务端)
*/
func (s *sRsa) Sign(data []byte, algorithmSign crypto.Hash) ([]byte, error) {
hash := algorithmSign.New()
hash.Write(data)
// 用户私钥做签名
sign, err := rsa.SignPKCS1v15(rand.Reader, s.rsaPrivateKey, algorithmSign, hash.Sum(nil))
if err != nil {
return nil, err
}
return sign, err
}
func (s *sRsa) MarshalPKCS8PrivateKey(key *rsa.PrivateKey) []byte {
info := struct {
Version int
PrivateKeyAlgorithm []asn1.ObjectIdentifier
PrivateKey []byte
}{}
info.Version = 0
info.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 1)
info.PrivateKeyAlgorithm[0] = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
info.PrivateKey = x509.MarshalPKCS1PrivateKey(key)
k, _ := asn1.Marshal(info)
return k
}
func POST(test_url string, data url.Values) {
resp, err := http.PostForm(test_url, data)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(string(body))
//fmt.Println(resp.Header)
}
func main() {
// 测试解密
// 需要带服务端给的 publicKey 请求get_key接口获取
publicKey := "-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArDc0i4ZWuEqpbPvrHi6e\\nxLJIDHnreYMuJfeRPJq0Az0E4tsrlwQXy0hsmk5nIGwrdEBKJ30Er75O4V3SfwcU\\nFZYqnZ4vdqCIkTzwTYWGPOXb1mmbs8KuJzmmF7YfhwLH+DAbQOvJYteZqTWQiQtq\\njcw50rm8x3ifzB4QhdetJHQfdA8OaBXdzHeAAD8gtPilOi66n1lrR1CkS6uVpquP\\nRq0eVlJnJ56IfUVKsrP9bVH0dFfWcL7qXO8zJc3oJ2V45SobvXksGJbq6h3kGc99\\nU+k/bm9uppaRg/zJJ0IM26ioRQ0yl5NmIwfmVfSXlvuku47Fi5i7RMOWjW/ZJBM5\\n1wIDAQAB\\n-----END PUBLIC KEY-----\\n"
// 私钥会在数据库查询当前用户的
pub := strings.ReplaceAll(publicKey, "\\n", "\n")
rsaObj := Rsa(pub, "")
// 加密内容
secretData, err := rsaObj.Encrypt([]byte("test"))
if err != nil {
println(err)
}
data1 := make(url.Values)
data1["name"] = []string{"asimov123"}
data1["secret"] = []string{string(secretData)}
data1["publickey"] = []string{pub}
test_url := "http://127.0.0.1:8000/decrypt"
POST(test_url, data1) //{"code":0,"message":"","data":{"result":"Decrypt success:test"}}
// 测试签名
// 先push本地公钥
public := "-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5ZPKd/oNXOp9Mhr6DnWd\\na1DEw+YjVVKKRY8edibRlvGhkAx3rKeLbNO1ZYhyYza8YPQEDjrAnZjD/prfh+HW\\nhtA39LLJjDXAjTlGb/2OsmxRAtmPALoPBbFHladV2O6ZBWI+p1sY+ODXRM1NRpKB\\n7aJut6Kg+wo/B0DwNioWPlqqH2OHxniwtTT9ZUCYQMXjCUmoa5a9LZBoFzvXmgnI\\nkeFpTeGJb0fJoZ7YUoZ+mUE5NhzXiLspcO9ZzaKkJlUSkYuJ0D5PR9s3tzIniifb\\nYrfPBWFyLIYpLEW4tvDmR3N993GRXyERJemVsZjBbnLr5mLVIYas9o0rmhEU5oMI\\nRQIDAQAB\\n-----END PUBLIC KEY-----\\n"
data2 := make(url.Values)
data2["name"] = []string{"asimov123"}
data2["public"] = []string{strings.ReplaceAll(public, "\\n", "\n")}
test_url1 := "http://127.0.0.1:8000/push_key"
POST(test_url1, data2)
// 签署信息
data := []byte(strings.Repeat("test", 200))
// 需要用户本地私钥
rsaPrivateKey := "-----BEGIN PRIVATE KEY-----\\nMIIEvAIBADALBgkqhkiG9w0BAQEEggSoMIIEpAIBAAKCAQEA5ZPKd/oNXOp9Mhr6\\nDnWda1DEw+YjVVKKRY8edibRlvGhkAx3rKeLbNO1ZYhyYza8YPQEDjrAnZjD/prf\\nh+HWhtA39LLJjDXAjTlGb/2OsmxRAtmPALoPBbFHladV2O6ZBWI+p1sY+ODXRM1N\\nRpKB7aJut6Kg+wo/B0DwNioWPlqqH2OHxniwtTT9ZUCYQMXjCUmoa5a9LZBoFzvX\\nmgnIkeFpTeGJb0fJoZ7YUoZ+mUE5NhzXiLspcO9ZzaKkJlUSkYuJ0D5PR9s3tzIn\\niifbYrfPBWFyLIYpLEW4tvDmR3N993GRXyERJemVsZjBbnLr5mLVIYas9o0rmhEU\\n5oMIRQIDAQABAoIBAGNpgwQ/EGhK1hnLWrrGLXuaBwp5bpV035FNbzhkiN+fFIIH\\nFA98ocBnUKZ91mKmAh7Nq6/puxzDWSO4NtFldvr70S8x+FqxsAa3ZYv7NT6H7vCX\\n+veqmfSyFrh0NJVyhGqzZ0QbC45B9pXBfRPxPzgC3YTBdIognrhqY1phES7AS9hQ\\ntOfDD5B5jiAaIWXuDX9aXBJWT+NV0p59l+/xRTVen9bSVU3rl3rM1T7w5/Ax2l4G\\nvv603m4MIEMqXvufhvErmwBMNrpLIEjvy6zmfTqXoOCWoTIl0GNLQNaMulGvAf6T\\nL6xJ+kJ5BMxaeZVm4GU6QBaFpJ2gMVRekfXJHcUCgYEA6tRXywQcirvKgrb5NoGz\\nYf9Q5haXzdDbJHs6HbSySfS69fGurhaOJzywPUxa907OGbJ3zFMEpA3Z/R5Lzt5j\\nKBYXMOC7J9bN8jsPiR6RAtFIKzYDSX2/Xln3jydNLmVfvGgU4GqZmsacigNcG2hi\\nZ6qUj2j0qthPoQ7nu6YUszsCgYEA+kY7mXc+k0q++KGzm7syxHcmtP44w9llQmp0\\nLXlVm55scyYN9fbsTOIMDtNYgc4nlAcDT3vcDh/YxFAOZ3ZhFSc0aCCejxOUgV+F\\nSpWIxb22FCcN0m/yZx03hzB02P6dqxWEYVxcdushESchbvicRJUNIElyMylbDrg6\\n6Lk8en8CgYBekRSp1QYJeIadDUJfCOxMUp0pi3+miq01i8pjnBkQX1XLJYDK6ppk\\ngrQWe2FGpp2pC43i4qvDxTA8Fq9Ap54Wzo6YSGgWKxLUsaQX/A85qz386Mt6FQGz\\n5VckdxdFz9016lQ966/f/IudqKy2/NpkFPWuqv2cr2+h1HbNwpwjcQKBgQD4QBg4\\nNub0FW1ulH7jF4HZDVNwrsbBxe9CPPP2c2duUGvEoFeyxfZIoORTBGLDhykNFRO8\\nkOCLhh1vRPW0vOC5qcS7ELgWtdZVqdk+TSt48aAdR0vXlEF+9KUyzObqo0zj+hjw\\ntjvlnX+UUxs/xwzCnpKBlzjW9Mukwytz0uHhowKBgQCNk8zbbWgU8MXiylLQxcdu\\n45AFt7b8UW9H3y9I7ds/l8mQF9aHvAykpp8OSdNP5dASlYaFzq+2RaFMTUcZClxa\\ntXSxuPLAnUXDok5oP2A6SCX1LA9vJ2kxpLprh4BHaKwevbmx6qtyRHTJyc+V9L5a\\nTiD4zVzrW9Ez13heA3P4RQ==\\n-----END PRIVATE KEY-----\\n"
rsaObj1 := Rsa("", strings.ReplaceAll(rsaPrivateKey, "\\n", "\n"))
sign, _ := rsaObj1.Sign(data, crypto.SHA256)
data3 := make(url.Values)
data3["name"] = []string{"asimov123"}
data3["sign"] = []string{string(sign)}
data3["data"] = []string{string(data)}
test_url2 := "http://127.0.0.1:8000/verify"
POST(test_url2, data3) //{"code":0,"message":"","data":{"result":true}}
}
版权声明
本文为[Asimov__]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_41661056/article/details/124352415
边栏推荐
- Flink SQL realizes the integration of stream and batch
- EmuElec 编译总结
- Flink reads MySQL and PgSQL at the same time, and the program will get stuck without logs
- LeetCode_DFS_中等_1254. 统计封闭岛屿的数目
- [boutique] using dynamic agent to realize unified transaction management II
- LeetCode_ DFS_ Medium_ 1254. Count the number of closed islands
- 深度学习框架中的自动微分及高阶导数
- 2021 Li Hongyi's adaptive learning rate of machine learning
- Production practice elk
- L2-023 图着色问题 (25 分)(图的遍历)
猜你喜欢
A must see wechat applet development guide 1 - basic knowledge
Arbre de dépendance de l'emballage des ressources
SAP 101K 411K 库存变化
机器学习(六)——贝叶斯分类器
Consensus Token:web3. 0 super entrance of ecological flow
Please arrange star trek in advance to break through the new playing method of chain tour, and the market heat continues to rise
Brush classic topics
GoLand debug go use - white record
Project upload part
计算神经网络推理时间的正确方法
随机推荐
Strength comparison vulnerability of PHP based on hash algorithm
How does kubernetes use harbor to pull private images
LaTeX数学公式
Complete binary search tree (30 points)
Valgrind et kcachegrind utilisent l'analyse d'exécution
2021 Li Hongyi's adaptive learning rate of machine learning
Redis Desktop Manager for Mac
Failed to download esp32 program, prompting timeout
K210 learning notes (II) serial communication between k210 and stm32
How to read excel table to database
valgrind和kcachegrind使用运行分析
Chris LATTNER, father of llvm: the golden age of compilers
Single chip microcomputer nixie tube stopwatch
Go language self-study series | golang method
Data visualization: use Excel to make radar chart
Withholding agent
企业微信应用授权/静默登录
小女孩行走
Trc20 fund collection solution based on thinkphp5 version
LGB, XGB, cat, k-fold cross validation