当前位置:网站首页>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
边栏推荐
- Failed to prepare device for development
- ONEFLOW learning notes: from functor to opexprinter
- Notes d'apprentissage oneflow: de functor à opexprinterpreter
- 小程序报错 :should have url attribute when using navigateTo, redirectTo or switchTab
- 爬虫使用xpath解析时返回为空,获取不到相应的元素的原因和解决办法
- [Luke V0] verification environment 2 - Verification Environment components
- 基于ThinkPHP5版本TRC20-资金归集解决方案
- 資源打包關系依賴樹
- Basic usage of synchronized locks
- LaTeX数学公式
猜你喜欢
计算神经网络推理时间的正确方法
DJ music management software pioneer DJ rekordbox
L2-022 重排链表 (25 分)(map+结构体模拟)
Cadence process angle simulation, Monte Carlo simulation, PSRR
K210 learning notes (II) serial communication between k210 and stm32
Matlab draw five-star red flag
Mini - exercice MySQL (seulement pour les débutants, pas pour les non - débutants)
A must see wechat applet development guide 1 - basic knowledge
Introduction to matlab
Consensus Token:web3. 0 super entrance of ecological flow
随机推荐
企业微信应用授权/静默登录
Technological innovation in government affairs in the construction of Digital Government
MySQL small exercise (only suitable for beginners, non beginners are not allowed to enter)
爬虫使用xpath解析时返回为空,获取不到相应的元素的原因和解决办法
Open services in the bottom bar of idea
Summary of solid problems
LLVM之父Chris Lattner:编译器的黄金时代
The most concerned occupations after 00: civil servants ranked second. What was the first?
Brush classic topics
First principle mind map
1099 建立二叉搜索树 (30 分)
L2-024 tribe (25 points) (and check the collection)
[original] use system Text. JSON formats the JSON string
To remember the composition ~ the pre order traversal of binary tree
How does kubernetes use harbor to pull private images
Error: cannot find or load main class
基于点云凸包的凹包获取方法
Illegal character in scheme name at index 0:
还原二叉树 (25 分)
在sqli-liabs学习SQL注入之旅(第十一关~第二十关)