Golang RSA生成密钥、加密、解密、签名与验签的实现
脚本之家 / 编程助手:解决程序员“几乎”所有问题!
脚本之家官方知识库 → 点击立即使用
1.RSA
RSA 是最常用的非对称加密算法,由 Ron Rivest、Adi Shamir、Leonard Adleman 于1977 年在麻省理工学院工作时提出,RSA 是三者姓氏首字母的拼接。
它的基本原理涉及到数学中的大整数因数分解问题,即将一个大的合数(通常是一个极大数字)分解为其素数因子。RSA 算法的安全性基于这个问题的难解性,目前还没有高效的方法可以在合理的时间内分解大整数。
RSA 支持变长密钥非对称加密,需要加密的文件块的长度也是可变的。
2.Golang 实现 RSA
Golang 标准库在 crypto/rsa 包实现了 RSA。
下面将利用 Golang 标准库相演示 RSA 生成密钥、加密、解密、签名与验签等操作。
生成密钥
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // GenRsaKey generates an PKCS#1 RSA keypair of the given bit size in PEM format. func GenRsaKey(bits int ) (prvkey, pubkey [] byte , err error ) { // Generates private key. privateKey, err := rsa.GenerateKey(rand.Reader, bits) if err != nil { return } derStream := x509.MarshalPKCS1PrivateKey(privateKey) block := &pem.Block{ Type : "RSA PRIVATE KEY" , Bytes: derStream, } prvkey = pem.EncodeToMemory(block) // Generates public key from private key. publicKey := &privateKey.PublicKey derPkix, err := x509.MarshalPKIXPublicKey(publicKey) if err != nil { return } block = &pem.Block{ Type : "RSA PUBLIC KEY" , Bytes: derPkix, } pubkey = pem.EncodeToMemory(block) return } |
加密
RSA 是一个非对称加密算法,虽然私钥也可以用于加密数据,但因为公钥是对外的,所以加密数据的意义不大,因为知道公钥的所有人都能解密。
所以常见的做法是是用公钥加密数据,私钥解密数据。而私钥则用户签名,公钥用于验签。
1 2 3 4 5 6 7 8 9 10 11 12 | // RsaEncrypt encrypts data using rsa public key. func RsaEncrypt(pubkey, data [] byte ) ([] byte , error ) { block, _ := pem.Decode(pubkey) if block == nil { return nil , errors. New ( "decode public key error" ) } pub, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return nil , err } return rsa.EncryptPKCS1v15(rand.Reader, pub.(*rsa.PublicKey), data) } |
解密
1 2 3 4 5 6 7 8 9 10 11 12 | // RsaDecrypt decrypts data using rsa private key. func RsaDecrypt(prvkey, cipher [] byte ) ([] byte , error ) { block, _ := pem.Decode(prvkey) if block == nil { return nil , errors. New ( "decode private key error" ) } prv, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil , err } return rsa.DecryptPKCS1v15(rand.Reader, prv, cipher) } |
签名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | // RsaSign signs using private key in PEM format. func RsaSign(prvkey [] byte , hash crypto.Hash, data [] byte ) ([] byte , error ) { block, _ := pem.Decode(prvkey) if block == nil { return nil , errors. New ( "decode private key error" ) } privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil , err } // MD5 and SHA1 are not supported as they are not secure. var hashed [] byte switch hash { case crypto.SHA224: h := sha256.Sum224(data) hashed = h[:] case crypto.SHA256: h := sha256.Sum256(data) hashed = h[:] case crypto.SHA384: h := sha512.Sum384(data) hashed = h[:] case crypto.SHA512: h := sha512.Sum512(data) hashed = h[:] } return rsa.SignPKCS1v15(rand.Reader, privateKey, hash, hashed) } |
验签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | // RsaVerifySign verifies signature using public key in PEM format. // A valid signature is indicated by returning a nil error. func RsaVerifySign(pubkey [] byte , hash crypto.Hash, data, sig [] byte ) error { block, _ := pem.Decode(pubkey) if block == nil { return errors. New ( "decode public key error" ) } pub, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return err } // SHA1 and MD5 are not supported as they are not secure. var hashed [] byte switch hash { case crypto.SHA224: h := sha256.Sum224(data) hashed = h[:] case crypto.SHA256: h := sha256.Sum256(data) hashed = h[:] case crypto.SHA384: h := sha512.Sum384(data) hashed = h[:] case crypto.SHA512: h := sha512.Sum512(data) hashed = h[:] } return rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), hash, hashed, sig) } |
3.dablelv/cyan
以上函数已放置 Golang 实用函数库 dablelv/cyan,欢迎大家 import 使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | package main import ( stdcrypto "crypto" "fmt" "github.com/dablelv/cyan/crypto" ) func main() { prvkey, pubkey, err := crypto.GenRsaKey( 2048 ) if err != nil { panic (err) } data := [] byte ( "foo" ) // Encrypt data. cipher, err := crypto.RsaEncrypt(pubkey, data) if err != nil { panic (err) } if len (cipher) != 2048 / 8 { panic ( "cipher len not equal to key length" ) } // Decrypt data. plain, err := crypto.RsaDecrypt(prvkey, cipher) if err != nil { panic (err) } if string (data) == string (plain) { fmt.Printf( "rsa encrypt and decrypt succeeded, data:%v plain:%v\n" , string (data), string (plain)) } // Using SHA256 to hash msg and then use rsa private key to sign. sig, err := crypto.RsaSign(prvkey, stdcrypto.SHA256, data) if err != nil { panic (err) } if len (sig) != 2048 / 8 { panic ( "signature len not equal to key length" ) } // Using public key to verify signature. err = crypto.RsaVerifySign(pubkey, stdcrypto.SHA256, data, sig) if err != nil { panic (err) } fmt. Println ( "verify signature succeeded" ) } |
运行输出:
参考文献
到此这篇关于Golang RSA生成密钥、加密、解密、签名与验签的实现的文章就介绍到这了,更多相关Golang RSA加密解密内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
微信公众号搜索 “ 脚本之家 ” ,选择关注
程序猿的那些事、送书等活动等着你
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 reterry123@163.com 进行投诉反馈,一经查实,立即处理!
相关文章
GO 使用Webhook 实现github 自动化部署的方法
这篇文章主要介绍了GO 使用Webhook 实现github 自动化部署的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2020-05-05
最新评论