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

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

What's the proper way to extract unexported fields from a Golang type?

问题

我正在尝试从一个SSH公钥(由解析authorized_keys生成的x.crypto.ssh.PublicKey)中提取一个普通的crypto.rsa.PublicKey(我知道该密钥的类型是ssh-rsa)。这意味着在SSH领域,该密钥是未导出的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()函数,但它给我提供的是线路格式的表示,如果我通过那里,嗯,我猜它避免了滥用类型系统,但我最终只会编写自己的字节流到大整数到RSA的转换器,这似乎并没有真正帮助。在那一点上,我可能还不如直接从authorized_keys文件开始并自己解析它,这似乎也很愚蠢。

有什么正确的方法来做到这一点呢?

英文:

I'm trying to take an SSH public key (x.crypto.ssh.PublicKey, generated by parsing authorized_keys) and extract a plain old crypto.rsa.PublicKey from it (I know the key is of type ssh-rsa). That means, in ssh-land, the key is of (unexported) type rsaPublicKey.

By using either reflect.Interface() or plain old fmt.Sprintf("%v") I can get a value that looks like:

&{133141753607255377833524803712241410600224583899447743985716492314976605735038858392516407436607315136967439536840885454950028631410155683051419836325912444338003188332463816050354540934271243064035037856360864190161298769948076508355604915775510460445701536855931828420791030023079646791573156484306628882221 35}

I know, by reading the ssh package source, that ssh.rsaPublickey is in fact defined as the type I want:

type rsaPublicKey rsa.PublicKey

and therefore this value is already the thing I want. (In fact, I can, using "%+v", even see that its fields are (of course) named N and E.)

My problem is that I don't know a better way to make Go believe that this is in fact an rsa.PublicKey than to extract each of those numbers into strings with fmt.Sscan, and then convert into big.Int and int, respectively, and then use those two values I just got as the modulus and exponent to create a new rsa.PublicKey.

That works, but seems incredibly nasty. I get that since it's unexported, there's probably no direct route, but surely there's a better way to get the fields than by reconverting their printable representations.

ssh.PublicKey does have a Marshal() function, but that gives me the wire-format representation, and if I go through there, well, I guess it avoids abusing the type system, but I'd just end up writing my own byte-stream-to-big-Int-to-RSA converter there, which doesn't seem like it really helps. At that point I might just as well start with the authorized_keys file and parse it myself, and that seems dumb too.

What's the right way to do this?

答案1

得分: 1

你可以使用reflect将该接口值转换回原始的rsa.PublicKey

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

类似示例的 Playground:http://play.golang.org/p/bcYhYHrIl_。

英文:

You can use reflect to convert that interface value back to the original rsa.PublicKey:

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

Playground with a similar example: http://play.golang.org/p/bcYhYHrIl_.

答案2

得分: 0

你可以使用反射来从ssh.PublicKey接口的rsaPublicKey中提取NE的值:

// 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,
}

请注意,这是一段代码,用于从rsaPublicKey中提取NE的值,并创建一个rsa.PublicKey对象。

英文:

The best you can do is use reflection to extract the N and E values from the rsaPublicKey in the ssh.PublicKey interace:

// 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,
}

huangapple
  • 本文由 发表于 2015年7月24日 00:41:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/31593329.html
匿名

发表评论

匿名网友

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

确定