How to Generate ECDSA Key Pair for SSH in Go? - go

I'm trying to generate ECDSA Key Pair for SSH with Go, but I find that the private key format is different from ssh-keygen and can't be accepted by GitHub.
Here's the 256-bit key pair generated via ssh-keygen -t ecdsa -b 256:
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOJWUhO+waiB+aKvXO0xC5XTL6P/X/TIzQ4hgdXkDfmAfntOj/HXRIu4GulCvJgUoyTiF5Qt9j9gK6Z17szUv3s= root#9e5eef4b58c5
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTiVlITvsGogfmir1ztMQuV0y+j/1/0
yM0OIYHV5A35gH57To/x10SLuBrpQryYFKMk4heULfY/YCumde7M1L97AAAAsDs42wc7ON
sHAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOJWUhO+waiB+aKv
XO0xC5XTL6P/X/TIzQ4hgdXkDfmAfntOj/HXRIu4GulCvJgUoyTiF5Qt9j9gK6Z17szUv3
sAAAAgOpAIXW6rZQqgYZboSJXojH2diS26wfm6P3hn8cQVZrwAAAARcm9vdEA5ZTVlZWY0
YjU4YzUBAgMEBQYH
-----END OPENSSH PRIVATE KEY-----
Here's the generator code in Go:
// GenerateECDSAKeys generates ECDSA public and private key pair with given size for SSH.
func GenerateECDSAKeys(bitSize int) (pubKey string, privKey string, err error) {
// generate private key
var privateKey *ecdsa.PrivateKey
if privateKey, err = ecdsa.GenerateKey(curveFromLength(bitSize), rand.Reader); err != nil {
return
}
// encode public key
var (
bytes []byte
publicKey ssh.PublicKey
)
if publicKey, err = ssh.NewPublicKey(privateKey.Public()); err != nil {
return
}
pubBytes := ssh.MarshalAuthorizedKey(publicKey)
// encode private key
if bytes, err = x509.MarshalECPrivateKey(privateKey); err != nil {
return
}
privBytes := pem.EncodeToMemory(&pem.Block{
Type: "ECDSA PRIVATE KEY",
Bytes: bytes,
})
return string(pubBytes), string(privBytes), nil
}
func curveFromLength(l int) elliptic.Curve {
switch l {
case 224:
return elliptic.P224()
case 256:
return elliptic.P256()
case 348:
return elliptic.P384()
case 521:
return elliptic.P521()
}
return elliptic.P384()
}
And generated result:
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNYTtNRlEKh/harLSfIsSziDkEQ8E7OJ7azhTBJi1Qx+fDa6dGg9f/vudGEizJ5d9TINVLTP+Jemwg6FBhajiVA=
-----BEGIN ECDSA PRIVATE KEY-----
MHcCAQEEIEGZZ/4aD6tf0sc1ovyctlGWRSFp7RGw5ovRONZKLg4eoAoGCCqGSM49
AwEHoUQDQgAE1hO01GUQqH+FqstJ8ixLOIOQRDwTs4ntrOFMEmLVDH58Nrp0aD1/
++50YSLMnl31Mg1UtM/4l6bCDoUGFqOJUA==
-----END ECDSA PRIVATE KEY-----
So why SSH private key was so different after the generation, and how to make it works?

OpenSSH uses different formats for private EC keys, the SEC1 (as generated by your Go code), the PKCS#8 or the newer OpenSSH format (as generated with the ssh-keygen command). This is described here, which also contains a more detailed explanation of the OpenSSH format. The SEC1 format is explained e.g. in this post.
The current Go code generates a SEC1 key with wrong header and footer. This turned out to be the cause of the problem! To fix the bug, ECDSA must be replaced by EC in header and footer:
-----BEGIN EC PRIVATE KEY-----
...
-----END EC PRIVATE KEY-----
i.e. in the Go code in the EncodeToMemory() call Type: "ECDSA PRIVATE KEY" must be replaced by Type: "EC PRIVATE KEY".
Note that a conversion between the formats is also possible e.g. with ssh-keygen. For instance
ssh-keygen -p -N "" -f data.key
converts the SEC1 key contained in data.key to the OpenSSH format, see here.

Related

Generate DSA Keys for OpenSSH in Golang

I read through a few examples to generate DSA keys for OpenSSH in Go. And my clean code snippet and outputs are listed below.
It has two problems:
for 2048-bit length, the public key can't be loaded via ssh.ParseAuthorizedKey, for error: "ssh: no key found".
OpenSSH client and GitHub SSH can't accept it.
Code snippets:
// GenerateDSAKeys generates DSA public and private key pair with given size for SSH.
func GenerateDSAKeys(bitSize int, passphrase string) (pubKey string, privKey string, err error) {
params := new(dsa.Parameters)
// see http://golang.org/pkg/crypto/dsa/#ParameterSizes
if err = dsa.GenerateParameters(params, rand.Reader, dsaSizeFromLength(bitSize)); err != nil {
return
}
var privateKey dsa.PrivateKey
privateKey.PublicKey.Parameters = *params
// this generates a public & private key pair
if err = dsa.GenerateKey(&privateKey, rand.Reader); err != nil {
return
}
// generate public key
var publicKey ssh.PublicKey
if publicKey, err = ssh.NewPublicKey(&privateKey.PublicKey); err != nil {
return
}
// encode public key
pubBytes := ssh.MarshalAuthorizedKey(publicKey)
// encode private key
var (
bytes []byte
privBytes []byte
)
if bytes, err = asn1.Marshal(privateKey); err != nil {
return
}
privBytes, err = encodePEMBlock(&pem.Block{
Type: "DSA PRIVATE KEY",
Bytes: bytes,
}, passphrase)
if err != nil {
return
}
return string(pubBytes), string(privBytes), nil
}
func dsaSizeFromLength(l int) dsa.ParameterSizes {
switch l {
case 1024:
return dsa.L1024N160
case 2048:
return dsa.L2048N224
case 3072:
return dsa.L3072N256
default:
return dsa.L2048N256
}
}
Output for 1024:
bash-3.2$ cat id_dsa.pub
ssh-dss AAAAB3NzaC1kc3MAAACBAIbuW6wh5hU2W96tEyo7xPDZmslWnsyQBYtf4SSTeHOMTNTxznlMujjkmCuqKJ04BlHFi+ner2qzCd1GkzGhHrretQw1z5Ew8ysAGsmbb9Yc6BMTyhJkrQ2lIR5Vmqa9Ukx0PM/HdXa6GieYZWxyabN5IjN4SESXZ6G7Jb4StwCfAAAAFQCnj+WurTgW5aXGYePwhBYAWX01WwAAAIBHQpZSsJGKsEII7Oe6RMz5ek27ydHPnrLDqVOmEKqHrIrsYXoTHaMOLW+fvsDBC3q0EWMBNgu4IAZe3eL2Gx2r94+DS+GTfECWiJ3+O76DTAwDcB6fXxdYxG88nJMzCkcMZEmOjbIpuiGP5NC+OOqBv2DEHw7YEWs8Kx4T71mE0AAAAIEAhg/OB98FTcYX/gXEclKqqDByHzHIt71Y7DFZnxnmd4DFEZp/WzJ6VT2jTNMyWKRT9h0SITORLKNxTCM3ZLhQYVBinOsjIzZ8YlYYOxTn2mWntWzmsdhUeBx+aNCwuhz/cMHjbhWJWVXRDfgzPf9IHtF1FLgjtMiz6/xwzAMEPlE= vej#Vej-Work-MBP.local
bash-3.2$ cat id_dsa
-----BEGIN DSA PRIVATE KEY-----
MIIBwDCCAaYwggEeAoGBAIbuW6wh5hU2W96tEyo7xPDZmslWnsyQBYtf4SSTeHOM
TNTxznlMujjkmCuqKJ04BlHFi+ner2qzCd1GkzGhHrretQw1z5Ew8ysAGsmbb9Yc
6BMTyhJkrQ2lIR5Vmqa9Ukx0PM/HdXa6GieYZWxyabN5IjN4SESXZ6G7Jb4StwCf
AhUAp4/lrq04FuWlxmHj8IQWAFl9NVsCgYBHQpZSsJGKsEII7Oe6RMz5ek27ydHP
nrLDqVOmEKqHrIrsYXoTHaMOLW+fvsDBC3q0EWMBNgu4IAZe3eL2Gx2r94+DS+GT
fECWiJ3+O76DTAwDcB6fXxdYxG88nJMzCkcMZEmOjbIpuiGP5NC+OOqBv2DEHw7Y
EWs8Kx4T71mE0AKBgQCGD84H3wVNxhf+BcRyUqqoMHIfMci3vVjsMVmfGeZ3gMUR
mn9bMnpVPaNM0zJYpFP2HRIhM5Eso3FMIzdkuFBhUGKc6yMjNnxiVhg7FOfaZae1
bOax2FR4HH5o0LC6HP9wweNuFYlZVdEN+DM9/0ge0XUUuCO0yLPr/HDMAwQ+UQIU
RhBIeYLqxL4PJgENdgtjfjxDX80=
-----END DSA PRIVATE KEY-----
For 2048, output:
bash-3.2$ cat id_dsa.pub
ssh-dss AAAAB3NzaC1kc3MAAAEBAKbfrtje1KqerXL0DFg35Ouou2NP08vsuqCbv/cr65X2/AMaDy/Zdikq1rHw1ScWzre0vGTDwnGsFJgNDf3p0ckJqxMN9kop+8a+M1nuQ39LnkHATM+x58jgJaC06VZisLQuMoJvzdOlMPKb1v9TKfSiI0XZujhS5RVl4DkqABEXFsNXOHTIGDXToq80IPf0KV01qvOGBnICzhPkXw5HcCF9rmVD5aPfADjHZfUTt9PJfFcPk06mmfvpOEBfWgaluIDp0Wf5DsKu0RxlZVm4x3iP43hQfJ8NaFRyOKhNxd0r5t5SDUubF2Z37v0QNIvLZPrKsE0AywNkDZ66bf3HigMAAAAdAMjEhWBLtQ+nWfJIO16rpLQZQKBpXePefLrztpUAAAEALJsfHywD5PSfeFUGs901I1Z/yvOuyHQFxJGXEAQJ08CBAGvwcGA1M41sDnbrbOFm8ol91xcnUqW0HMlwDpdHIBxgytlnKlsEw69GqCx1dJAv8LnDokK/zV406I0LLwXzQ3QvfSMtM3VDsIA/jInd273LlXFEG4dmkG1mIP7SBgbzy7jZ4LpH5y8ZSUMFlZ4dXTURj4TAe/ByScaXoVO8QDLaZq5EiSRAomUxLvnwTNJHt/YqQog5EWhQNBUKp5HbPS7pk+KujaUpYwXNZZuhqjp4dmaBYppwCZnrqvsHKq6p8BCt4ZQ/589q0D1Mx0pbgI/sQLvib5jSHJ0jKq7xrAAAAQBzxG2gTr89VeVJBMsconclvXw7vYDxQGBGhZBmKQ6e/s8swxJzzUbpRzoeYGEL1nE28e4Apw6pQFY3XkuvklYTwNHPLwG/5FJV7fc2HJgwVg8/wf5hUrzqlKK9Xhjm2369iKnGig/u28e79oOWgdbqfrjWpNih/aVL60ApdWgxmxC61PGppJ2AXNubaDynhMOx1q+lSH+unu+kLml+c+lbqwZYXmI0t+gFzyyu+pL8DpVEhAG8P/AMCXMDR3JmQhWF7fKiP1QdDMidUODM8keVQaK5txIp9EUAThk0ErigG5ZsIL5V2Z4UistlwQ4WiZYJmz/IlD50+PtkjwBFiA6z vej#Vej-Work-MBP.local
bash-3.2$ cat id_dsa
-----BEGIN DSA PRIVATE KEY-----
MIIDUzCCAzAwggIoAoIBAQCm367Y3tSqnq1y9AxYN+TrqLtjT9PL7Lqgm7/3K+uV
9vwDGg8v2XYpKtax8NUnFs63tLxkw8JxrBSYDQ396dHJCasTDfZKKfvGvjNZ7kN/
S55BwEzPsefI4CWgtOlWYrC0LjKCb83TpTDym9b/Uyn0oiNF2bo4UuUVZeA5KgAR
FxbDVzh0yBg106KvNCD39CldNarzhgZyAs4T5F8OR3Ahfa5lQ+Wj3wA4x2X1E7fT
yXxXD5NOppn76ThAX1oGpbiA6dFn+Q7CrtEcZWVZuMd4j+N4UHyfDWhUcjioTcXd
K+beUg1Lmxdmd+79EDSLy2T6yrBNAMsDZA2eum39x4oDAh0AyMSFYEu1D6dZ8kg7
XquktBlAoGld4958uvO2lQKCAQAsmx8fLAPk9J94VQaz3TUjVn/K867IdAXEkZcQ
BAnTwIEAa/BwYDUzjWwOduts4WbyiX3XFydSpbQcyXAOl0cgHGDK2WcqWwTDr0ao
LHV0kC/wucOiQr/NXjTojQsvBfNDdC99Iy0zdUOwgD+Mid3bvcuVcUQbh2aQbWYg
/tIGBvPLuNngukfnLxlJQwWVnh1dNRGPhMB78HJJxpehU7xAMtpmrkSJJECiZTEu
+fBM0ke39ipCiDkRaFA0FQqnkds9LumT4q6NpSljBc1lm6GqOnh2ZoFimnAJmeuq
+wcqrqnwEK3hlD/nz2rQPUzHSluAj+xAu+JvmNIcnSMqrvGsAoIBAHPEbaBOvz1V
5UkEyxyidyW9fDu9gPFAYEaFkGYpDp7+zyzDEnPNRulHOh5gYQvWcTbx7gCnDqlA
VjdeS6+SVhPA0c8vAb/kUlXt9zYcmDBWDz/B/mFSvOqUor1eGObbfr2IqcaKD+7b
x7v2g5aB1up+uNak2KH9pUvrQCl1aDGbELrU8amknYBc25toPKeEw7HWr6VIf66e
76QuaX5z6VurBlheYjS36AXPLK76kvwOlUSEAbw/8AwJcwNHcmZCFYXt8qI/VB0M
yJ1Q4MzyR5VBorm3Ein0RQBOGTQSuKAblmwgvlXZnhSKy2XBDhaJlgmbP8iUPnT4
+2SPAEWIDrMCHQDGpe828eiBg56q0tQup2r3UpgiXevRNEuF0Gbw
-----END DSA PRIVATE KEY-----
Can you please tell me how resolve it, and make it works?
OpenSSH stopped supporting DSA (aka ssh-dss) by default over 5 years ago; see
https://security.stackexchange.com/questions/112802/why-openssh-deprecated-dsa-keys
https://security.stackexchange.com/questions/146379/does-ssh-support-dsa-with-2048-bit-keys
https://superuser.com/questions/1016989/ssh-dsa-keys-no-longer-work-
https://unix.stackexchange.com/questions/247612/ssh-keeps-skipping-my-pubkey-
You can reenable it on your client following instructions on Qs like those or the openssh website or documentation, but github won't accept it so you can't make that work. (You could set up your own server, and use it there.)
I don't know why some go code (library?) doesn't accept the 2048-bit publickey -- if you give a reference I could try to loook -- but (both) your privatekey files are incorrect, I'm guessing due to the structuring used in crypto/dsa shown at your link. The key is being marshalled (serialized) to ASN.1 as nested sequences, namely SEQUENCE { pub = SEQUENCE { params = SEQUENCE {p,q,g}, y }, x } which conceptually is a reasonable structure, but the PEM (or pseudo-PEM) type DSA PRIVATE KEY is de-facto defined by SSLeay-now-OpenSSL as using a single level: SEQUENCE { p,q,g, y, x } .

invalid argument: no armored data found

When I try to load an armored GPG public key to verify a signature, I get the error openpgp: invalid argument: no armored data found
My code (some data shortened to fit better):
pubKey := `-----BEGIN PGP PUBLIC KEY BLOCK-----
xsFNBF/9Xn [...] =Yo8+
-----END PGP PUBLIC KEY BLOCK-----`
content := "Hello World"
signature := `-----BEGIN PGP SIGNATURE-----
wsFcBAE [...] =z3nL
-----END PGP SIGNATURE-----`
keyring, err := openpgp.ReadArmoredKeyRing(strings.NewReader(pubKey))
if err != nil {
// Errors out here with: openpgp: invalid argument: no armored data found
// ...
}
// Code never gets this far but I'm including this in case I'm using it all wrong...
_, err = openpgp.CheckArmoredDetachedSignature(keyring, strings.NewReader(content), strings.NewReader(signature))
if err != nil {
return false, err
}
Entire public key, entire signature.
edit: i think its something to do with your public key armor not being valid. below is a link to a working function with an example const e2ePublicKey public key.
instead of using strings.NewReader(pubKey), they use:
keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(pubKey))
maybe another bytes.NewBufferString for the signature.
(from src)

Encode Private Key getting Error: asn1: structure error: tags don't match

When i try to parses the encode private key with
sample private key
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAQEA4if4vmEnNh2Ijlfrhsb02Exh+LXjkYySOiILtj8rg1ZGWFz1vtPe
DiKbbWLo9xcjDp7UQ2gHnhUZno/gFxcokzTYTkexpb/s4mzU4CH0XaS7IV/xRz1Of1+dwC
2MvsclD0NKceyNu0glocGUu6w2MMsWdevr8YqjPABZYwPmANg5wns61FoI5uQi4e6pcNkr
gGnbf1Sh8DChuM22aLksmOW9UapEKovaUxA4DxEd58zJpmg7UN1ZduUrwCVz1tg1BF+EW5
knMd037olDWdgZtEzMxbmSRlqF6t5dcybnp7LQsdPrbXDubY3mjqgCg25xMk4of3mdDc5b
VcRuNSbDmwAAA+AnwUz5J8FM+QAAAAdzc2gtcnNhAAABAQDiJ/i+YSc2HYiOV+uGxvTYTG
H4teORjJI6Igu2PyuDVkZYXPW+094OIpttYuj3FyMOntRDaAeeFRmej+AXFyiTNNhOR7Gl
v+zibNTgIfRdpLshX/FHPU5/X53ALYy+xyUPQ0px7I27SCWhwZS7rDYwyxZ16+vxiqM8AF
ljA+YA2DnCezrUWgjm5CLh7qlw2SuAadt/VKHwMKG4zbZouSyY5b1RqkQqi9pTEDgPER3n
zMmmaDtQ3Vl25SvAJXPW2DUEX4RbmScx3TfuiUNZ2Bm0TMzFuZJGWoXq3l1zJuenstCx0+
ttcO5tjeaOqAKDbnEyTih/eZ0NzltVxG41JsObAAAAAwEAAQAAAQBUyVuONGo49ZWOmBOq
8cg1l11bmwV4OdVQihcN+lzb3mp9EkzngBLOBddziROCH2B7SLyXkNbaQ1rZgWMoBPynQ7
acknBdjbjHormkVdaBjRLDDm8soCVfx38i33DWzV5tfHLahy8TuZayMBsMySF/5YPELfDF
G47bHd5lKr7+LV3T4kvZ1g1UpDgUGlwpVMpu+ybfhMhCOO2w5Vz/Fl7ptYJQnx8rDARgYu
GDf1yKpRCt7Rx4U+lla5HMnoxh4/g5dXDb8vBDfC/QXj+DPY2/Ju5c3zifryfkB2Cvppq2
EULxDO41iwXgzRpmv9hv6adSp2Qqob72XDu7mWdz/u9BAAAAgFDu2TKaU71igLIMd4sheb
wzjsB2ZW8x5CO+N95OKddkC6lkJiBFrAiF98SVs0AFbqDlw46V3xrBqCVL6ByfW4Zro3Qw
C9GRhjfW/koyuJbplf0uiNaa1ApM7nRoRiOcE5kXkLOObxojPuur29rbI1JGozSn6YhxwA
Q3WthgQipmAAAAgQD7RXYeHQ1P0gpdpWfMXspIbkzODWQDH3VkvQHFFl87+QpsFIWGd8zX
jMMo2bELCgr9cnzRffd8UUCzWJy/mfj+PWjsCr9EaojlnDWYEComa5PYkJKKOxmN+rLg7P
F3Xd/KV4XVBP5wqobTU1sxLnhJkVJMCqHOdDzv9mYr75sXqwAAAIEA5mmDj/4mvkNTNZKw
aaD/8sOz7JjD90jqQCchLETVcwJ1sCgPl5qVAa/S99g9QJXuW3TlXbj4jw01s5APpKq6eY
H91+vJcS8ZmzARXMt4jVB3oWsrhFXw5BEaKYjyKx5gYdSGETbcGz1WxQF4i5E/A43ow73n
RftprflPg+CUU9EAAAAkc3VtaXR0aGFrdXJAU3VtaXRzLU1hY0Jvb2stQWlyLmxvY2FsAQ
IDBAUGBw==
-----END OPENSSH PRIVATE KEY-----
x509.ParsePKCS1PrivateKey(block.Bytes)
it will giving me error
Explain:
case "OPENSSH PRIVATE KEY":
log.Println("Here at OPENSSH Private Key:")
rsa, err := x509.ParsePKCS1PrivateKey(block.Bytes)
log.Println("Rsa and Error:", rsa, err)
if err != nil {
return nil, err
}
rawkey = rsa
key
-----BEGIN OPENSSH PRIVATE KEY-----
key
-----END OPENSSH PRIVATE KEY-----
Getting Error:
asn1: structure error: tags don't match (16 vs {class:1 tag:15 length:112 isCompound:true}) {optional:false explicit:false application:false private:false defaultValue:<nil> tag:<nil> stringType:0 timeType:0 set:false omitEmpty:false} pkcs1PrivateKey #2
2019/04/02 13:57:52 Signer: <nil>
and I will also try with
x509.ParsePKCS8PrivateKey(block.Bytes)
But same Error getting.
The problem is the key type. OPENSSH PRIVATE KEY should be parsed with ssh.ParseRawPrivateKey, whereas RSA PRIVATE KEY can be parsed with both ssh.ParseRawPrivateKey and x509.ParsePKCS1PrivateKey.
You can generate RSA PRIVATE KEY with e.g. ssh-keygen -t rsa -f key.pem -m pem (-m pem here is important) or openssl genrsa -out key.pem, and test it with openssl rsa -check -in key.pem.
So just do a block type check and use the corresponding functions in the case clauses to parse the key.
Also think about key encryption, which means you might need to use ssh.ParseRawPrivateKeyWithPassphrase or x509.IsEncryptedPEMBlock and x509.DecryptPEMBlock functions too.
I post the test private key and the code which I used
Sample private key:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAQEA4if4vmEnNh2Ijlfrhsb02Exh+LXjkYySOiILtj8rg1ZGWFz1vtPe
DiKbbWLo9xcjDp7UQ2gHnhUZno/gFxcokzTYTkexpb/s4mzU4CH0XaS7IV/xRz1Of1+dwC
2MvsclD0NKceyNu0glocGUu6w2MMsWdevr8YqjPABZYwPmANg5wns61FoI5uQi4e6pcNkr
gGnbf1Sh8DChuM22aLksmOW9UapEKovaUxA4DxEd58zJpmg7UN1ZduUrwCVz1tg1BF+EW5
knMd037olDWdgZtEzMxbmSRlqF6t5dcybnp7LQsdPrbXDubY3mjqgCg25xMk4of3mdDc5b
VcRuNSbDmwAAA+AnwUz5J8FM+QAAAAdzc2gtcnNhAAABAQDiJ/i+YSc2HYiOV+uGxvTYTG
H4teORjJI6Igu2PyuDVkZYXPW+094OIpttYuj3FyMOntRDaAeeFRmej+AXFyiTNNhOR7Gl
v+zibNTgIfRdpLshX/FHPU5/X53ALYy+xyUPQ0px7I27SCWhwZS7rDYwyxZ16+vxiqM8AF
ljA+YA2DnCezrUWgjm5CLh7qlw2SuAadt/VKHwMKG4zbZouSyY5b1RqkQqi9pTEDgPER3n
zMmmaDtQ3Vl25SvAJXPW2DUEX4RbmScx3TfuiUNZ2Bm0TMzFuZJGWoXq3l1zJuenstCx0+
ttcO5tjeaOqAKDbnEyTih/eZ0NzltVxG41JsObAAAAAwEAAQAAAQBUyVuONGo49ZWOmBOq
8cg1l11bmwV4OdVQihcN+lzb3mp9EkzngBLOBddziROCH2B7SLyXkNbaQ1rZgWMoBPynQ7
acknBdjbjHormkVdaBjRLDDm8soCVfx38i33DWzV5tfHLahy8TuZayMBsMySF/5YPELfDF
G47bHd5lKr7+LV3T4kvZ1g1UpDgUGlwpVMpu+ybfhMhCOO2w5Vz/Fl7ptYJQnx8rDARgYu
GDf1yKpRCt7Rx4U+lla5HMnoxh4/g5dXDb8vBDfC/QXj+DPY2/Ju5c3zifryfkB2Cvppq2
EULxDO41iwXgzRpmv9hv6adSp2Qqob72XDu7mWdz/u9BAAAAgFDu2TKaU71igLIMd4sheb
wzjsB2ZW8x5CO+N95OKddkC6lkJiBFrAiF98SVs0AFbqDlw46V3xrBqCVL6ByfW4Zro3Qw
C9GRhjfW/koyuJbplf0uiNaa1ApM7nRoRiOcE5kXkLOObxojPuur29rbI1JGozSn6YhxwA
Q3WthgQipmAAAAgQD7RXYeHQ1P0gpdpWfMXspIbkzODWQDH3VkvQHFFl87+QpsFIWGd8zX
jMMo2bELCgr9cnzRffd8UUCzWJy/mfj+PWjsCr9EaojlnDWYEComa5PYkJKKOxmN+rLg7P
F3Xd/KV4XVBP5wqobTU1sxLnhJkVJMCqHOdDzv9mYr75sXqwAAAIEA5mmDj/4mvkNTNZKw
aaD/8sOz7JjD90jqQCchLETVcwJ1sCgPl5qVAa/S99g9QJXuW3TlXbj4jw01s5APpKq6eY
H91+vJcS8ZmzARXMt4jVB3oWsrhFXw5BEaKYjyKx5gYdSGETbcGz1WxQF4i5E/A43ow73n
RftprflPg+CUU9EAAAAkc3VtaXR0aGFrdXJAU3VtaXRzLU1hY0Jvb2stQWlyLmxvY2FsAQ
IDBAUGBw==
-----END OPENSSH PRIVATE KEY-----
Signed the constructed json string with business private key
func SignatureWithPrivateKey(data string) string {
signer, err := loadPrivateKey("/Users/sumitthakur/test")
log.Println("Signer:", signer)
if err != nil {
fmt.Errorf("signer is damaged: %v", err)
}
toSign := data
signed, err := signer.Sign([]byte(toSign))
if err != nil {
fmt.Errorf("could not sign request: %v", err)
}
return base64.StdEncoding.EncodeToString(signed)
}
loadPrivateKey loads an parses a PEM encoded private key file.
func loadPrivateKey(path string) (Signer, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
log.Println("Data and Error pem:", data, err)
return parsePrivateKey(data)
}
parses an encoded private key.
func parsePrivateKey(pemBytes []byte) (Signer, error) {
block, err := pem.Decode(pemBytes)
if block == nil {
return nil, errors.New("ssh: no key found")
}
log.Println("Block and Error: ", block, err)
var rawkey interface{}
switch block.Type {
case "OPENSSH PRIVATE KEY":
log.Println("Here at OPENSSH Private Key:")
rsa, err := ssh.ParseRawPrivateKey(block.Bytes)
log.Println("Rsa and Error:", rsa, err)
if err != nil {
return nil, err
}
rawkey = rsa
default:
log.Println("Here at default")
return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
}
return newSignerFromKey(rawkey)
}

ParsePrivateKeyWithPassphrase returns ssh: cannot decode encrypted private keys

here is my code snippet:
user, err := user.Current()
key, err := ioutil.ReadFile(fmt.Sprintf("%s/.ssh/id_rsa", user.HomeDir))
fmt.Println(string(key)) // prints valid data
signer, err := ssh.ParsePrivateKeyWithPassphrase(key, []byte("test"))
if err != nil {
// error happens here
log.Fatalf("unable to parse private key: %v", err)
}
ouput:
unable to parse private key: ssh: cannot decode encrypted private keys
and here is my id_rsa file:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABD5f5tjBE
IeNkF+DmGNAQLaAAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQDSHOjIEPNh
9Qf0l7ILzAY5csC5fBrcykj8K49N6OLIofClwVxeeT9ucJAYz9um3QSnYBstxcozN+EG30
7b7gPCGEDLZbB2bOeyU1Wda8wBm6Jy3V1xw6XDvdC4ZZJeGEjBKeY/5l/scAurfcjNo6rG
dFNMyY8RAQb5XZEzvhzDJGebYH3ezMTf9zb2RXP8anud/qdAJMvm8uICSAg4gzI0C+fC8+
t7SeE6BWLHUNKyBLXB2/b74oXJCIgYou1pBd2xol/lSM9rqSNanzn7yhj4s1+BTFlJaijH
+xVxac3sbK9AfCPoq3zQA1W1QZQDghMMSd0OuQg6TR3w4X8rq3UBAAAD0FsXxxJuKOB9Pb
zNrZ69tHKBsTirWNkLq/0MfNJlqNCRYArsq0PH2IWiioKp2mQgRwXwIfrM71LnpemXmS/F
rtjJAabNifGfCT6v7BGM1OubFh+n3Y8ejSK8rPLh25m/KFwWABEwFkoXpSiY2e07Y8cf5i
BmnMpSDlmgkWUipRlDZq1NvXYovAlFzlzmbAlC2utqjiA+D2V/Pc+rI0E/t/iS2LuW4Y5q
7OfWxPynbQuKkt16cXVK1oXUOa7KJoy8+v7MJQRHP6Ipurrfn23DXyM+xXmMRBy9Ai+JI8
ffFh8DzCjL+AM88eHF13fwLMa1IXfvbJKsHk/SsoLq62EDinfvpTEUa/FmQLsiXpYKKm+r
kTvvTmcCTch0C24Haa5UxKrqD7F7V9i3nLYP7ot9gOJ2XkLWczYvnZJRlIEFuNiObxKuTe
3aUxWSQloVq8LwQR/N5fACH4nZmafk0JsXNq6ImBRwP0a7AxTZ6F9pAt57XjTYNAER6SBv
oHNxMnwxt31/kV+7SYs1OgburqBOYBDgtdjT4n2VlBtHjmiflxeychlr4G7zvR9hhK+fZl
AoskIJNYqrHgBimlTYwzvy+fJr2DbTZFkuyQyhzFBAtNnV04YWufAnPl/r7fB4GrNdqksi
pxAHUWpJLY47q0GIAMwdMt8lEBcQ1okg+9PLOsXOZCjkOx1/dcaRmNKC9TEU/0tvgIDybL
HVL15S/cZz19wNAt1Qvvx8LjNyq6xm0hbeRUldm8r0BQanK6Y6ReImnjwm9pojd7N/nPMt
E/zf0whJgzVikqt95SbCkyaW9wkMOayjxrm6b6hhNthldAgcz/vGQKNd8gyvUmgauHHrMI
NgbQL1N6dBY5rNF+SGPelEDNQu8n1l0sq0ln7BA3RiXVMff/FxgvV2b0DSTa4d7MfLm7Xi
S/2Cn1Tzwi+90m62zU38KbQJLAhXrB0KumFcOM3Tmp2V+kdqu2E0F2AOTs1uzTOzBALXSd
fThlLXxVS5VVrAbQajneVWRg741iHqFR+9tDRlOunjPfJ2v2PGqDyVEIVFsJ4d+mhzCM3z
Z2KNv1gjiOn9bgyfKldE8xA2ee+sax6HIUSa2u54LpWAhgGtJjAaYA9tWabjdTaKIpiFo6
DSIa39Kx7hkEjLstCN+OCzSGqiVw8RUsLcOMJi6gBzMTalgp8KeMkXwT2GUOvfFC1aHecJ
F2vApS+VW331FWYxNYPCAKbJx8iaKUZ7Ca6whPqwyB7lvdtjmi+3vREu3m4yROwDkknivc
SF7LrsG2766/Z09Cr+V7fT4yDP3EE=
-----END OPENSSH PRIVATE KEY-----
Passphrase for key is test and I can verify it with ssh-keygen -y

How to create PKCS#8 Private Key using Go [duplicate]

This question already has answers here:
golang - marshal PKCS8 private key?
(2 answers)
Closed 5 years ago.
I want to generate tls certificates.
So first I need a Private Key.
-----BEGIN PRIVATE KEY-----
BASE64 ENCODED DATA
-----END PRIVATE KEY-----
But, I can generate RSA Private Key
// "crypto/rsa"
rsa.GenerateKey(cryptorand.Reader, 2048)
which gives me following
-----BEGIN RSA PRIVATE KEY-----
BASE64 ENCODED DATA
-----END RSA PRIVATE KEY-----
And I can't use it. I need PKCS#8 Private Key start with BEGIN PRIVATE KEY
How can I generate PKCS#8 Private Key?
Or Is there any way to convert PKCS#1 to PKCS#8 Key?
I don't know how exactly you get literal -----BEGIN RSA PRIVATE KEY-----
Go stdlib crypto do not has PKCS#8 marshaller but there is generic asn1.Marchal() in encoding/asn1 and PKCS#8 standard(rfc5208) provide ASN#1 syntax definition, so you can do something like:
import (
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
)
type Pkcs8Key struct {
Version int
PrivateKeyAlgorithm []asn1.ObjectIdentifier
PrivateKey []byte
}
func RsaToPkcs8(key *rsa.PrivateKey) ([]byte, error) {
var pkey Pkcs8Key
pkey.Version = 0
pkey.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 1)
pkey.PrivateKeyAlgorithm[0] = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
pkey.PrivateKey = x509.MarshalPKCS1PrivateKey(key)
return asn1.Marshal(pkey)
}
Here's a solution based on the custom PKCS#8 marshal function in this answer:
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"fmt"
)
type PKCS8Key struct {
Version int
PrivateKeyAlgorithm []asn1.ObjectIdentifier
PrivateKey []byte
}
func MarshalPKCS8PrivateKey(key *rsa.PrivateKey) ([]byte, error) {
var pkey PKCS8Key
pkey.Version = 0
pkey.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 1)
pkey.PrivateKeyAlgorithm[0] = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
pkey.PrivateKey = x509.MarshalPKCS1PrivateKey(key)
return asn1.Marshal(pkey)
}
func main() {
// Generate the private key.
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
fatal(err)
// Encode the private key into PEM data.
bytes, err := MarshalPKCS8PrivateKey(privateKey)
fatal(err)
privatePem := pem.EncodeToMemory(
&pem.Block{
Type: "PRIVATE KEY",
Bytes: bytes,
},
)
fmt.Printf("%s\n", privatePem)
// -----BEGIN PRIVATE KEY-----
// MIIEvAIBADALBgkqhkiG9w0BAQEEggSoMIIEpAIBAAKCAQEAz5xD5cdqdE0PMmk1
// 4YN6Tj0ybTsvS5C95ogQmBJ4bGxiuGPR5JtIc+UmT8bnCHtK5xnHiP+gPWunwmhS
// ...
// qpb1NZsMLz2lRXqx+3Pq7Q==
// -----END PRIVATE KEY-----
}
func fatal(err error) {
if err != nil {
panic(err)
}
}

Resources