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}}
}
|