Reputation: 53
Hello i'am trying to unmarshal object that contain ECC public key but i go umarshaling error saying that can't unmarshal object properly. i'am tring to do the followeing :
var privateKey *ecdsa.PrivateKey
var publicKey ecdsa.PublicKey
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Fatalf("Failed to generate ECDSA key: %s\n", err)
}
publicKey = privateKey.PublicKey
marshalledKey, err := json.Marshal(publicKey)
if err != nil {
panic(err)
}
var unmarshalledKey ecdsa.PublicKey
err2 := json.Unmarshal(marshalledKey, &unmarshalledKey)
if err2 != nil {
panic(err2)
}
and tthe error returned from (err2) is :
panic: json: cannot unmarshal object into Go struct field PublicKey.Curve of type elliptic.Curve
and there is no way in either eliptoc or 509x function to umarshal and the curve value is alwayes null
Upvotes: 1
Views: 1854
Reputation: 396
For public key, it looks like we only need to save the point (X, Y), and the Curve type. If we know what curve is for the original private key, then we only need to save the public point into persistent storage.
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"encoding/json"
"log"
"math/big"
)
type P256PublicKey struct {
X, Y *big.Int
}
func (p *P256PublicKey) Key() *ecdsa.PublicKey {
return &ecdsa.PublicKey{
Curve: elliptic.P256(),
X: p.X,
Y: p.Y,
}
}
func main() {
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
panic(err)
}
pub := &privKey.PublicKey
key := P256PublicKey{
X: pub.X,
Y: pub.Y,
}
// Get bytes and save
bz, err := json.Marshal(key)
if err != nil {
panic(err)
}
nk := P256PublicKey{}
err = json.Unmarshal(bz, &nk)
if err != nil {
panic(err)
}
newPub := key.Key()
log.Printf("is equal: %v", newPub.Equal(pub))
}
More discussion at this issue https://github.com/golang/go/issues/33564#issuecomment-2249743482
Upvotes: 0
Reputation: 53
i found the answer finally and i will post it in case somone need it.
all we need is just to creat another struct, lets name it "retrieve" and declare the value it wil read from the unmarshal.
now the ECC public key contain 3 values "curve" and will append it as json:"Curve"
, "Y" ans will append it as json:"Y"
and we will do the same for "X"
and it will work like this :
type retrieve struct {
CurveParams *elliptic.CurveParams `json:"Curve"`
MyX *big.Int `json:"X"`
MyY *big.Int `json:"Y"`
}
//UnmarshalECCPublicKey extract ECC public key from marshaled objects
func UnmarshalECCPublicKey(object []byte) (pub ecdsa.PublicKey) {
var public ecdsa.PublicKey
rt := new(retrieve)
errmarsh := json.Unmarshal(object, &rt)
if errmarsh != nil {
fmt.Println("err at UnmarshalECCPublicKey()")
panic(errmarsh)
}
public.Curve = rt.Key.CurveParams
public.X = rt.Key.MyX
public.Y = rt.Key.MyY
mapstructure.Decode(public, &pub)
fmt.Println("Unmarshalled ECC public key : ", pub)
return
}
we will pass the the marshalled public key to UnmarshalECCPublicKey() and it will return the correct unmarshaled obj
so the coorect use will be :
var privateKey *ecdsa.PrivateKey
var publicKey ecdsa.PublicKey
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Fatalf("Failed to generate ECDSA key: %s\n", err)
}
publicKey = privateKey.PublicKey
marshalledKey, err := json.Marshal(publicKey)
if err != nil {
panic(err)
}
var unmarshalledKey ecdsa.PublicKey
unmarshalledKey = UnmarshalECCPublicKey(marshalledKey)
and that should do it, u will get the ECC public unmarshalled successfully.
Upvotes: 2