gmessages/libgm/crypto/ECDSA.go
Tulir Asokan 1615e146b6 Update library
Co-authored-by: zero <108243503+0xzer@users.noreply.github.com>
2023-07-09 14:49:55 +03:00

139 lines
3.2 KiB
Go

package crypto
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"math/big"
)
type JWK struct {
Kty string `json:"kty"`
Crv string `json:"crv"`
D string `json:"d"`
X string `json:"x"`
Y string `json:"y"`
Ext bool `json:"ext"`
KeyOps []string `json:"key_ops"`
PrivateBytes []byte `json:"private_bytes,omitempty"`
}
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
}
// Returns a byte slice containing the JWK and an error if the generation or export failed.
func (t *JWK) Marshal() ([]byte, error) {
JWKJSON, err := json.Marshal(t)
if err != nil {
fmt.Printf("Failed to marshal JWK: %v", err)
return nil, err
}
fmt.Printf("%s\n", JWKJSON)
return JWKJSON, err
}
func (t *JWK) PrivKeyB64Bytes() ([]byte, error) {
decodedPrivateKey, err2 := base64.RawURLEncoding.DecodeString(t.D)
return decodedPrivateKey, err2
}
func (t *JWK) ExtractPublicKeyDetails(pubKey []byte) *JWK {
x := base64.RawURLEncoding.EncodeToString(pubKey[1:33])
y := base64.RawURLEncoding.EncodeToString(pubKey[33:])
return &JWK{
Kty: "EC",
Crv: "P-256",
X: x,
Y: y,
}
}
func (t *JWK) DecompressPubkey() (*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) UncompressPubKey() ([]byte, 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,
}
uncompressedPubKey := elliptic.Marshal(pubKey.Curve, pubKey.X, pubKey.Y)
return uncompressedPubKey, nil
}
// GenerateECDSA_P256_JWK generates a new ECDSA private key with P-256 curve
func GenerateECDSA_P256_JWK() (*JWK, error) {
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
fmt.Printf("Failed to generate private key: %v", err)
return nil, err
}
JWK := &JWK{
Kty: "EC",
Crv: "P-256",
D: base64.RawURLEncoding.EncodeToString(privKey.D.Bytes()),
X: base64.RawURLEncoding.EncodeToString(privKey.X.Bytes()),
Y: base64.RawURLEncoding.EncodeToString(privKey.Y.Bytes()),
Ext: true,
KeyOps: []string{"sign"},
}
return JWK, nil
}