{"record":{"id":"889e358f3de2a2ee","repo":"OpenNHP/opennhp","slug":"decode-private-key-w","errorCode":null,"errorMessage":"decode private key: %w","messagePattern":"decode private key: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"endpoints/server/main/main.go","lineNumber":131,"sourceCode":"\t\tName:  \"pubkey\",\n\t\tUsage: \"derive public key(s) from an existing base64 private key\",\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.BoolFlag{Name: \"curve\", Value: false, DisableDefaultText: true, Usage: \"output curve25519 public key\"},\n\t\t\t&cli.BoolFlag{Name: \"sm2\", Value: false, DisableDefaultText: true, Usage: \"output sm2 public key (default)\"},\n\t\t\t&cli.BoolFlag{Name: \"both\", Value: false, DisableDefaultText: true, Usage: \"output both SM2 and Curve25519 public keys\"},\n\t\t\t&cli.BoolFlag{Name: \"json\", Value: false, DisableDefaultText: true, Usage: \"output in JSON format\"},\n\t\t},\n\t\tAction: func(c *cli.Context) error {\n\t\t\temitErr := func(err error) error {\n\t\t\t\tif c.Bool(\"json\") {\n\t\t\t\t\tjson.NewEncoder(os.Stdout).Encode(map[string]string{\"error\": err.Error()})\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tprivBytes, err := base64.StdEncoding.DecodeString(c.Args().First())\n\t\t\tif err != nil {\n\t\t\t\treturn emitErr(fmt.Errorf(\"decode private key: %w\", err))\n\t\t\t}\n\n\t\t\tif c.Bool(\"both\") {\n\t\t\t\tsm2 := core.ECDHFromKey(core.ECC_SM2, privBytes)\n\t\t\t\tcurve := core.ECDHFromKey(core.ECC_CURVE25519, privBytes)\n\t\t\t\tif sm2 == nil || curve == nil {\n\t\t\t\t\treturn emitErr(fmt.Errorf(\"invalid input key\"))\n\t\t\t\t}\n\t\t\t\tif c.Bool(\"json\") {\n\t\t\t\t\tjson.NewEncoder(os.Stdout).Encode(map[string]string{\n\t\t\t\t\t\t\"sm2PublicKey\":        sm2.PublicKeyBase64(),\n\t\t\t\t\t\t\"curve25519PublicKey\": curve.PublicKeyBase64(),\n\t\t\t\t\t})\n\t\t\t\t} else {\n\t\t\t\t\tfmt.Println(\"SM2 public key:       \", sm2.PublicKeyBase64())\n\t\t\t\t\tfmt.Println(\"Curve25519 public key:\", curve.PublicKeyBase64())\n\t\t\t\t}\n\t\t\t\treturn nil","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/server/main/main.go#L113-L149","documentation":"The `pubkey` subcommand of nhp-serverd decodes its first CLI argument as a base64 (std encoding) private key before deriving public keys. This error is wrapped when base64.StdEncoding.DecodeString fails — the argument is empty, contains non-base64 characters, or uses URL-safe/-padded variants that std decoding rejects.","triggerScenarios":"Running `nhp-serverd pubkey` (or `pubkey --both`) with: no argument at all, a hex-encoded key, a URL-safe base64 string (with - and _), a key with whitespace/newlines or quotes copied from a terminal, or a truncated base64 string.","commonSituations":"Pasting a private key from Secrets Manager JSON with surrounding quotes; scripts passing unquoted values with shell mangling; mixing up std vs URL-safe base64 encodings; using the output of a different tool that emits hex.","solutions":["Pass the exact std-base64 private key as a single quoted argument: nhp-serverd pubkey 'BASE64KEY'.","Confirm the key is base64, not hex (32 bytes -> 44 std-base64 chars ending in '='); convert with `printf <hex> | xxd -r -p | base64` if needed.","Strip quotes, whitespace, and newlines from the value before passing it.","For URL-safe base64 input, convert padding/alphabet: tr '_-' '/+' first.","If the key came from opennhp/demo, use the raw nhp_*_private_key field value verbatim."],"exampleFix":"// before (script)\nnhp-serverd pubkey $NHP_SERVER_PRIVATE_KEY   # unquoted, may break\n// after\nnhp-serverd pubkey \"$NHP_SERVER_PRIVATE_KEY\" # quoted single std-base64 argument","handlingStrategy":"validation","validationCode":"key := c.Args().First()\nif key == \"\" { return errors.New(\"missing private key argument\") }\nif _, err := base64.StdEncoding.DecodeString(key); err != nil {\n    return fmt.Errorf(\"private key must be std base64: %w\", err)\n}","typeGuard":"func isStdBase64(s string) bool {\n    _, err := base64.StdEncoding.DecodeString(s)\n    return err == nil && len(s) >= 43\n}","tryCatchPattern":"if err := app.Run(os.Args); err != nil {\n    if strings.Contains(err.Error(), \"decode private key\") {\n        fmt.Fprintln(os.Stderr, \"pass the private key as std base64, quoted: nhp-serverd pubkey '<key>'\")\n        os.Exit(1)\n    }\n    panic(err)\n}","preventionTips":["Always quote the key argument in shell scripts","Verify the key is 44-char std base64 (32-byte key) before invoking","Convert hex or URL-safe encodings before passing","Never copy keys with trailing newlines or surrounding quotes from JSON/secret stores"],"tags":["go","cli","base64","keys"],"backgroundTag":"invalid-argument-format","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}