【问题标题】:Save and load crypto/rsa PrivateKey to and from the disk在磁盘上保存和加载 crypto/rsa PrivateKey
【发布时间】:2012-11-13 08:29:01
【问题描述】:

我正在使用crypto/rsa,并试图找到一种正确保存和加载密钥的方法。有没有从rsa.PrivateKey 创建[]byte 的正确方法。如果是这样,有没有办法为rsa.PublicKey 正确执行此操作?

非常感谢大家。

【问题讨论】:

    标签: go cryptography rsa


    【解决方案1】:

    您需要某种格式来编组密钥。 Go 标准库支持的一种格式可以在这里找到:http://golang.org/pkg/crypto/x509/#MarshalPKCS1PrivateKey

    func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte
    

    反函数是http://golang.org/pkg/crypto/x509/#ParsePKCS1PrivateKey

    func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error)
    

    但是,将封送密钥编码到 PEM 文件中是相对标准的。

    pemdata := pem.EncodeToMemory(
        &pem.Block{
            Type: "RSA PRIVATE KEY",
            Bytes: x509.MarshalPKCS1PrivateKey(key),
        },
    )
    

    你可以找到一个完整的例子here

    【讨论】:

    • 您始终可以从私钥中提取公钥。如果你只想写公钥,你可以使用x509.MarshalPKIXPublicKey
    【解决方案2】:

    这里的代码 sn-p 显示了公钥和私钥的导入和导出。它基于其他非常有用的答案,以及来自官方文档的 copy-pasta。

    package main
    
    import (
        "crypto/rand"
        "crypto/rsa"
        "crypto/x509"
        "encoding/pem"
        "errors"
        "fmt"
    )
    
    func GenerateRsaKeyPair() (*rsa.PrivateKey, *rsa.PublicKey) {
        privkey, _ := rsa.GenerateKey(rand.Reader, 4096)
        return privkey, &privkey.PublicKey
    }
    
    func ExportRsaPrivateKeyAsPemStr(privkey *rsa.PrivateKey) string {
        privkey_bytes := x509.MarshalPKCS1PrivateKey(privkey)
        privkey_pem := pem.EncodeToMemory(
                &pem.Block{
                        Type:  "RSA PRIVATE KEY",
                        Bytes: privkey_bytes,
                },
        )
        return string(privkey_pem)
    }
    
    func ParseRsaPrivateKeyFromPemStr(privPEM string) (*rsa.PrivateKey, error) {
        block, _ := pem.Decode([]byte(privPEM))
        if block == nil {
                return nil, errors.New("failed to parse PEM block containing the key")
        }
    
        priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
        if err != nil {
                return nil, err
        }
    
        return priv, nil
    }
    
    func ExportRsaPublicKeyAsPemStr(pubkey *rsa.PublicKey) (string, error) {
        pubkey_bytes, err := x509.MarshalPKIXPublicKey(pubkey)
        if err != nil {
                return "", err
        }
        pubkey_pem := pem.EncodeToMemory(
                &pem.Block{
                        Type:  "RSA PUBLIC KEY",
                        Bytes: pubkey_bytes,
                },
        )
    
        return string(pubkey_pem), nil
    }
    
    func ParseRsaPublicKeyFromPemStr(pubPEM string) (*rsa.PublicKey, error) {
        block, _ := pem.Decode([]byte(pubPEM))
        if block == nil {
                return nil, errors.New("failed to parse PEM block containing the key")
        }
    
        pub, err := x509.ParsePKIXPublicKey(block.Bytes)
        if err != nil {
                return nil, err
        }
    
        switch pub := pub.(type) {
        case *rsa.PublicKey:
                return pub, nil
        default:
                break // fall through
        }
        return nil, errors.New("Key type is not RSA")
    }
    
    func main() {
    
        // Create the keys
        priv, pub := GenerateRsaKeyPair()
    
        // Export the keys to pem string
        priv_pem := ExportRsaPrivateKeyAsPemStr(priv)
        pub_pem, _ := ExportRsaPublicKeyAsPemStr(pub)
    
        // Import the keys from pem string
        priv_parsed, _ := ParseRsaPrivateKeyFromPemStr(priv_pem)
        pub_parsed, _ := ParseRsaPublicKeyFromPemStr(pub_pem)
    
        // Export the newly imported keys
        priv_parsed_pem := ExportRsaPrivateKeyAsPemStr(priv_parsed)
        pub_parsed_pem, _ := ExportRsaPublicKeyAsPemStr(pub_parsed)
    
        fmt.Println(priv_parsed_pem)
        fmt.Println(pub_parsed_pem)
    
        // Check that the exported/imported keys match the original keys
        if priv_pem != priv_parsed_pem || pub_pem != pub_parsed_pem {
                fmt.Println("Failure: Export and Import did not result in same Keys")
        } else {
                fmt.Println("Success")
        }
    }
    

    【讨论】:

    • 最后验证有点问题:条件应该是||而不是&&
    • ExportRsaPublicKeyAsPemStr 中的公钥页眉/页脚需要修改。修复:Type: "PUBLIC KEY",
    【解决方案3】:

    由于您问题的公钥部分没有得到解答,我只是遇到了同样的问题并解决了它,这里是:

    注意MarshalPKIXPublicKey参数前面的&

    Priv := rsa.GenerateKey(rand.Reader, 4096)
    
    pubASN1, err := x509.MarshalPKIXPublicKey(&Priv.PublicKey)
    if err != nil {
        // do something about it
    }
    
    pubBytes := pem.EncodeToMemory(&pem.Block{
        Type:  "RSA PUBLIC KEY",
        Bytes: pubASN1,
    })
    
    ioutil.WriteFile("key.pub", pubBytes, 0644)
    

    相关阅读:

    • MarshalPKIXPublicKey(pub interface{}) ([]byte, error) godoc
    • EncodeToMemory(b *Block) []byte godoc
    • 阻止godoc

    PS:MarshalPKIXPublicKey 也接受 ECDSA 密钥,适当调整 pem 标头。

    【讨论】:

      【解决方案4】:

      仅供参考:我完善了@David W 的答案并将其放入一个小型 Go 模块中。 https://github.com/rokk4/gorsapemhelpers

      【讨论】:

        猜你喜欢
        • 2013-12-06
        • 1970-01-01
        • 2013-04-28
        • 1970-01-01
        • 1970-01-01
        • 2015-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多