I have two objects. key1
is of type *rsa.PublicKey
. key2
is of type *ssh.PublicKey
which is an interface hiding a *ssh.rsaPublicKey
object. ssh.rsaPublicKey
is defined as:
type ssh.rsaPublicKey rsa.PublicKey
And it has a few extra methods. However, I can't cast either key to an ssh.rsaPublicKey
since that class is "not exported", I can't cast key2
to an rsa.PublicKey
since that doesn't implement ssh.PublicKey
, and I can't access the N
or e
from key2
because I am not supposed to know I have an rsaPublicKey
object.
How am I supposed to compare that key1
and key2
are the same key?
As you mentioned, you can't use type assertion because you can't refer to the unexported type ssh.rsaPublicKey
.
What you want is possible with using the reflect
package.
Since rsa.PublicKey
is the underlying type of ssh.rsaPublicKey
, the pointed value wrapped in key2
can be converted to rsa.PublicKey
. Once you obtain reflect.Value
of your key2
, "navigate" to the pointed value using Value.Elem()
. This value is convertible to a value of type rsa.PublicKey
. You may use the Value.Convert()
to "dynamically", at runtime convert it to rsa.PublicKey
. Once you have it, you can use reflect.DeepEquals()
to do the comparison, or compare it manually.
This is how it could look like:
key1 := &rsa.PublicKey{N: big.NewInt(123), E: 10}
key2, _ := ssh.NewPublicKey(&rsa.PublicKey{N: big.NewInt(123), E: 10})
key2conv := reflect.ValueOf(key2).Elem().
Convert(reflect.TypeOf(rsa.PublicKey{})).Interface()
// key2conf is an interface{}, wrapping an rsa.PublicKey
// Comparision with DeepEqual
fmt.Println(reflect.DeepEqual(*key1, key2conv))
// Comparing manually:
key22 := key2conv.(rsa.PublicKey)
fmt.Println(key1.N.Cmp(key22.N)) // Int.Cmp() returns 0 if equal
fmt.Println(key1.E == key22.E)
Note that when comparing manually, comparing the PublicKey.N
field –which is of type *big.Int
– you need to use the Int.Cmp()
method because comparing pointers compares the memory addresses, not the pointed values. And Int.Cmp()
returns 0
if the 2 values are equal.