basically, -----BEGIN ENCRYPTED SIGSTORE PRIVATE KEY----- is not ans1 encoded but a JSON struct which looks like the follwoing
You need to decode/decrypt the EC key thats embedded inside it. The following keypair in the code does not have passphrase
also see cosign signature-specification
$ go run main.go
{
"kdf": {
"name": "scrypt",
"params": {
"N": 65536,
"r": 8,
"p": 1
},
"salt": "qO75jNQqsQFo9CT4WnkSdf2hW3s6gHvWmObYJISJZ94="
},
"cipher": {
"name": "nacl/secretbox",
"nonce": "URPuPLvn57USx0xNIc80IN+1EsM01n9D"
},
"ciphertext": "BoiMnOK/cVZ1lj6harBEdKj2UR4wGO8r/h8fcEu8VhcyE+RkC08REEzIz6CUPQ2qYDorkgSCHrbQnC/j8iP0UfGpBYtVxH+TAN97y7qUGM/Mp//42TdShmoYf5Agout7ivDjR9E8cEtEtoXzbtMVuSv+UkbuFY4M+/Pr/0xa9OUOk19gyfCjfXSXMffg4UJFRIi5JkL0S3ZVnw=="
}
PublicKey:
Curve: P-256
X: 423b20553642a4b7fef10a8aa7a19051ce7b8caf7e49ac42de036b62ef5093bb
Y: 6c06ae2884acecaada6116507de22cf1a6795bce153abf552dc862e3d8273aeb
-----BEGIN EC PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg1ZAT5dNLdA+LJq9v
NDFUAV4oBgbD6x+Zz/xi2xV9m7qhRANCAARCOyBVNkKkt/7xCoqnoZBRznuMr35J
rELeA2ti71CTu2wGriiErOyq2mEWUH3iLPGmeVvOFTq/VS3IYuPYJzrr
-----END EC PRIVATE KEY-----
Signature (ASN.1 encoded): 304602210088939ef2c6816959ab9b8b61802f291cf228dbcf6e46816b2a5e170bd0aaab44022100a303d435582781b2e53dd139b291245799af42bbc75bfc5fca4597f24c814070
Signature valid: truepackage main
import (
"bytes"
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"crypto/x509"
"encoding/json"
"encoding/pem"
"flag"
"fmt"
"log"
"golang.org/x/crypto/nacl/secretbox"
"golang.org/x/crypto/scrypt"
)
const pemcosigneckey = `-----BEGIN ENCRYPTED SIGSTORE PRIVATE KEY-----
eyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjo2NTUzNiwiciI6
OCwicCI6MX0sInNhbHQiOiJxTzc1ak5RcXNRRm85Q1Q0V25rU2RmMmhXM3M2Z0h2
V21PYllKSVNKWjk0PSJ9LCJjaXBoZXIiOnsibmFtZSI6Im5hY2wvc2VjcmV0Ym94
Iiwibm9uY2UiOiJVUlB1UEx2bjU3VVN4MHhOSWM4MElOKzFFc00wMW45RCJ9LCJj
aXBoZXJ0ZXh0IjoiQm9pTW5PSy9jVloxbGo2aGFyQkVkS2oyVVI0d0dPOHIvaDhm
Y0V1OFZoY3lFK1JrQzA4UkVFekl6NkNVUFEycVlEb3JrZ1NDSHJiUW5DL2o4aVAw
VWZHcEJZdFZ4SCtUQU45N3k3cVVHTS9NcC8vNDJUZFNobW9ZZjVBZ291dDdpdkRq
UjlFOGNFdEV0b1h6YnRNVnVTditVa2J1Rlk0TSsvUHIvMHhhOU9VT2sxOWd5ZkNq
ZlhTWE1mZmc0VUpGUklpNUprTDBTM1pWbnc9PSJ9
-----END ENCRYPTED SIGSTORE PRIVATE KEY-----`
// https://github.com/sigstore/cosign/tree/8bce2dc8bb70efad54a9221612e2208ec615c6fc?tab=readme-ov-file#signature-specification
// {
// "kdf": {
// "name": "scrypt",
// "params": {
// "N": 65536,
// "r": 8,
// "p": 1
// },
// "salt": "qO75jNQqsQFo9CT4WnkSdf2hW3s6gHvWmObYJISJZ94="
// },
// "cipher": {
// "name": "nacl/secretbox",
// "nonce": "URPuPLvn57USx0xNIc80IN+1EsM01n9D"
// },
// "ciphertext": "BoiMnOK/cVZ1lj6harBEdKj2UR4wGO8r/h8fcEu8VhcyE+RkC08REEzIz6CUPQ2qYDorkgSCHrbQnC/j8iP0UfGpBYtVxH+TAN97y7qUGM/Mp//42TdShmoYf5Agout7ivDjR9E8cEtEtoXzbtMVuSv+UkbuFY4M+/Pr/0xa9OUOk19gyfCjfXSXMffg4UJFRIi5JkL0S3ZVnw=="
// }
// from https://github.com/smallstep/crypto/blob/master/pemutil/cosign.go#L13-L34
type cosignEnvelope struct {
KDF cosignKDF `json:"kdf"`
Cipher cosignCipher `json:"cipher"`
Ciphertext []byte `json:"ciphertext"`
}
type cosignKDF struct {
Name string `json:"name"`
Params cosignScryptParams `json:"params"`
Salt []byte `json:"salt"`
}
type cosignScryptParams struct {
N int `json:"N"`
R int `json:"r"`
P int `json:"p"`
}
type cosignCipher struct {
Name string `json:"name"`
Nonce []byte `json:"nonce"`
}
const pemcosignPublic = `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQjsgVTZCpLf+8QqKp6GQUc57jK9+
SaxC3gNrYu9Qk7tsBq4ohKzsqtphFlB94izxpnlbzhU6v1UtyGLj2Cc66w==
-----END PUBLIC KEY-----`
var (
// fsalt = flag.String("salt", "qO75jNQqsQFo9CT4WnkSdf2hW3s6gHvWmObYJISJZ94=", "salt, base64")
// fnonce = flag.String("nonce", "URPuPLvn57USx0xNIc80IN+1EsM01n9D", "nonce base64")
fpassword = flag.String("password", "", "privatekey password")
// fciphertext = flag.String("ciphertext", "BoiMnOK/cVZ1lj6harBEdKj2UR4wGO8r/h8fcEu8VhcyE+RkC08REEzIz6CUPQ2qYDorkgSCHrbQnC/j8iP0UfGpBYtVxH+TAN97y7qUGM/Mp//42TdShmoYf5Agout7ivDjR9E8cEtEtoXzbtMVuSv+UkbuFY4M+/Pr/0xa9OUOk19gyfCjfXSXMffg4UJFRIi5JkL0S3ZVnw==", "cipherText, base64")
)
func main() {
flag.Parse()
pblock, _ := pem.Decode([]byte(pemcosigneckey))
if pblock == nil {
log.Fatalf("failed to find any PEM data in input")
}
var prettyJSON bytes.Buffer
err := json.Indent(&prettyJSON, pblock.Bytes, "", " ")
if err != nil {
log.Fatalf("JSON indentation error: %s", err)
}
fmt.Println(prettyJSON.String())
var env cosignEnvelope
if err := json.Unmarshal(pblock.Bytes, &env); err != nil {
log.Fatalf("error unmarshaling key %v", err)
}
salt := env.KDF.Salt
ssb, err := scrypt.Key([]byte(*fpassword), salt, 65536, 8, 1, 32)
if err != nil {
log.Fatalf("error creating scryptkey %v", err)
}
var secretKey [32]byte
copy(secretKey[:], ssb)
var decryptNonce [24]byte
copy(decryptNonce[:], env.Cipher.Nonce)
encrypted := env.Ciphertext
decrypted, ok := secretbox.Open(nil, encrypted, &decryptNonce, &secretKey)
if !ok {
log.Fatalf("decryption error")
}
//fmt.Printf("%s", base64.StdEncoding.EncodeToString(decrypted))
blockPub, _ := pem.Decode([]byte(pemcosignPublic))
genericPublicKey, err := x509.ParsePKIXPublicKey(blockPub.Bytes)
publicKey := genericPublicKey.(*ecdsa.PublicKey)
fmt.Println("PublicKey: ")
fmt.Printf("Curve: %s\n", publicKey.Curve.Params().Name)
fmt.Printf("X: %x\n", publicKey.X.Bytes())
fmt.Printf("Y: %x\n", publicKey.Y.Bytes())
// bigIntValue := new(big.Int)
// bigIntValue.SetBytes(decrypted)
pkey, err := x509.ParsePKCS8PrivateKey(decrypted)
if err != nil {
log.Fatalf("error parsing private key %v", err)
}
privateKey := pkey.(*ecdsa.PrivateKey)
ppemBlock := &pem.Block{
Type: "EC PRIVATE KEY", // Common block type for EC private keys
Bytes: decrypted,
}
ppemBytes := pem.EncodeToMemory(ppemBlock)
fmt.Println(string(ppemBytes))
fmt.Printf("Public keys equal: %t\n", publicKey.Equal(&privateKey.PublicKey))
// now issue a test signature
msg := "This is a message to be signed and verified by ECDSA!"
hash := sha256.Sum256([]byte(msg))
signature, err := ecdsa.SignASN1(rand.Reader, privateKey, hash[:])
if err != nil {
log.Fatalf("error signing %v", err)
}
fmt.Printf("Signature (ASN.1 encoded): %x\n", signature)
isValid := ecdsa.VerifyASN1(publicKey, hash[:], signature)
fmt.Printf("Signature valid: %v\n", isValid)
}