|
6 | 6 | "crypto/rand" |
7 | 7 | "crypto/sha256" |
8 | 8 | "crypto/x509" |
| 9 | + "encoding/base64" |
9 | 10 | "encoding/hex" |
10 | 11 | "fmt" |
11 | 12 | "strings" |
@@ -55,16 +56,18 @@ func ParseP256PrivateKey(keyData []byte) (*ecdsa.PrivateKey, error) { |
55 | 56 | return nil, fmt.Errorf("failed to parse P256 private key from DER or hex format") |
56 | 57 | } |
57 | 58 |
|
58 | | -// SignWithP256 signs data using the P256 private key |
| 59 | +// SignWithP256 signs data using a P256 private key |
59 | 60 | func SignWithP256(privateKey *ecdsa.PrivateKey, data []byte) ([]byte, error) { |
| 61 | + if privateKey == nil { |
| 62 | + return nil, fmt.Errorf("invalid private key: private key is nil") |
| 63 | + } |
| 64 | + |
60 | 65 | if privateKey.Curve == nil { |
61 | 66 | return nil, fmt.Errorf("invalid private key: curve is nil") |
62 | 67 | } |
63 | 68 |
|
64 | 69 | hash := sha256.Sum256(data) |
65 | 70 |
|
66 | | - // Use crypto/ecdsa.Sign to create a proper P256 signature |
67 | | - // The signature will be in ASN.1 DER format |
68 | 71 | signature, err := ecdsa.SignASN1(rand.Reader, privateKey, hash[:]) |
69 | 72 | if err != nil { |
70 | 73 | return nil, fmt.Errorf("failed to sign data: %w", err) |
@@ -117,3 +120,65 @@ func VerifyP256Signature(publicKey *ecdsa.PublicKey, data []byte, signature []by |
117 | 120 |
|
118 | 121 | return nil |
119 | 122 | } |
| 123 | +func ParseP256PublicKeyFromBytes(keyBytes []byte) (*ecdsa.PublicKey, error) { |
| 124 | + // Try to parse as DER first |
| 125 | + if key, err := x509.ParsePKIXPublicKey(keyBytes); err == nil { |
| 126 | + if ecdsaKey, ok := key.(*ecdsa.PublicKey); ok { |
| 127 | + if ecdsaKey.Curve == elliptic.P256() { |
| 128 | + return ecdsaKey, nil |
| 129 | + } |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + // Try to parse as EC public key |
| 134 | + if key, err := x509.ParsePKIXPublicKey(keyBytes); err == nil { |
| 135 | + if ecdsaKey, ok := key.(*ecdsa.PublicKey); ok { |
| 136 | + if ecdsaKey.Curve == elliptic.P256() { |
| 137 | + return ecdsaKey, nil |
| 138 | + } |
| 139 | + } |
| 140 | + } |
| 141 | + |
| 142 | + return nil, fmt.Errorf("failed to parse P-256 public key from bytes") |
| 143 | +} |
| 144 | + |
| 145 | +// ParseP256PublicKeyFromHex parses a P-256 public key from hex string |
| 146 | +func ParseP256PublicKeyFromHex(hexString string) (*ecdsa.PublicKey, error) { |
| 147 | + // Remove 0x prefix if present |
| 148 | + if strings.HasPrefix(hexString, "0x") { |
| 149 | + hexString = hexString[2:] |
| 150 | + } |
| 151 | + |
| 152 | + // Decode hex |
| 153 | + keyBytes, err := hex.DecodeString(hexString) |
| 154 | + if err != nil { |
| 155 | + return nil, fmt.Errorf("failed to decode hex string: %w", err) |
| 156 | + } |
| 157 | + |
| 158 | + return ParseP256PublicKeyFromBytes(keyBytes) |
| 159 | +} |
| 160 | + |
| 161 | +// ParseP256PublicKeyFromBase64 parses a P-256 public key from base64 string |
| 162 | +func ParseP256PublicKeyFromBase64(base64String string) (*ecdsa.PublicKey, error) { |
| 163 | + // Decode base64 |
| 164 | + keyBytes, err := base64.StdEncoding.DecodeString(base64String) |
| 165 | + if err != nil { |
| 166 | + return nil, fmt.Errorf("failed to decode base64 string: %w", err) |
| 167 | + } |
| 168 | + |
| 169 | + return ParseP256PublicKeyFromBytes(keyBytes) |
| 170 | +} |
| 171 | + |
| 172 | +// ValidateP256PublicKey validates that a public key is P-256 |
| 173 | +func ValidateP256PublicKey(publicKey *ecdsa.PublicKey) error { |
| 174 | + if publicKey == nil { |
| 175 | + return fmt.Errorf("public key is nil") |
| 176 | + } |
| 177 | + if publicKey.Curve == nil { |
| 178 | + return fmt.Errorf("public key curve is nil") |
| 179 | + } |
| 180 | + if publicKey.Curve != elliptic.P256() { |
| 181 | + return fmt.Errorf("public key is not P-256 curve (got: %s)", publicKey.Curve.Params().Name) |
| 182 | + } |
| 183 | + return nil |
| 184 | +} |
0 commit comments