golang语言rsa加解密及签名验签

golang语言rsa加解密及签名验签

rsa算法

概述

rsa是一种非对称可逆的加密算法,对加密数据长度有限制,同时rsa也提供了数据的签名与验签的支持,在实际项目中被广泛应用,如:支付宝等。

golang语言对于rsa算法的实现在crypto/rsa包中,rsa包实现了PKCS#1标准的rsa加密算法。

rsa算法依赖一对公钥私钥,私钥有PKCS1PKCS8两种格式标准,一般采用公钥加密私钥解密私钥签名公钥验签

Rsa结构体封装

import (
	"bytes"
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/asn1"
	"encoding/hex"
	"encoding/pem"
	"fmt"
	"strings"
)

type Rsa struct {
	privateKey    string
	publicKey     string
	rsaPrivateKey *rsa.PrivateKey
	rsaPublicKey  *rsa.PublicKey
}

func NewRsa(publicKey, privateKey string) *Rsa {
	rsaObj := &Rsa{
		privateKey:privateKey,
		publicKey:publicKey,
	}

	rsaObj.init()

	return rsaObj
}

func (this *Rsa) init() {
	if this.privateKey != "" {
		block,_           := pem.Decode([]byte(this.privateKey))

		//pkcs1
		if strings.Index(this.privateKey,"BEGIN RSA") > 0 {
			this.rsaPrivateKey,_ = x509.ParsePKCS1PrivateKey(block.Bytes)
		}else { //pkcs8
			privateKey,_ := x509.ParsePKCS8PrivateKey(block.Bytes)
			this.rsaPrivateKey = privateKey.(*rsa.PrivateKey)
		}
	}

	if this.publicKey != "" {
		block, _ := pem.Decode([]byte(this.publicKey))
		publickKey,_ := x509.ParsePKIXPublicKey(block.Bytes)
		this.rsaPublicKey = publickKey.(*rsa.PublicKey)
	}
}

/**
 * 加密
 */
func (this *Rsa) Encrypt(data []byte) ([]byte, error) {
	blockLength := this.rsaPublicKey.N.BitLen() / 8 - 11
	if len(data) <= blockLength {
		return rsa.EncryptPKCS1v15(rand.Reader, this.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, this.rsaPublicKey, data[start: end])
		if err != nil {
			return nil, err
		}
		buffer.Write(chunk)
	}
	return buffer.Bytes(), nil
}

/**
 * 解密
 */
func (this *Rsa) Decrypt(secretData []byte) ([]byte, error) {
	blockLength := this.rsaPublicKey.N.BitLen() / 8
	if len(secretData) <= blockLength {
		return rsa.DecryptPKCS1v15(rand.Reader, this.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, this.rsaPrivateKey, secretData[start: end])
		if err != nil {
			return nil, err
		}
		buffer.Write(chunk)
	}
	return buffer.Bytes(), nil
}

/**
 * 签名
 */
func (this *Rsa) Sign(data []byte, algorithmSign crypto.Hash) ([]byte, error) {
	hash := algorithmSign.New()
	hash.Write(data)
	sign, err := rsa.SignPKCS1v15(rand.Reader, this.rsaPrivateKey, algorithmSign, hash.Sum(nil))
	if err != nil {
		return nil, err
	}
	return sign, err
}

/**
 * 验签
 */
func (this *Rsa) Verify(data []byte, sign []byte, algorithmSign crypto.Hash) bool {
	h := algorithmSign.New()
	h.Write(data)
	return rsa.VerifyPKCS1v15(this.rsaPublicKey, algorithmSign, h.Sum(nil), sign) == nil
}

/**
 * 生成pkcs1格式公钥私钥
 */
func (this *Rsa) 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",
		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 (this *Rsa) 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:  this.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 (this *Rsa) 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
}

封装的优点

  • 1.支持PKCS1PKCS8两种格式的私钥
  • 2.突破了加解密对数据长度的限制
  • 3.签名与验签支持多种数据签名算法
  • 4.支持生成PKCS1PKCS8两种格式的私钥

使用案例

func main() {
	//content   := strings.Repeat("H", 244)+"e"
	//content   := strings.Repeat("H", 245)+"e"
	content   := strings.Repeat("H", 24270)+"e"
	//privateKey, publicKey := NewRsa("", "").CreateKeys(1024)
	privateKey, publicKey := NewRsa("", "").CreatePkcs8Keys(2048)
	fmt.Printf("公钥:%v\n私钥:%v\n", publicKey, privateKey)

	rsaObj := NewRsa(publicKey, privateKey)
	secretData,err := rsaObj.Encrypt([]byte(content))
	if err != nil {
		fmt.Println(err)
	}
	plainData, err := rsaObj.Decrypt(secretData)
	if err != nil {
		fmt.Print(err)
	}

	data := []byte(strings.Repeat(content,200))
	//sign,_ := rsaObj.Sign(data, crypto.SHA1)
	//verify := rsaObj.Verify(data, sign, crypto.SHA1)

	sign,_ := rsaObj.Sign(data, crypto.SHA256)
	verify := rsaObj.Verify(data, sign, crypto.SHA256)

	fmt.Printf(" 加密:%v\n 解密:%v\n 签名:%v\n 验签结果:%v\n",
		hex.EncodeToString(secretData),
		string(plainData),
		hex.EncodeToString(sign),
		verify,
	)
}

输出样例:

公钥:-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq2FqPV4IzgxdnhoF3QdY
Sxxy8oLNMd02rg04Ye9uLdfJu//898u6nruD9u7zXy6lbdRoP7XdXq1HIGlQGX+T
WGYzj/39ul4ZPdROxRKhsp/OaLiMhyWDaZ00W6UyRddWKHEI+XL3GfzFOoWFkT99
tgC0mHoxGX8XiRJ3X86IZdDvyTgbmder+GB7D2k4ErFPzMIvDi22OGBWcW+r1Lmr
MWuHF1MIc4g6oEoXMSDZUVbzsNeyUVSgl0B5icGwUTtKpOmGCnh2AjyCIF5euzG5
jZE26vGP7Taey7vAAPgtNJq1SQbeQJTdh63LlGWlNPfZ5VNkI9+MwLIlg9fQvK/B
OQIDAQAB
-----END PUBLIC KEY-----

私钥:-----BEGIN PRIVATE KEY-----
MIIEuwIBADALBgkqhkiG9w0BAQEEggSnMIIEowIBAAKCAQEAq2FqPV4IzgxdnhoF
3QdYSxxy8oLNMd02rg04Ye9uLdfJu//898u6nruD9u7zXy6lbdRoP7XdXq1HIGlQ
GX+TWGYzj/39ul4ZPdROxRKhsp/OaLiMhyWDaZ00W6UyRddWKHEI+XL3GfzFOoWF
kT99tgC0mHoxGX8XiRJ3X86IZdDvyTgbmder+GB7D2k4ErFPzMIvDi22OGBWcW+r
1LmrMWuHF1MIc4g6oEoXMSDZUVbzsNeyUVSgl0B5icGwUTtKpOmGCnh2AjyCIF5e
uzG5jZE26vGP7Taey7vAAPgtNJq1SQbeQJTdh63LlGWlNPfZ5VNkI9+MwLIlg9fQ
vK/BOQIDAQABAoIBAQCHpsnS3TWW8o6/b9WoSAIJIfGSJxqIF5MKXYh9bGkHfEA/
wLXY5bdHoSEpOaYFdwSWVIRXuXoJUJp1+yXdqO9WDz9NADvvYkAUgpH+x2qZ2ogk
t77z0iucU0R4LeAHDBU0WZRC7k7MkRkD41//wgOdJh3MexuWFNTqOGWove+UtmqE
CxsqQ4VcGjiQzJu6mqYMvVQuHIpknj0gl+c6zNU49rHWObyxXzOF4vGBw2BhJPEq
UyON4eJuRb49WiU9THug73sjCYe1t5vvrvXl+rkW6+ribFMTkSWPigumN7JEV3uK
2IKXEOHdB6Vcy6ihXggdEoO67f5UNrbHy4f4TSLJAoGBAMUr2SvJDg9EwaPLdpwO
VIStPp//Pjy2fnMdYlz1pMk2t6IW6lOFeqNxHjOOxYfnYO2L3dZ1gHjPIz9QX5Zm
2PLxsTv1PsGKkwzniIIOetJdBwd+wFd7HtDLjoQEamkz5dcgDR26ySbrmV7H/wZg
GMmr8+LkD5VhM7FSn5/ExbZDAoGBAN6DpDV2PvqeAdCMeh917PZbZhAA8i0yNUMB
MpGHx86nm2SgfmgQ8b4gTghjCS24nnSI8EaMkyjROS/TWDLZoErcqy+/O+wKJaKM
gmmiZa1QMrAi80xTFIMsHD34GIG+qsf6+xZYUSv8KE+t92W/czSwRlKG7/0MG0E4
gIe6JtjTAoGAGDgEmv49Pd7iMi5hyVVxSELHeHuvt2FrMtSfKm/558VS1RQfgFba
84yHeynEVac0HrmZbChOuYgn+jTzKNRFPcI2VPkQ1lEhMuqVt/PzXjeTD3agRZ6X
8GmwfcLVF0sKplwHgGlbH+68jgne53eSU+NNN8dvqpef894EQWm4J2UCgYBcoerz
grV3Od5Bhqm0fTBX4vbbRLmNDTDVIyN9KEyLAIWVX6cgBaXN4774iNoiWZBFrVhx
1kXRIUCwY0h9atHrOHBfoTn96r9+KwaDmWLAwvlHEFW++Xs5nFxpg+YX5VtNg3OR
+tRX/lJ90UuD5S69yYCNDLXN34NdJHuFhX50lwKBgGqdUCKfM1oiD1Cnnr7YtIIp
6c3PmPn0cdK+Wb7rTp/u8gU90LSDRgA8GhTcrV6dj/0mmcvDiiAI+FPnWrDNQr97
2IkhMbQi651P+TyDIb8uehCjKI58SqvT0u8wqyHqKn6lEW6TZ8qnyO9QFBlJHA3p
cMR9qOxIQay/heVbOVTz
-----END PRIVATE KEY-----

 加密:3e44f56871841096e218dadd7d519b058a267ead9511bdddcd8e69a87a9a730438a0d017819c4f68e688fbf2638446f9924ccc9505c7b9c5d04bf45f9f36c4290ea9bf63a53d2b59fa8179f536c03a266a585bfe6336b17268a9c628e7e1f125e8e63a7bd91ff733ed2b08cb47d8f1ebd2b6be38074367f6d7dba5653d52635986e3c1716be406b1ffcf9eb67b84a87f368052ce1f28bd6f6776bc159bb56c62eb9f6d0b24b09cef89b5db3b1550c25ac64a2ab4b8901283d67846e8f408c59b65d00ea570abb0f7025b3ddf43511f04dde2a316fd8b46158691a330f54e82a75d897c85a5bc7175e20cc6e692fcf7125d0b5cf2af170a843798874a3cb83228fa3c9f83ac1f7b26d9e269d93313a8c7e1013613f624c82352760a3539b10468e6b75bf58b6d0d4e3179cd73eacd1f790fc0baa5593289177e1cc2b27fb4b8c14da48ae6cd26b939cd5888ce67401e5b5ac02ba3a8c76b64f16c7fe0ff2e2430d06924a36e331e292110f2758977239984260c8f8908850f93ebeddf112a4ad9694ac1271bd44dc628f82aad36c548ccf3a398f41a415c56816e9d0c46a35d1eeac4c6eb69ab064235bba249f20dc6a8e1b8625bf77fbb266dd0e95188251d5c87001a12d6d58a1ef479aa5fa50aac8606ee09e73e7d5ed965c0d73048df9c916232ec950056a47a8873e8debc76c2d15f183fce08db001fed87f923f09928c7c4ff18626e2d231c5caafc6a414e4b6f6da0d5d66bf0d042eb75c51c8b5b61035cfa75fae4ef51afa36386a105178fa4d65e5c565888d813837e61c38309abe2cc967b9a510c1fe01ef2ceacdbccc8b5fd90c9600b5a5028fc8451f24e38cbb4b64fddcb6cefc7f1d7289da033293cd72ff2bc5d1997adfe04ef48b1283c680b330bb62d35fd88cecb46b3c5e4d01c1383ad0c7ccaa0266b5641cdae22fb922b75db7c481b8ddb991a5c767d2fb25dbd4410c94f2f5afd68ecede907452ed491931063e4ca9271cbea802db99f69f3b573ba699c3455fe9f307185f20c21829881ba2c9165e6d191ed527293f3b324641ac91077a26a411f9fe7769bce4e168ea1beb6c6de2a3c0747ba3750fbd4e5b0c7169698158a94aa5ea4c2fa7979029b9ed1075d8ebe8d4fc8d9fd8bb424f6313c6cd43bff584ed73723614658f43c1a1b7de19f1f467f0fddbe5be6d93d82c467dcaefbb83881c29f3bd0bbd57b9e64522b8e603e5aab589257d889d80d7db15e4fbb3716daee48627feb9c105c1555d488028421f833f8676273bc663f06c8fe3590ade6357ff2fe0f0f6a99c8459a158a353e524c0a738a6f6b127c797d6594e2a987063c9b111d190be5289b9ccae19d9348ec5f8b257885c1974f734dca8e0992bd4c06dfa5f7bf56aab48103761755eb21d3ac95bee66e2ff6985d6ff20e677776d652e5f83727fa254c7d28c070eca7b5597830e0d3c844666ccace00242f85d92dae9ed47cc403d2ad39d827e3a8e6a4ba1feb7c097b1c9dbf00214a7f4cff6eb291439d7bc9143bcb39616c5d2b9d27d7f18810823b1eccc6a95fb98d2c6060963393c77951986af6330d801221fc037152f31fc07936fbe6b49c99fd69f0b0f30a5268ad601505048be8f9976bbe1513e93a0ddaa57831c8f53cdb4e99dc9ec81f9b99d1a2aa02bffa1a08bbeb823919a42af4b0a465d0b5d59db1bb377599926016b0b9c3fb38741e8130589fd1e48d0ff96557680e19909c16e0cfc954206427683ff81632ea5cc288409730ad43aa2c36305c7fd853f912ea88a7f4038ca95b567fb540ae842c9853f1b250cd822c7da2eb042082657bbaf79effd0b2922fd073edeb8334b1b009afd5476077cd770552912f78a63bcf4cb66acf29a6f6004b3e5b6cd46489a0401de0efd549037fc706be79707f991da214ae91e3d4514fedb14ea1bda5fadd7c2a59038ae0749250215dd44ef995918f097889cd5e653c97dc13b7f232d6cda9e823037a72a6b6542be9ace101e51dc76815e6ab729ecbed3843a6831147050c7bb333f85db091317ca64a12af5df1e936709ddf776f05f731fd2ab287785c83d72588c2fabc284c88c855dc2b1e57afe4edc10bc148eef4da7732e3cacb4b7091b6abe6e8d7e28bd28b4df8ad4ed076787550900169edab5cf8c7ea54da8ece91261ba602a958b57827077b9895924febb00d95151cc34a465a541b07239db4a9f899db8e2fb9d607b165fddb93232e30deab4c773f790496a8b2ee2087449ae71cce3659648c3430f770aad447865f58f357f72575cc79d960d65593a3f78a0623e333373228cf4442c16acb76d5258a92361035a7591bebd5258f7c06fc21936dddc2ad89caf85c9d89a551aa06fc5b1949dfa4961bf209ec680efc568b0ad6bb2ad3b04178a293efa26815d7b634cdd0920b3fc95e7dcad7a27fe57541d92f73b1f52b15c7e54e16277f919067d8e7f14a9e62256af4ba53e0100472965dbabfe1270f4a089960ce870ea9f76fc1ff029c8c8b1efe2e462b1828a65f65ba922c31443593115a3fd0569112597a8ed0fc2200a933a7afdbeae357c885da6e95bbe8f421186b7fd13d3e488492339d74be35c32cc36e1d70d86fd786e6ac3373224d79221d453d8f64d12a9c979bda0712173da3196a19bd600eea4811329e71fba39466058676920cfcdcc58637a39efb88aef726dd1b9b3bc56dfcacf4afe99515ea160c54f5b93fedc66fdcb2d2e206bf61eb73dda5380a41c6135dcd4f983f92fedc2ca9db3fd928b0072bc8d8ab88b8ba4f853b3ce335dbddd1ee94700c2a234fae16949b6fc6bb48c935e114b3f83297e9321241c7ed5c3ccf81a1a7f5f400126e78c06f9c76c890ec725365732c6bd53f7bfb114160cdfee29f3d89c8f9cc7a36fe8a3752abe7a11da82f23416ae308cbb7a451fc948791daea6b3b1ca92e17780fe3e5429d124f718b16dde05385de51af7b822f4dcc0212f7fa93053a890139803047ff7b55cd34bacef917f4e79b6bd062f5cf772db75befa6d9ab795d0434aefb2abb85877f14faecafbc26bb8216bd4a7a6badaaa0d3335c5e5f00725331d77c956458890f799407561a6c3704f4446102d6e903104c4dc8a839de492651b4621aba5bad58adfab642a1f8cf58e04596cc814bf19daf5c8c00ab18805fb7b4630fd8b827609ecf5b7a5d60b650134433aa9f0e9edab3d98baca850906ca81b9cda8e6b4fab413a01e7402d49f5d52fa029d8018252c59922f467fa13d827de7d4155571fb601d73bf19bb7bb4b1f7a2d860b99c3f5d37d2163b4295f878620ae01713a1c64a1d505ea9bd93fc5da8cf52ec66abb91f53b6410e9c783f8ae4f921c1e2ad4399071b955d4f0d45eda2be0f25cc11da293e51fbb8a8f03d4c7247a5891e7b91e1d2e2119b9757370f741fc864653d904e616d75b3596a2da354c031320ef8bd491e7652ca1fe8e3c25bb1f404497210b921d678d888b19f23c14ff9ff54b1c83df577ce7e473e5fcd9c71e8be9faea4ae4707a152b3b0383fb94a1d6bc5248ccd5ecd8e1ef687e088c09f32995cf478e902242f43bc6aedebc91943f851fc693db04e1435d1bbccba3f2f47c4e50337f30b4fce1f
 解密:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHe
 签名:7125c98bb2443b975d41af34f480c6d0f08522dd88de61216759082bfe643a09b4a4c1aadf03c4607abe54ed6e69ac12347d08f70816539929ffbec5fc972a4cda8cf4d09bcf4fff6e51140fb7766712ec0cd30a02bd1690d7f136c507afee84b5456bfedbb109088dc0db4a0a31e4d791f06e8e6340797822d5ca96ac7fa58ed5ad9f36d2edcde53d1de07d1691b66e11d14fd3cba36e8947d48e811fbf414b901d9d8d968a2663a1dcc3f0531da64f0bbad2fae666173492fc1d88d14e92997639de21d32b8c7137ee3ed013c9fd258f383c271e7243ee24f64a94f58e77adf2ab2d22fad63022471e2e7bbf8a8dbca7400a17026f51c25b9374e2ec3c7
 验签结果:true
发布了101 篇原创文章 · 获赞 113 · 访问量 33万+

猜你喜欢

转载自blog.csdn.net/jhq0113/article/details/104690765
今日推荐