英文:
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"
,看到它的字段(当然)被命名为N
和E
。)
我的问题是,我不知道让Go相信这实际上是一个rsa.PublicKey
的更好方法,除了使用fmt.Sscan
将这些数字分别提取为字符串,然后分别转换为big.Int
和int
,然后使用我刚刚得到的这两个值作为模数和指数来创建一个新的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
中提取N
和E
的值:
// 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
中提取N
和E
的值,并创建一个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,
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论