如何从文件中读取RSA密钥

huangapple go评论115阅读模式
英文:

How to read an RSA key from file

问题

我需要从文件中读取一个RSA私钥来签署JWT。我找到了一些关于如何将生成的RSA密钥保存到磁盘的示例,但没有找到关于如何基于预先生成的密钥从文件构建密钥结构的示例。

生成密钥的方法如下:

<pre>
openssl genrsa 2048 | openssl pkcs8 -topk8 -nocrypt
</pre>

示例密钥:

<pre>
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQClHYNDPVSF‌​FmWF
oKGTqd/n7Dt2+tGXh97KJjVLAqCBZZHlQJ534v2OzFjTgzuMNehD9Y6HnkYF‌​dkRb
QzYi2YDROOzRl1bhyyWPA35OGf50r7LiNvSvNPNtswsCuK7ywOcH0yEMKSiW‌​4q5R
GKYi42w961EcTQQPrfihavY+c2FYPv4+pXymzaIz9hGBPLHwaHq/QTAyHxPC‌​fkOo
s/x3mxUVd7Ni2bz1VJGlyqcNEeU88wTAYMmv8oQ3y2NfKExtYn+W6TCDiq/+‌​ZkOp
wacuAU0J7tCNgcXvkq39KH5uza2uSiTniye6uhlkvYWD3s9riIIiekTEiHk/‌​kkc6
jMg8HN/7AgMBAAECggEBAJ12u8vQHV6esUrymaTdCG+BVmRtZpyA ...
-----END RSA PRIVATE KEY-----
</pre>

英文:

I need to read in an RSA private key from a file to sign a JWT. I have found some examples on how to save a generated RSA key to disk but nothing showing how to build a key struct based on a pre-generated key from a file.

The key is generated like this:

<pre>
openssl genrsa 2048 | openssl pkcs8 -topk8 -nocrypt
</pre>

Example key:

<pre>
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQClHYNDPVSF‌​FmWF
oKGTqd/n7Dt2+tGXh97KJjVLAqCBZZHlQJ534v2OzFjTgzuMNehD9Y6HnkYF‌​dkRb
QzYi2YDROOzRl1bhyyWPA35OGf50r7LiNvSvNPNtswsCuK7ywOcH0yEMKSiW‌​4q5R
GKYi42w961EcTQQPrfihavY+c2FYPv4+pXymzaIz9hGBPLHwaHq/QTAyHxPC‌​fkOo
s/x3mxUVd7Ni2bz1VJGlyqcNEeU88wTAYMmv8oQ3y2NfKExtYn+W6TCDiq/+‌​ZkOp
wacuAU0J7tCNgcXvkq39KH5uza2uSiTniye6uhlkvYWD3s9riIIiekTEiHk/‌​kkc6
jMg8HN/7AgMBAAECggEBAJ12u8vQHV6esUrymaTdCG+BVmRtZpyA ...
-----END RSA PRIVATE KEY-----
</pre>

答案1

得分: 65

pem.Decodex509.ParsePKCS1PrivateKey 的组合可以解决问题:

  1. package main
  2. import (
  3. "crypto/x509"
  4. "encoding/pem"
  5. "fmt"
  6. )
  7. func main() {
  8. pemString := `-----BEGIN RSA PRIVATE KEY-----
  9. MIICXQIBAAKBgQDLets8+7M+iAQAqN/5BVyCIjhTQ4cmXulL+gm3v0oGMWzLupUS
  10. v8KPA+Tp7dgC/DZPfMLaNH1obBBhJ9DhS6RdS3AS3kzeFrdu8zFHLWF53DUBhS92
  11. 5dCAEuJpDnNizdEhxTfoHrhuCmz8l2nt1pe5eUK2XWgd08Uc93h5ij098wIDAQAB
  12. AoGAHLaZeWGLSaen6O/rqxg2laZ+jEFbMO7zvOTruiIkL/uJfrY1kw+8RLIn+1q0
  13. wLcWcuEIHgKKL9IP/aXAtAoYh1FBvRPLkovF1NZB0Je/+CSGka6wvc3TGdvppZJe
  14. rKNcUvuOYLxkmLy4g9zuY5qrxFyhtIn2qZzXEtLaVOHzPQECQQDvN0mSajpU7dTB
  15. w4jwx7IRXGSSx65c+AsHSc1Rj++9qtPC6WsFgAfFN2CEmqhMbEUVGPv/aPjdyWk9
  16. pyLE9xR/AkEA2cGwyIunijE5v2rlZAD7C4vRgdcMyCf3uuPcgzFtsR6ZhyQSgLZ8
  17. YRPuvwm4cdPJMmO3YwBfxT6XGuSc2k8MjQJBAI0+b8prvpV2+DCQa8L/pjxp+VhR
  18. Xrq2GozrHrgR7NRokTB88hwFRJFF6U9iogy9wOx8HA7qxEbwLZuhm/4AhbECQC2a
  19. d8h4Ht09E+f3nhTEc87mODkl7WJZpHL6V2sORfeq/eIkds+H6CJ4hy5w/bSw8tjf
  20. sz9Di8sGIaUbLZI2rd0CQQCzlVwEtRtoNCyMJTTrkgUuNufLP19RZ5FpyXxBO5/u
  21. QastnN77KfUwdj3SJt44U/uh1jAIv4oSLBr8HYUkbnI8
  22. -----END RSA PRIVATE KEY-----`
  23. block, _ := pem.Decode([]byte(pemString))
  24. key, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
  25. fmt.Println(key.N)
  26. }

如果你手头的是一个 PKCS#8 编码的密钥,你可以使用以下代码:

  1. func main() {
  2. pemString := `-----BEGIN PRIVATE KEY-----
  3. MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKhPSTDs4cpKfnMc
  4. p86fCkpnuER7bGc+mGkhkw6bE+BnROfrDCFBSjrENLS5JcsenANQ1kYGt9iVW2fd
  5. ZAWUdDoj+t7g6+fDpzY1BzPSUls421Dmu7joDPY8jSdMzFCeg7Lyj0I36bJJ7ooD
  6. VPW6Q0XQcb8FfBiFPAKuY4elj/YDAgMBAAECgYBo2GMWmCmbM0aL/KjH/KiTawMN
  7. nfkMY6DbtK9/5LjADHSPKAt5V8ueygSvI7rYSiwToLKqEptJztiO3gnls/GmFzj1
  8. V/QEvFs6Ux3b0hD2SGpGy1m6NWWoAFlMISRkNiAxo+AMdCi4I1hpk4+bHr9VO2Bv
  9. V0zKFxmgn1R8qAR+4QJBANqKxJ/qJ5+lyPuDYf5s+gkZWjCLTC7hPxIJQByDLICw
  10. iEnqcn0n9Gslk5ngJIGQcKBXIp5i0jWSdKN/hLxwgHECQQDFKGmo8niLzEJ5sa1r
  11. spww8Hc2aJM0pBwceshT8ZgVPnpgmITU1ENsKpJ+y1RTjZD6N0aj9gS9UB/UXdTr
  12. HBezAkEAqkDRTYOtusH9AXQpM3zSjaQijw72Gs9/wx1RxOSsFtVwV6U97CLkV1S+
  13. 2HG1/vn3w/IeFiYGfZXLKFR/pA5BAQJAbFeu6IaGM9yFUzaOZDZ8mnAqMp349t6Q
  14. DB5045xJxLLWsSpfJE2Y12H1qvO1XUzYNIgXq5ZQOHBFbYA6txBy/QJBAKDRQN47
  15. 6YClq9652X+1lYIY/h8MxKiXpVZVncXRgY6pbj4pmWEAM88jra9Wq6R77ocyECzi
  16. XCqi18A/sl6ymWc=
  17. -----END PRIVATE KEY-----`
  18. block, _ := pem.Decode([]byte(pemString))
  19. parseResult, _ := x509.ParsePKCS8PrivateKey(block.Bytes)
  20. key := parseResult.(*rsa.PrivateKey)
  21. fmt.Println(key.N)
  22. }
英文:

A combination of pem.Decode and x509.ParsePKCS1PrivateKey should do the trick:

  1. package main
  2. import (
  3. &quot;crypto/x509&quot;
  4. &quot;encoding/pem&quot;
  5. &quot;fmt&quot;
  6. )
  7. func main() {
  8. pemString := `-----BEGIN RSA PRIVATE KEY-----
  9. MIICXQIBAAKBgQDLets8+7M+iAQAqN/5BVyCIjhTQ4cmXulL+gm3v0oGMWzLupUS
  10. v8KPA+Tp7dgC/DZPfMLaNH1obBBhJ9DhS6RdS3AS3kzeFrdu8zFHLWF53DUBhS92
  11. 5dCAEuJpDnNizdEhxTfoHrhuCmz8l2nt1pe5eUK2XWgd08Uc93h5ij098wIDAQAB
  12. AoGAHLaZeWGLSaen6O/rqxg2laZ+jEFbMO7zvOTruiIkL/uJfrY1kw+8RLIn+1q0
  13. wLcWcuEIHgKKL9IP/aXAtAoYh1FBvRPLkovF1NZB0Je/+CSGka6wvc3TGdvppZJe
  14. rKNcUvuOYLxkmLy4g9zuY5qrxFyhtIn2qZzXEtLaVOHzPQECQQDvN0mSajpU7dTB
  15. w4jwx7IRXGSSx65c+AsHSc1Rj++9qtPC6WsFgAfFN2CEmqhMbEUVGPv/aPjdyWk9
  16. pyLE9xR/AkEA2cGwyIunijE5v2rlZAD7C4vRgdcMyCf3uuPcgzFtsR6ZhyQSgLZ8
  17. YRPuvwm4cdPJMmO3YwBfxT6XGuSc2k8MjQJBAI0+b8prvpV2+DCQa8L/pjxp+VhR
  18. Xrq2GozrHrgR7NRokTB88hwFRJFF6U9iogy9wOx8HA7qxEbwLZuhm/4AhbECQC2a
  19. d8h4Ht09E+f3nhTEc87mODkl7WJZpHL6V2sORfeq/eIkds+H6CJ4hy5w/bSw8tjf
  20. sz9Di8sGIaUbLZI2rd0CQQCzlVwEtRtoNCyMJTTrkgUuNufLP19RZ5FpyXxBO5/u
  21. QastnN77KfUwdj3SJt44U/uh1jAIv4oSLBr8HYUkbnI8
  22. -----END RSA PRIVATE KEY-----`
  23. block, _ := pem.Decode([]byte(pemString))
  24. key, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
  25. fmt.Println(key.N)
  26. }

If what you are sitting on is a PKCS#8 encoded key, instead you would do something like the following:

  1. func main() {
  2. pemString := `-----BEGIN PRIVATE KEY-----
  3. MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKhPSTDs4cpKfnMc
  4. p86fCkpnuER7bGc+mGkhkw6bE+BnROfrDCFBSjrENLS5JcsenANQ1kYGt9iVW2fd
  5. ZAWUdDoj+t7g6+fDpzY1BzPSUls421Dmu7joDPY8jSdMzFCeg7Lyj0I36bJJ7ooD
  6. VPW6Q0XQcb8FfBiFPAKuY4elj/YDAgMBAAECgYBo2GMWmCmbM0aL/KjH/KiTawMN
  7. nfkMY6DbtK9/5LjADHSPKAt5V8ueygSvI7rYSiwToLKqEptJztiO3gnls/GmFzj1
  8. V/QEvFs6Ux3b0hD2SGpGy1m6NWWoAFlMISRkNiAxo+AMdCi4I1hpk4+bHr9VO2Bv
  9. V0zKFxmgn1R8qAR+4QJBANqKxJ/qJ5+lyPuDYf5s+gkZWjCLTC7hPxIJQByDLICw
  10. iEnqcn0n9Gslk5ngJIGQcKBXIp5i0jWSdKN/hLxwgHECQQDFKGmo8niLzEJ5sa1r
  11. spww8Hc2aJM0pBwceshT8ZgVPnpgmITU1ENsKpJ+y1RTjZD6N0aj9gS9UB/UXdTr
  12. HBezAkEAqkDRTYOtusH9AXQpM3zSjaQijw72Gs9/wx1RxOSsFtVwV6U97CLkV1S+
  13. 2HG1/vn3w/IeFiYGfZXLKFR/pA5BAQJAbFeu6IaGM9yFUzaOZDZ8mnAqMp349t6Q
  14. DB5045xJxLLWsSpfJE2Y12H1qvO1XUzYNIgXq5ZQOHBFbYA6txBy/QJBAKDRQN47
  15. 6YClq9652X+1lYIY/h8MxKiXpVZVncXRgY6pbj4pmWEAM88jra9Wq6R77ocyECzi
  16. XCqi18A/sl6ymWc=
  17. -----END PRIVATE KEY-----`
  18. block, _ := pem.Decode([]byte(pemString))
  19. parseResult, _ := x509.ParsePKCS8PrivateKey(block.Bytes)
  20. key := parseResult.(*rsa.PrivateKey)
  21. fmt.Println(key.N)
  22. }

答案2

得分: 3

有一个有用的函数ssh.ParseRawPrivateKey,它已经实现了一些所需的逻辑。我建议在此基础上进行构建,特别是如果您的密钥用作SSH密钥,就像在我的情况下一样。

  1. import (
  2. "os"
  3. "crypto/rsa"
  4. "golang.org/x/crypto/ssh"
  5. "io/ioutil"
  6. )
  7. func mustNot(err error) {
  8. if err != nil {
  9. panic(err)
  10. }
  11. }
  12. func loadRsaPrivateKey() *rsa.PrivateKey {
  13. bytes, err := ioutil.ReadFile(os.Getenv("HOME") + "/.ssh/id_rsa")
  14. mustNot(err)
  15. key, err := ssh.ParseRawPrivateKey(bytes)
  16. mustNot(err)
  17. return key.(*rsa.PrivateKey)
  18. }
英文:

There is a helpful function ssh.ParseRawPrivateKey which already implements some of the required logic. I suggest building upon it, especially if your key is used as a SSH key, which in my case it is.

  1. import (
  2. &quot;os&quot;
  3. &quot;crypto/rsa&quot;
  4. &quot;golang.org/x/crypto/ssh&quot;
  5. &quot;io/ioutil&quot;
  6. )
  7. func mustNot(err error) {
  8. if err != nil {
  9. panic(err)
  10. }
  11. }
  12. func loadRsaPrivateKey() *rsa.PrivateKey {
  13. bytes, err := ioutil.ReadFile(os.Getenv(&quot;HOME&quot;) + &quot;/.ssh/id_rsa&quot;)
  14. mustNot(err)
  15. key, err := ssh.ParseRawPrivateKey(bytes)
  16. mustNot(err)
  17. return key.(*rsa.PrivateKey)
  18. }

答案3

得分: 1

这是一个完整的示例,包括私钥和公钥的pem文件:

  1. import (
  2. "crypto/rand"
  3. "crypto/rsa"
  4. "crypto/x509"
  5. "encoding/pem"
  6. "io/ioutil"
  7. "log"
  8. )
  9. func RSAConfigSetup(rsaPrivateKeyLocation, privatePassphrase, rsaPublicKeyLocation string) (*rsa.PrivateKey, error) {
  10. if rsaPrivateKeyLocation == "" {
  11. log.Println("未提供RSA密钥,生成临时密钥")
  12. return GenRSA(4096)
  13. }
  14. priv, err := ioutil.ReadFile(rsaPrivateKeyLocation)
  15. if err != nil {
  16. log.Println("未找到RSA私钥,生成临时密钥")
  17. return GenRSA(4096)
  18. }
  19. privPem, _ := pem.Decode(priv)
  20. if privPem.Type != "RSA PRIVATE KEY" {
  21. log.Println("RSA私钥类型错误", privPem.Type)
  22. }
  23. if x509.IsEncryptedPEMBlock(privPem) && privatePassphrase == "" {
  24. log.Println("需要密码来打开私钥pem文件")
  25. return GenRSA(4096)
  26. }
  27. var privPemBytes []byte
  28. if privatePassphrase != "" {
  29. privPemBytes, err = x509.DecryptPEMBlock(privPem, []byte(privatePassphrase))
  30. } else {
  31. privPemBytes = privPem.Bytes
  32. }
  33. var parsedKey interface{}
  34. //PKCS1
  35. if parsedKey, err = x509.ParsePKCS1PrivateKey(privPemBytes); err != nil {
  36. //如果你手上的是PKCS#8编码的密钥
  37. if parsedKey, err = x509.ParsePKCS8PrivateKey(privPemBytes); err != nil { // 注意这里返回的是`interface{}`
  38. log.Println("无法解析RSA私钥,生成临时密钥", err)
  39. return GenRSA(4096)
  40. }
  41. }
  42. var privateKey *rsa.PrivateKey
  43. var ok bool
  44. privateKey, ok = parsedKey.(*rsa.PrivateKey)
  45. if !ok {
  46. log.Println("无法解析RSA私钥,生成临时密钥", err)
  47. return GenRSA(4096)
  48. }
  49. pub, err := ioutil.ReadFile(rsaPublicKeyLocation)
  50. if err != nil {
  51. log.Println("未找到RSA公钥,生成临时密钥")
  52. return GenRSA(4096)
  53. }
  54. pubPem, _ := pem.Decode(pub)
  55. if pubPem == nil {
  56. log.Println("使用 `ssh-keygen -f id_rsa.pub -e -m pem > id_rsa.pem` 生成RSA公钥的pem编码 - RSA公钥不是pem格式")
  57. return GenRSA(4096)
  58. }
  59. if pubPem.Type != "RSA PUBLIC KEY" {
  60. log.Println("RSA公钥类型错误", pubPem.Type)
  61. return GenRSA(4096)
  62. }
  63. if parsedKey, err = x509.ParsePKIXPublicKey(pubPem.Bytes); err != nil {
  64. log.Println("无法解析RSA公钥,生成临时密钥", err)
  65. return GenRSA(4096)
  66. }
  67. var pubKey *rsa.PublicKey
  68. if pubKey, ok = parsedKey.(*rsa.PublicKey); !ok {
  69. log.Println("无法解析RSA公钥,生成临时密钥", err)
  70. return GenRSA(4096)
  71. }
  72. privateKey.PublicKey = *pubKey
  73. return privateKey, nil
  74. }
  75. // GenRSA 返回一个长度为bits的新RSA密钥
  76. func GenRSA(bits int) (*rsa.PrivateKey, error) {
  77. key, err := rsa.GenerateKey(rand.Reader, bits)
  78. return key, err
  79. }

这是一个用于设置RSA配置的函数,它可以根据提供的私钥和公钥文件路径以及私钥密码来生成RSA私钥。如果未提供私钥文件或无法解析私钥文件,则会生成一个临时的RSA私钥。函数还会读取公钥文件并将其与私钥关联起来。最后,函数返回生成的RSA私钥。

另外,还有一个名为GenRSA的函数,用于生成指定位数的RSA密钥对。

英文:

Here's a full example for both private and public pem files:

  1. import (
  2. &quot;crypto/rand&quot;
  3. &quot;crypto/rsa&quot;
  4. &quot;crypto/x509&quot;
  5. &quot;encoding/pem&quot;
  6. &quot;io/ioutil&quot;
  7. &quot;log&quot;
  8. )
  9. func RSAConfigSetup(rsaPrivateKeyLocation, privatePassphrase, rsaPublicKeyLocation string) (*rsa.PrivateKey, error) {
  10. if rsaPrivateKeyLocation == &quot;&quot; {
  11. log.Println(&quot;No RSA Key given, generating temp one&quot;)
  12. return GenRSA(4096)
  13. }
  14. priv, err := ioutil.ReadFile(rsaPrivateKeyLocation)
  15. if err != nil {
  16. log.Println(&quot;No RSA private key found, generating temp one&quot;)
  17. return GenRSA(4096)
  18. }
  19. privPem, _ := pem.Decode(priv)
  20. if privPem.Type != &quot;RSA PRIVATE KEY&quot; {
  21. log.Println(&quot;RSA private key is of the wrong type&quot;, privPem.Type)
  22. }
  23. if x509.IsEncryptedPEMBlock(privPem) &amp;&amp; privatePassphrase == &quot;&quot; {
  24. log.Println(&quot;Passphrase is required to open private pem file&quot;)
  25. return GenRSA(4096)
  26. }
  27. var privPemBytes []byte
  28. if privatePassphrase != &quot;&quot; {
  29. privPemBytes, err = x509.DecryptPEMBlock(privPem, []byte(privatePassphrase))
  30. } else {
  31. privPemBytes = privPem.Bytes
  32. }
  33. var parsedKey interface{}
  34. //PKCS1
  35. if parsedKey, err = x509.ParsePKCS1PrivateKey(privPemBytes); err != nil {
  36. //If what you are sitting on is a PKCS#8 encoded key
  37. if parsedKey, err = x509.ParsePKCS8PrivateKey(privPemBytes); err != nil { // note this returns type `interface{}`
  38. log.Println(&quot;Unable to parse RSA private key, generating a temp one&quot;, err)
  39. return GenRSA(4096)
  40. }
  41. }
  42. var privateKey *rsa.PrivateKey
  43. var ok bool
  44. privateKey, ok = parsedKey.(*rsa.PrivateKey)
  45. if !ok {
  46. log.Println(&quot;Unable to parse RSA private key, generating a temp one&quot;, err)
  47. return GenRSA(4096)
  48. }
  49. pub, err := ioutil.ReadFile(rsaPublicKeyLocation)
  50. if err != nil {
  51. log.Println(&quot;No RSA public key found, generating temp one&quot;)
  52. return GenRSA(4096)
  53. }
  54. pubPem, _ := pem.Decode(pub)
  55. if pubPem == nil {
  56. log.Println(&quot;Use `ssh-keygen -f id_rsa.pub -e -m pem &gt; id_rsa.pem` to generate the pem encoding of your RSA public key - rsa public key not in pem format&quot;)
  57. return GenRSA(4096)
  58. }
  59. if pubPem.Type != &quot;RSA PUBLIC KEY&quot; {
  60. log.Println(&quot;RSA public key is of the wrong type&quot;, pubPem.Type)
  61. return GenRSA(4096)
  62. }
  63. if parsedKey, err = x509.ParsePKIXPublicKey(pubPem.Bytes); err != nil {
  64. log.Println(&quot;Unable to parse RSA public key, generating a temp one&quot;, err)
  65. return GenRSA(4096)
  66. }
  67. var pubKey *rsa.PublicKey
  68. if pubKey, ok = parsedKey.(*rsa.PublicKey); !ok {
  69. log.Println(&quot;Unable to parse RSA public key, generating a temp one&quot;, err)
  70. return GenRSA(4096)
  71. }
  72. privateKey.PublicKey = *pubKey
  73. return privateKey, nil
  74. }
  75. // GenRSA returns a new RSA key of bits length
  76. func GenRSA(bits int) (*rsa.PrivateKey, error) {
  77. key, err := rsa.GenerateKey(rand.Reader, bits)
  78. return key, err
  79. }

huangapple
  • 本文由 发表于 2017年5月29日 02:28:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/44230634.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定