从PEM文件加载(openssl生成)DSA私钥

时间:2015-10-23 11:33:25

标签: go openssl digital-signature

我正在尝试在我的程序中加载一个dsa私钥,以下是我如何处理它:

  1. 我使用openssl创建了一个dsa密钥对:

    openssl dsaparam -genkey 2048 -out dsakey.pem
    
  2. 我使用以下函数来解析pem文件

    func getDSAPrivateKeyFromPemFile(pemfilepath string) (recoveredprivateKey *dsa.PrivateKey, err error) {
    pemfile, err := os.Open(pemfilepath)
    if err != nil {
        return nil, err
    }
    recoveredbytes, err := ioutil.ReadAll(pemfile)
    if err != nil {
        return nil, err
    }
    
    recoveredpemdsaparameteres, rest := pem.Decode(recoveredbytes)
    if recoveredpemdsaparameteres == nil {
        return nil, errors.New("No pem recovered")
    }
    
    _, err = asn1.Unmarshal(append(recoveredpemdsaparameteres.Bytes, recoveredpemdsaprivatekey.Bytes...), recoveredprivateKey)
    if err != nil {
        return nil, err
     }
     fmt.Printf("PEM:%v\n", recoveredpemdsaparameteres)
    
     recoveredpemdsaprivatekey, _ := pem.Decode(rest)
     fmt.Printf("PEM:%v\n", recoveredpemdsaprivatekey)
     pemfile.Close()
    }
    
  3. 如果失败则调用此函数:

    panic: reflect: call of reflect.Value.Type on zero Value
    
    goroutine 1 [running]:
    reflect.Value.Type(0x0, 0x0, 0x0, 0x0, 0x0)
        /usr/local/go/src/reflect/value.go:1664 +0x7b
    encoding/asn1.parseField(0x0, 0x0, 0x0, 0xc8200b0600, 0x58b, 0x600, 0x0, 0x0, 0x0, 0x0, ...)
        /usr/local/go/src/encoding/asn1/asn1.go:558 +0xbd
    encoding/asn1.UnmarshalWithParams(0xc8200b0600, 0x58b, 0x600, 0x1383e0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
        /usr/local/go/src/encoding/asn1/asn1.go:957 +0x16e
    encoding/asn1.Unmarshal(0xc8200b0600, 0x58b, 0x600, 0x1383e0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
        /usr/local/go/src/encoding/asn1/asn1.go:950 +0x8f
    main.getDSAPrivateKeyFromPemFile(0x1e7fa0, 0x26, 0x0, 0x0, 0x0)
    

    但是,我可以在输出中完美地看到我的dsa键:

    PEM:&{DSA PARAMETERS map[] [48 130 2 45 2 130...]}
    PEM:&{DSA PRIVATE KEY map[] [48 130 3 86 2 1 0 ...]}
    

    问题实际上是如何将pem字节解组为dsa.PrivateKey。 有什么想法吗?

    P.S:我无法找到任何通过互联网加载DSA私钥pem文件的示例。

1 个答案:

答案 0 :(得分:1)

花了几个小时后,我设法解决了我的问题 我发布我的发现,这样可以节省一些人的时间:

首先,我使用这个出色的在线工具审核了我的pem文件编码:http://lapo.it/asn1js/。只有这时我才意识到go期待pem文件有不同的结构...不好! 另外,将文件中的每个值与相应的dsa.PrivateKey结构相关联并不困难。 所以,我创建了一个新结构,并将其命名为MyPrivateKey,其顺序与pem文件相同:

type MyPrivateKey struct {
    E1, P, Q, G, Y, X *big.Int
}

然后,我没有尝试直接解组到dsa.PrivateKey,而是将asn1编码的值解组为我自制的struct。神奇地它起作用了。这是修改后的函数:

func getDSAPrivateKeyFromPemFile(pemFilePath string) (privateKey *dsa.PrivateKey, err error) {
    pemfile, err := os.Open(pemFilePath)

    if err != nil {
        return nil, err
    }
    recoveredBytes, err := ioutil.ReadAll(pemfile)
    if err != nil {
        return nil, err
    }
    pemfile.Close()

    pemDSAParameters, rest := pem.Decode(recoveredBytes)
    if pemDSAParameters == nil {
        return nil, errors.New("No pem recovered")
    }
    pemDSAPrivateKey, _ := pem.Decode(rest)
    keyParameters := dsa.Parameters{G: big.NewInt(0), P: big.NewInt(0), Q: big.NewInt(0)}
    _, err = asn1.Unmarshal(pemDSAParameters.Bytes, &keyParameters)
    if err != nil {
        return nil, err
    }
    //fmt.Printf("\n\n\n\n\n\nP:%x\n\nG:%x\n\nQ:%x\n\n\n\n\n\n", keyParameters.P, keyParameters.G, keyParameters.Q)
    myPrivateKey := MyPrivateKey{}
    _, err = asn1.Unmarshal(pemDSAPrivateKey.Bytes, &myPrivateKey)
    if err != nil {
        return nil, err
    }
    //fmt.Printf("\nprivate\nE1:%x\n\nP:%x\n\nQ:%x\n\nG:%x\n\nY:%x\nX:%x\n\n\n\n", myPrivateKey.E1, myPrivateKey.P, myPrivateKey.Q, myPrivateKey.G, myPrivateKey.Y, myPrivateKey.X)
    privateKey = &dsa.PrivateKey{}
    privateKey.Parameters = keyParameters
    privateKey.X = myPrivateKey.X

    return privateKey, nil
}

也许有一个更简单的方法来解决这个问题,我只是忽略了!如果您知道更好的方式请成为我的客人!否则,我相信go应该在标准库中处理这类问题。