从Golang类型中提取未导出字段的正确方法是什么?

时间:2015-07-23 16:41:13

标签: reflection ssh go type-conversion rsa

我正在尝试使用SSH公钥(x.crypto.ssh.PublicKey,通过解析authorized_keys生成)并从中提取一个普通的旧crypto.rsa.PublicKey(我知道密钥是输入ssh-rsa)。这意味着,在ssh-land中,密钥是(未导出的)类型rsaPublicKey

使用reflect.Interface()或普通旧fmt.Sprintf("%v")我可以获得一个类似于以下内容的值:

&{133141753607255377833524803712241410600224583899447743985716492314976605735038858392516407436607315136967439536840885454950028631410155683051419836325912444338003188332463816050354540934271243064035037856360864190161298769948076508355604915775510460445701536855931828420791030023079646791573156484306628882221 35}

我知道,通过阅读ssh包源,ssh.rsaPublickey实际上被定义为我想要的类型:

type rsaPublicKey rsa.PublicKey

因此这个值已经是我想要的了。 (事实上​​,我可以使用"%+v",甚至可以看到其字段(当然)名为NE。)

我的问题是我不知道一个更好的方法让Go认为这实际上是rsa.PublicKey,而不是将每个数字提取到fmt.Sscan的字符串中,然后转换为分别为big.Intint,然后使用我刚刚得到的两个值作为模数和指数来创建新的rsa.PublicKey

这有效,但看起来非常令人讨厌。我得到了,因为它没有被导出,可能没有直接的路线,但肯定有更好的方法来获得字段而不是重新转换其可打印的表示。

ssh.PublicKey确实有一个Marshal()函数,但这给了我线格式表示,如果我经过那里,好吧,我想它避免滥用类型系统,但我会最后在那里编写我自己的byte-stream-to-big-Int-to-RSA转换器,这似乎并没有真正的帮助。那时我也可以从authorized_keys文件开始并自己解析它,这看起来也很愚蠢。

这样做的正确方法是什么?

2 个答案:

答案 0 :(得分:1)

您可以使用reflect将该界面值转换回原始rsa.PublicKey

rsaKey := reflect.ValueOf(sshKey).
    Convert(reflect.TypeOf(&rsa.PublicKey{})).Interface().(*rsa.PublicKey)

带有类似示例的游乐场:http://play.golang.org/p/bcYhYHrIl_

答案 1 :(得分:0)

您可以做的最好的事情是使用反射从N interace中的E中提取rsaPublicKeyssh.PublicKey值:

// pub, _, _, _, err := ssh.ParseAuthorizedKey(authKeyData)
val := reflect.ValueOf(pub).Elem()
n := val.FieldByName("N").Interface().(*big.Int)
e := val.FieldByName("E").Interface().(int)

rsaKey := &rsa.PublicKey{
    N: n,
    E: e,
}