Skip to content

Instantly share code, notes, and snippets.

@amlweems
Created March 15, 2017 20:06
Show Gist options
  • Save amlweems/641f26d7389ec0ec016565e725fedf5f to your computer and use it in GitHub Desktop.
Save amlweems/641f26d7389ec0ec016565e725fedf5f to your computer and use it in GitHub Desktop.
convert old ssh-rsa encoded private key to PEM
// Implements a converter for old ssh-rsa encoded private key files.
// These files are formatted as <length><data> and should contain six fields.
// An example header is as follows:
// 00000000: 0000 0007 7373 682d 7273 6100 0000 0301 ....ssh-rsa.....
// 00000010: 0001 0000 0103 0080 .... .... .... .... ................
// The full file should contain the following fields:
// ssh-rsa
// public exponent
// modulus
// unknown (likely precomputed value)
// prime1
// prime2
package main
import (
"crypto/rsa"
"crypto/x509"
"encoding/binary"
"encoding/pem"
"flag"
"log"
"math/big"
"os"
)
var bigOne = big.NewInt(1)
func main() {
inFile := flag.String("in", "id_rsa", "ssh-rsa encoded private key")
outFile := flag.String("out", "priv.pem", "PEM encoded private key")
flag.Parse()
f, err := os.Open(*inFile)
if err != nil {
log.Printf("error reading file: %s", err)
return
}
// read ssh-rsa encoded file
var parts [][]byte
for {
var length uint32
binary.Read(f, binary.BigEndian, &length)
if length == 0 {
break
}
part := make([]byte, length)
_, err := f.Read(part)
if err != nil {
log.Printf("error: could not parse ssh-rsa")
return
}
parts = append(parts, part)
}
f.Close()
// only parse ssh-rsa files that conform to the format we expect
if len(parts) != 6 {
log.Printf("error: invalid ssh-rsa %d", len(parts))
return
}
// parse parts[] into big.Int values
e := new(big.Int).SetBytes(parts[1])
n := new(big.Int).SetBytes(parts[2])
p := new(big.Int).SetBytes(parts[4])
q := new(big.Int).SetBytes(parts[5])
// compute the private exponent manually
totient := new(big.Int).Mul(
new(big.Int).Sub(p, bigOne),
new(big.Int).Sub(q, bigOne),
)
d := new(big.Int)
new(big.Int).GCD(d, nil, e, totient)
// construct the private key
var key = &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
E: int(e.Int64()),
N: n,
},
D: d,
Primes: []*big.Int{p, q},
}
// output the private key as a PEM encoded blob
data := pem.EncodeToMemory(
&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(key),
},
)
f, err = os.Create(*outFile)
if err != nil {
log.Printf("error creating file: %s", err)
return
}
f.Write(data)
f.Close()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment