Created
March 15, 2017 20:06
-
-
Save amlweems/641f26d7389ec0ec016565e725fedf5f to your computer and use it in GitHub Desktop.
convert old ssh-rsa encoded private key to PEM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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