Skip to content

Instantly share code, notes, and snippets.

@salrashid123
Last active March 12, 2026 11:02
Show Gist options
  • Select an option

  • Save salrashid123/7dccfcb96e57b83ba9a1c304f64c7799 to your computer and use it in GitHub Desktop.

Select an option

Save salrashid123/7dccfcb96e57b83ba9a1c304f64c7799 to your computer and use it in GitHub Desktop.
Decoding ENCRYPTED SIGSTORE PRIVATE KEY cosign key format

Decoding ENCRYPTED SIGSTORE PRIVATE KEY cosign key format

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: true

package 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)

}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment