gmessages/libgm/crypto/ecdsa.go
2023-07-15 20:47:56 +03:00

99 lines
2.2 KiB
Go

package crypto
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"fmt"
"math/big"
)
type JWK struct {
KeyType string `json:"kty"`
Curve string `json:"crv"`
D string `json:"d"`
X string `json:"x"`
Y string `json:"y"`
}
func (t *JWK) GetPrivateKey() (*ecdsa.PrivateKey, error) {
curve := elliptic.P256()
xBytes, err := base64.RawURLEncoding.DecodeString(t.X)
if err != nil {
return nil, err
}
yBytes, err := base64.RawURLEncoding.DecodeString(t.Y)
if err != nil {
return nil, err
}
dBytes, err := base64.RawURLEncoding.DecodeString(t.D)
if err != nil {
return nil, err
}
priv := &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: curve,
X: new(big.Int).SetBytes(xBytes),
Y: new(big.Int).SetBytes(yBytes),
},
D: new(big.Int).SetBytes(dBytes),
}
return priv, nil
}
func (t *JWK) GetPublicKey() (*ecdsa.PublicKey, error) {
xBytes, err := base64.RawURLEncoding.DecodeString(t.X)
if err != nil {
return nil, err
}
yBytes, err := base64.RawURLEncoding.DecodeString(t.Y)
if err != nil {
return nil, err
}
x := new(big.Int).SetBytes(xBytes)
y := new(big.Int).SetBytes(yBytes)
pubKey := &ecdsa.PublicKey{
Curve: elliptic.P256(),
X: x,
Y: y,
}
return pubKey, nil
}
func (t *JWK) MarshalPubKey() ([]byte, error) {
pubKey, err := t.GetPublicKey()
if err != nil {
return nil, err
}
return elliptic.Marshal(pubKey.Curve, pubKey.X, pubKey.Y), nil
}
func (t *JWK) SignRequest(requestID string, timestamp int64) ([]byte, error) {
signBytes := sha256.Sum256([]byte(fmt.Sprintf("%s:%d", requestID, timestamp)))
privKey, privErr := t.GetPrivateKey()
if privErr != nil {
return nil, privErr
}
return ecdsa.SignASN1(rand.Reader, privKey, signBytes[:])
}
// GenerateECDSAKey generates a new ECDSA private key with P-256 curve
func GenerateECDSAKey() (*JWK, error) {
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, err
}
return &JWK{
KeyType: "EC",
Curve: "P-256",
D: base64.RawURLEncoding.EncodeToString(privKey.D.Bytes()),
X: base64.RawURLEncoding.EncodeToString(privKey.X.Bytes()),
Y: base64.RawURLEncoding.EncodeToString(privKey.Y.Bytes()),
}, nil
}