龙空技术网

在 Golang 中如何实现 RSA 算法的加解密操作?

路多辛 114

前言:

现在小伙伴们对“rsa加密算法优化的vc代码”大致比较关心,姐妹们都想要知道一些“rsa加密算法优化的vc代码”的相关内容。那么小编在网络上汇集了一些有关“rsa加密算法优化的vc代码””的相关知识,希望大家能喜欢,咱们一起来了解一下吧!

RSA 是一种非对称加密算法,广泛使用于数据的安全传输。crypto/rsa 是 Golang 中实现了 RSA 算法的一个标准库,提供了生成公私钥对、加解密数据、签名和验签等功能。接下来借助 crypto/rsa 的使用示例来看下对应的使用方法。

生成公私钥对

可以使用 GenerateKey 函数来生成公私钥对,GenerateKey 函数的定义如下:

func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) {	return GenerateMultiPrimeKey(random, 2, bits)}

random 参数是一个随机数生成器,通常传入 crypto/rand.Reader,bits 参数指定生成密钥的位数,例如 2048 或 4096。看一个简单的示例,生成一个 2048 位的 RSA 公私钥对,并编码为 PEM 格式的字符串:

package mainimport (	"crypto/rand"	"crypto/rsa"	"crypto/x509"	"encoding/pem"	"fmt"	"log")func main() {	// 生成 RSA 密钥对	privateKey, err := rsa.GenerateKey(rand.Reader, 2048)	if err != nil {		log.Fatalf("生成 RSA 密钥对失败: %v", err)	}	// 将私钥转换为 ASN.1 PKCS#1 DER 编码	privDER := x509.MarshalPKCS1PrivateKey(privateKey)	// 将 DER 编码的私钥转换为 PEM 格式	privPEM := pem.EncodeToMemory(&pem.Block{		Type:  "RSA PRIVATE KEY",		Bytes: privDER,	})	// 将公钥提取为 *rsa.PublicKey 类型	publicKey := &privateKey.PublicKey	// 将公钥转换为 ASN.1 PKIX DER 编码	pubDER, err := x509.MarshalPKIXPublicKey(publicKey)	if err != nil {		log.Fatalf("公钥编码失败: %v", err)	}	// 将 DER 编码的公钥转换为 PEM 格式	pubPEM := pem.EncodeToMemory(&pem.Block{		Type:  "RSA PUBLIC KEY",		Bytes: pubDER,	})	// 打印私钥和公钥	fmt.Println("私钥:")	fmt.Println(string(privPEM))	fmt.Println("公钥:")	fmt.Println(string(pubPEM))}

运行代码,输出类似如下内容:

私钥:-----BEGIN RSA PRIVATE KEY-----MIIEpAIBAAKCAQEAx5Hg78/Gwr4dtQ3ZehrQVet+RO5/k7Xm1RmNly0sCdPhcsawa8B0o7L7L11k2NP9ypVn2CDRHx8znhrtzSfBzh/HLCA9XLhG6jpABDsgam15hSvwbVgZNvTRXfDZvZXpK3fP2tH/z9ncxeQxrVJrOg/zf8GskMscTOQ1VdxiKQ2uZPuoBxHYe+UDkhWpYfZAcDSwUvO0JWUAdvteJT3o+kBcA3QywVAohfnzepej+QAZXFNf3Hs+PfoxOLejQpsdZ8KKonmtbrwUIuyDLVdWYtsEDA8g64rmIwKxPlNpFTyRXgMAOEkrEpiCRb7HnnOE6XAxJlou2z6HfB41QoO9+wIDAQABAoIBAHcLQKcsRL7j0yquET0yA3ZNHCwYLEe7KO+S54/3JR7TodbqSFBuI+WGHSmax05D3k7aonAc20F6RjsYiyNmhMfk0tUyggft8HdFuewMLQDvPp6+oBNJivjqPn2P7wKVCtqgBH/d5n9g0L3Gqg9ea5Hd8/0QVVSlo8MGGf6WkIM1lOrsPi6iBicweFEIeBRy9RBUv1KKJVThpZhZSmCM7Vy9nLVxegv+5tbbYACnQC4CozVDPKmz0UFe+P7TQ07K0g/SNAF15Hl+lnMJHdrecqZac7qGEJnrCI477o8gitlBo579OZeZkJd0JM2GrUjzcCOJWAHTKhDbs6DiPlUzU2ECgYEA7zR74nrWA5YrMklUOk9ssjuiv1gA9tN+F54JZN6AKp3nMguHlO2tViM0yArQBzTmresJ6hMwbemEU8LLFfaW5aODVZ8oxgm6gfbhxNnAYMwI+k/Itx0aooj5OK8y6rpcgHJzlAwOxPqn9VJ3Jze6ll1KPpeA/A9hhgFelAWu/OsCgYEA1ZT8DgHyrgzjZagR+sI7pRBxfUKUO4xi/LcwQhi3Z71RhoSSS+vzbaA2lyOw8vtPj6gEK8nuTAruuLfpVEdmIbu4EtoI+Bw9K0w7Cg2mXVGHvrJNlUTRY1wwnNMAVzWeIwDCOnvnDGRodv0lLRxs0XPjtLuNx7wnrnk8l9t2vzECgYEA7T3JjNM1hXMfvo0Z24dAj/kzrcDzm9ogmf3k5UUEKsBXN7xVqTCdlOvwAmMu9abTDzUorR6BDtHmq0hsMYlTGci1jmr/foLRluqr+pfZBGf4k4Ij2PElpIRjYYPp5QIWklJxLSlUUKslf9tdT+kmxtEZvMB4bgY3PDgJfJeyeScCgYEAyk5Vtfr4YQ7KMldRuIFUt9Rse2aePA2NEa1/Y4w/5V65Iz7dyFZV/Sf9rYncKTwMr5lJYiTiuFq+pm9l7zO2NQu3nvux9TniYunRHoOxasE4YFRKErLd10zSqyleMD0UbjlgwL7uKpnNLbA5D5LWLEumi2IAOQorWCN0Vq9FunECgYAaZAV4POfwGjJsJsBlAyNeddSytANVwFoioOQ9Wo6/E66MioAbZU3/fUEzmjo90ainHi8BLPiL9oEM9chn7Rq2kfUK4XDlo3/3k3O8rsQ/3DDEfD4UagAZFqwC148L2uFYVuCJ3huG+Ab0q0uQ1xlrY4rV1aRl5GLJwVDQFq3eEg==-----END RSA PRIVATE KEY-----公钥:-----BEGIN RSA PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx5Hg78/Gwr4dtQ3ZehrQVet+RO5/k7Xm1RmNly0sCdPhcsawa8B0o7L7L11k2NP9ypVn2CDRHx8znhrtzSfBzh/HLCA9XLhG6jpABDsgam15hSvwbVgZNvTRXfDZvZXpK3fP2tH/z9ncxeQxrVJrOg/zf8GskMscTOQ1VdxiKQ2uZPuoBxHYe+UDkhWpYfZAcDSwUvO0JWUAdvteJT3o+kBcA3QywVAohfnzepej+QAZXFNf3Hs+PfoxOLejQpsdZ8KKonmtbrwUIuyDLVdWYtsEDA8g64rmIwKxPlNpFTyRXgMAOEkrEpiCRb7HnnOE6XAxJlou2z6HfB41QoO9+wIDAQAB-----END RSA PUBLIC KEY-----

代码打印出了 PEM 编码的私钥和公钥字符串。对于公钥,有时可能需要以较为通用的 PEM 格式 "PUBLIC KEY" 而不是 "RSA PUBLIC KEY" 来保存。有的系统是需要以 16 进制的形式保存公钥,这就需要做一下转换了。首先去掉公钥的 开头一行“-----BEGIN RSA PUBLIC KEY-----”、结尾一行“-----END RSA PUBLIC KEY-----”和换行符,如下:

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx5Hg78/Gwr4dtQ3ZehrQVet+RO5/k7Xm1RmNly0sCdPhcsawa8B0o7L7L11k2NP9ypVn2CDRHx8znhrtzSfBzh/HLCA9XLhG6jpABDsgam15hSvwbVgZNvTRXfDZvZXpK3fP2tH/z9ncxeQxrVJrOg/zf8GskMscTOQ1VdxiKQ2uZPuoBxHYe+UDkhWpYfZAcDSwUvO0JWUAdvteJT3o+kBcA3QywVAohfnzepej+QAZXFNf3Hs+PfoxOLejQpsdZ8KKonmtbrwUIuyDLVdWYtsEDA8g64rmIwKxPlNpFTyRXgMAOEkrEpiCRb7HnnOE6XAxJlou2z6HfB41QoO9+wIDAQAB

转换代码如下:

package mainimport (	"encoding/base64"	"encoding/hex"	"fmt"	"log")func main() {	pubBase64 := "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx5Hg78/Gwr4dtQ3ZehrQVet+RO5/k7Xm1RmNly0sCdPhcsawa8B0o7L7L11k2NP9ypVn2CDRHx8znhrtzSfBzh/HLCA9XLhG6jpABDsgam15hSvwbVgZNvTRXfDZvZXpK3fP2tH/z9ncxeQxrVJrOg/zf8GskMscTOQ1VdxiKQ2uZPuoBxHYe+UDkhWpYfZAcDSwUvO0JWUAdvteJT3o+kBcA3QywVAohfnzepej+QAZXFNf3Hs+PfoxOLejQpsdZ8KKonmtbrwUIuyDLVdWYtsEDA8g64rmIwKxPlNpFTyRXgMAOEkrEpiCRb7HnnOE6XAxJlou2z6HfB41QoO9+wIDAQAB"	b, err := base64.StdEncoding.DecodeString(pubBase64)	if err != nil {		log.Fatal(err)	}	pubHex := hex.EncodeToString(b)	fmt.Println(pubHex)}
解析 pem 格式公私钥

可以使用 crypto/x509 和 encoding/pem 包来解析 PEM 编码的 RSA 私钥和公钥。看一个简单的示例:

package mainimport (	"crypto/rsa"	"crypto/x509"	"encoding/pem"	"fmt"	"os")func main() {	// 假设我们已经有了 PEM 编码的 RSA 私钥和公钥	pemPrivateKey := `-----BEGIN RSA PRIVATE KEY-----MIIEowIBAAKCAQEApiJlJTqj5JsymhpOleVkKIbtvuQ7+fSasSP5yudBqBQrF8J1ba8YkRodFrdNWcgrxGOVeYQWYl4aeEJq2MV0SpY56GU/y+WjnXFyrWXdBLbevKSF6zA6jWL8xjDt92Z7J2ew22rlubL+3atHdvXDL0G7ZIEPQlYD0eWkBQ+EGynibYecBFXi/+3BnStmw2Fm82g1nCaQWwRJwA8mbH7jvhtrhnGHmk4fhg++8MJkGn8MA6bIqOfqLFCvpp6WYDiTJ0qAFqS7mx7avZkCCg8+EHNsasyzEURIp/nGZ+nJMR0dtcpjaNpaeuU5lanmaGQJIdHODvbGovMEnh7dUo/+PQIDAQABAoIBADcCRINjO0lCqiqkc0jmv5c7thTy9Xj6KQ5mXxt0HyVMKEihtsgupe/FucP/xbjosrVAVAn8Vn0Ts6gGNeK43pyjyWDNxaX5z4cePV500A3zjyTfRQhu27RdBl2JbgHxCO4vQzwj1RT707AKOouFLK/FEAtjQG4ylOk3JGwYiyGC4DXCmVifspIinTixELNgSV+x2Qw71k407+wvGQs8w9ILpVJaG5HPUUrJUZhcHeWxAE/QLZ9g+TxycsCudHdkLH6SfTciAVlmd6C/gB4nqVOSRnS+JZujCk4yvHxDH7AaWNNibBzx0o8CruLzhTP3rKi6D4SqKIV72Hu9lxGdM4ECgYEAx6UoH9hqSg9qWO/WCtuFzOmqsqTKOpDrQ5CY/MpkUNUJ1/dIqCnzvgtezomziW5nZh0IX1V1t/3/2BOJZZ9Vuxbnjz48jksy12APY2jS4I0m6KIm1QMAgY5+kdr33wy5V/4xmLkJyVS7gA6cyYROuRrFvQRduzX8t+Nk3AutpnkCgYEA1Qeq2zghQsA5nOxl5+j6jH67GKAA5nJV01mEusJD7CijcePSxwsNMLVQ88fGcJH2c1oVmABEvu3D2dmRnTgT6/4W09opgSBzt2aDhaW4qsUt6ZT4CvVjdz3B3NaQeFTgPuzVt/XR/Q9zUSxriT4oFh85FPkePrlnY26iMElVtOUCgYEAiZ0IGVtdeItDrOY0zesfQW3XoagBVXlLEZl8OtNvbmBKlrj3NiMkxdykjw1P2e1mDHb6rGwF5ruIPPLKhGfd+kYBezVVHGgtNVQbh1Rb9ziUl0oeJjoZgTQtfnBG51Kn90VZ/oGdg0+KpuxrmmQ+t00C/BUkXsUJ2988SIksO1ECgYAZDG/Amxb+HFAp7XoGDNT5FCW3vYidkDAbS9lZhGIsMJMXXyx3jwscARXltEXXErKh2aPUXaO3t4lh4j1G+UMOarAQdQSQVFqG5Bzu6A+QtOKzJnsL/tKVQMO8zdXq8D/15i8zFEp+sQRkNQ7n8lEQWNeDac9unKpVfLrBZr4XKQKBgGM9ARebXGuTPwbwHSsF0m/fBZzJzH0c0z+IvOYxnZRbiCTmmk75VrwQpJrcwAzB4vb7Lbjpn6FicB1gDfACVMkvjQ+7ZwQn4Efu7GCGnyWgPEPXA6b4eQjf9G+iJSSj7QAdtSMSyjFXMcf+VheNO/nAYkU59fddDHH8Z2L+siqh-----END RSA PRIVATE KEY-----`	pemPublicKey := `-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApiJlJTqj5JsymhpOleVkKIbtvuQ7+fSasSP5yudBqBQrF8J1ba8YkRodFrdNWcgrxGOVeYQWYl4aeEJq2MV0SpY56GU/y+WjnXFyrWXdBLbevKSF6zA6jWL8xjDt92Z7J2ew22rlubL+3atHdvXDL0G7ZIEPQlYD0eWkBQ+EGynibYecBFXi/+3BnStmw2Fm82g1nCaQWwRJwA8mbH7jvhtrhnGHmk4fhg++8MJkGn8MA6bIqOfqLFCvpp6WYDiTJ0qAFqS7mx7avZkCCg8+EHNsasyzEURIp/nGZ+nJMR0dtcpjaNpaeuU5lanmaGQJIdHODvbGovMEnh7dUo/+PQIDAQAB-----END PUBLIC KEY-----`	// 解析 PEM 编码的私钥	block, _ := pem.Decode([]byte(pemPrivateKey))	if block == nil || block.Type != "RSA PRIVATE KEY" {		fmt.Println("failed to decode PEM block containing private key")		return	}	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)	if err != nil {		fmt.Fprintf(os.Stderr, "Error parsing private key: %s\n", err)		return	}	fmt.Println("Private Key:", privateKey)	// 解析 PEM 编码的公钥	block, _ = pem.Decode([]byte(pemPublicKey))	if block == nil || block.Type != "PUBLIC KEY" {		fmt.Println("failed to decode PEM block containing public key")		return	}	pubKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)	if err != nil {		fmt.Fprintf(os.Stderr, "Error parsing public key: %s\n", err)		return	}	publicKey, ok := pubKeyInterface.(*rsa.PublicKey)	if !ok {		fmt.Fprintf(os.Stderr, "Error casting public key to RSA Public Key\n")		return	}	fmt.Println("Public Key:", publicKey)}
使用公钥模数生成公钥

RSA 公钥由两部分组成:模数(n)和指数(e),这两个值一起定义了公钥的数学属性。根据 RSA 公钥的模数和指数,可以来构造一个 rsa.PublicKey 对象。示例代码如下:

package mainimport (	"crypto/rsa"	"fmt"	"math/big")func main() {	// 假设你有模数(n)和指数(e)作为十六进制字符串或者其他形式	// 在这个例子中,我们假设它们是十六进制的字符串	modulusHex := "c791e0efcfc6c2be1db50dd97a1ad055eb7e44ee7f93b5e6d5198d972d2c09d3e172c6b06bc074a3b2fb2f5d64d8d3fdca9567d820d11f1f339e1aedcd27c1ce1fc72c203d5cb846ea3a40043b206a6d79852bf06d581936f4d15df0d9bd95e92b77cfdad1ffcfd9dcc5e431ad526b3a0ff37fc1ac90cb1c4ce43555dc62290dae64fba80711d87be5039215a961f6407034b052f3b425650076fb5e253de8fa405c037432c1502885f9f37a97a3f900195c535fdc7b3e3dfa3138b7a3429b1d67c28aa279ad6ebc1422ec832d575662db040c0f20eb8ae62302b13e5369153c915e030038492b12988245bec79e7384e97031265a2edb3e877c1e354283bdfb" // 模数 n 的十六进制表示,这里应该是一个很长的数字	exponentHex := "010001"                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          // 公钥指数 e 的十六进制表示,通常为 65537 (即 0x10001)	// 将十六进制字符串转换为 *big.Int	n := new(big.Int)	n.SetString(modulusHex, 16)	e := new(big.Int)	e.SetString(exponentHex, 16)	// 创建 RSA 公钥	publicKey := &rsa.PublicKey{		N: n,		E: int(e.Int64()), // E 是一个 int 类型,在 RSA 中通常是一个较小的数值	}	// 输出公钥	fmt.Println("Public Key modulus (N):", publicKey.N)	fmt.Println("Public Key exponent (E):", publicKey.E)}
加解密数据

通常是使用 RSA 公钥加密数据,使用对应私钥解密数据。进行 RSA 加密和解密操作时通常涉及到填充方案。最常用的填充方案是 OAEP(Optimal Asymmetric Encryption Padding),比传统的 PKCS#1 v1.5 填充方案更安全。以下是使用 OAEP 填充方案进行加密和解密的示例代码:

package mainimport (	"crypto/rand"	"crypto/rsa"	"crypto/sha256"	"fmt"	"os")func main() {	// 生成 RSA 密钥对	privateKey, err := rsa.GenerateKey(rand.Reader, 2048)	if err != nil {		fmt.Fprintf(os.Stderr, "Error generating key pair: %s\n", err)		return	}	publicKey := &privateKey.PublicKey	// 待加密的数据	message := []byte("路多辛的博客")	// 使用公钥和 OAEP 填充方案加密数据	label := []byte("OAEP Encrypted")	ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey, message, label)	if err != nil {		fmt.Fprintf(os.Stderr, "Error encrypting message: %s\n", err)		return	}	fmt.Printf("Ciphertext: %x\n", ciphertext)	// 使用私钥和 OAEP 填充方案解密数据	plaintext, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey, ciphertext, label)	if err != nil {		fmt.Fprintf(os.Stderr, "Error decrypting message: %s\n", err)		return	}	fmt.Printf("Plaintext: %s\n", plaintext)}

请注意,RSA 加密通常用于加密小块数据,如密钥或密钥交换信息,而不是用于加密大量数据。对于大量数据,常见的做法是使用 RSA 加密一个对称加密算法的密钥,然后使用该对称密钥来加密实际的数据。

如果使用的是 PKCS#1 v1.5 填充方案,crypto/rsa 也提供了对应的函数,使用方法和上面的示例类似,就不举例说明了。

签名和验签

通常是使用 RSA 私钥对数据进行签名,使用对应公钥对数据进行验签。看一个简单的示例:

package mainimport (	"crypto"	"crypto/rand"	"crypto/rsa"	"crypto/sha256"	"fmt"	"os")func main() {	// 生成 RSA 密钥对	privateKey, err := rsa.GenerateKey(rand.Reader, 2048)	if err != nil {		fmt.Fprintf(os.Stderr, "Error generating RSA key pair: %s\n", err)		return	}	publicKey := &privateKey.PublicKey	// 待签名的数据	message := []byte("路多辛的博客")	// 对数据进行 SHA-256 哈希处理	hashed := sha256.Sum256(message)	// 使用私钥对哈希值进行签名	signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed[:])	if err != nil {		fmt.Fprintf(os.Stderr, "Error signing message: %s\n", err)		return	}	fmt.Printf("Signature: %x\n", signature)	// 使用公钥验证签名	err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hashed[:], signature)	if err != nil {		fmt.Fprintf(os.Stderr, "Error verifying signature: %s\n", err)		return	}	fmt.Println("Signature verified")}

可以看出,定义了一条消息后,计算了其 SHA-256 的哈希值。在实际应用中,签名通常是对数据的哈希值进行,而不是对原始数据本身进行,这样做是为了提高效率和性能,特别是数据非常大的场景。

请注意,SignPKCS1v15 和 VerifyPKCS1v15 函数都是使用的 PKCS#1 v1.5 签名方案。crypto/rsa 包还提供了对 PSS 签名方案的支持(SignPSS 和 VerifyPSS 函数),这是一种更现代的方案,具有更高的安全性。

标签: #rsa加密算法优化的vc代码