Checking in some work. Keygen is done (with confirmation of data formatting output pending), and dh params is way easier than I thought it would be. We shouldn't need to regenerate dhparams. i *think*.

This commit is contained in:
2020-09-24 04:38:29 -04:00
parent b80b823c02
commit c22786204a
10 changed files with 360 additions and 76 deletions

View File

@@ -23,10 +23,6 @@ const (
KeyV1Magic string = "openssh-key-v1"
)
// "Meta". Used for comment strings, etc.
const projUrl = "https://git.square-r00t.net/SSHSecure"
// Defaults.
const (
defCipher string = CipherAes256Ctr

View File

@@ -19,10 +19,12 @@
package sshkeys
import (
`bytes`
"bytes"
"crypto/rand"
"errors"
"fmt"
"r00t2.io/sshsecure/sharedconsts"
)
func (k *EncryptedSSHKeyV1) validate() error {
@@ -86,7 +88,7 @@ func (k *EncryptedSSHKeyV1) Generate(force bool) error {
// Currently, OpenSSH has an option for multiple private keys. However, it is hardcoded to 1.
// If multiple key support is added in the future, will need to re-tool how I do this, perhaps, in the future. TODO.
pk := SSHPrivKey{
Comment: fmt.Sprintf("Autogenerated via SSHSecure (%v)", projUrl),
Comment: sharedconsts.IDCmnt,
}
pk.Checksum = make([]byte, 4)
if _, err := rand.Read(pk.Checksum); err != nil {
@@ -181,7 +183,7 @@ func (k *EncryptedSSHKeyV1) buildKeybuf() error {
// Since this is encrypted, the private key blobs are encrypted.
// OpenSSH keys currently only support 1 keypair but support more *in theory*. This *seems* to be how they plan on doing it.
// But boy, is it a pain. So much wasted RAM and CPU cycles. They should use terminating byte sequences IMHO but whatever.
for _, i := range k.Keys { // 4.0.0 and 4.0.1
for _, i := range k.Keys { // 4.0.0 and 4.0.1
switch k.CipherName {
case CipherAes256Ctr:
i.BlockSize = k.Crypt.Cipher.BlockSize()
@@ -209,7 +211,7 @@ func (k *SSHKeyV1) buildKeybuf() error {
// Add the keypairs.
// OpenSSH keys currently only support 1 keypair but support more *in theory*. This *seems* to be how they plan on doing it.
// But boy, is it a pain. So much wasted RAM and CPU cycles. They should use terminating byte sequences IMHO but whatever.
for _, i := range k.Keys { // 4.0.0 and 4.0.1
for _, i := range k.Keys { // 4.0.0 and 4.0.1
i.BlockSize = 8
kbPtr, err := i.keyBlob(nil, false)
if err != nil {
@@ -224,19 +226,19 @@ func (k *SSHKeyV1) addHeader() error {
// TODO: error handling for each <buf>.Write()?
// First we need to do some prep for the plaintext header.
var kdfOptsBytes []byte
kdfOptsBytes = k.getKdfOptBytes() // 3.0.0
cipherBytes := []byte(k.CipherName) // 1.0
kdf := []byte(k.KDFName) // 2.0.0
kdfOptsBytes = k.getKdfOptBytes() // 3.0.0
cipherBytes := []byte(k.CipherName) // 1.0
kdf := []byte(k.KDFName) // 2.0.0
// This is just cast to an array for visual readability.
commonHeader := [][]byte{
[]byte(KeyV1Magic + "\x00"), // 0
getBytelenByteArr(cipherBytes), // 1.0
cipherBytes, // 1.0.0
getBytelenByteArr(kdf), // 2.0
kdf, // 2.0.0
getBytelenByteArr(kdfOptsBytes), // 3.0
kdfOptsBytes, // 3.0.0
getByteInt(len(k.Keys)), // 4.0
[]byte(KeyV1Magic + "\x00"), // 0
getBytelenByteArr(cipherBytes), // 1.0
cipherBytes, // 1.0.0
getBytelenByteArr(kdf), // 2.0
kdf, // 2.0.0
getBytelenByteArr(kdfOptsBytes), // 3.0
kdfOptsBytes, // 3.0.0
getByteInt(len(k.Keys)), // 4.0
}
for _, v := range commonHeader {
if _, err := k.Buffer.Write(v); err != nil {
@@ -247,28 +249,28 @@ func (k *SSHKeyV1) addHeader() error {
}
func (k *EncryptedSSHKeyV1) getKdfOptBytes() []byte {
var kdfOptsBytes []byte // 3.0.0
var kdfOptsBytes []byte // 3.0.0
// This is *probably* more efficient than using a buffer just for these bytes.
kdfOptsBytes = append(kdfOptsBytes, byte(len(k.KDFOpts.Salt))) // 3.0.0.0
kdfOptsBytes = append(kdfOptsBytes, k.KDFOpts.Salt...) // 3.0.0.0.0
kdfOptsBytes = append(kdfOptsBytes, byte(k.KDFOpts.Rounds)) // 3.0.0.1
kdfOptsBytes = append(kdfOptsBytes, byte(len(k.KDFOpts.Salt))) // 3.0.0.0
kdfOptsBytes = append(kdfOptsBytes, k.KDFOpts.Salt...) // 3.0.0.0.0
kdfOptsBytes = append(kdfOptsBytes, byte(k.KDFOpts.Rounds)) // 3.0.0.1
return kdfOptsBytes
}
func (k *SSHKeyV1) getKdfOptBytes() []byte {
var kdfOptsBytes []byte // 3.0.0
var kdfOptsBytes []byte // 3.0.0
// No-op; unencrypted keys' KDFOpts are encapsulated by a single null byte (which the caller implements).
return kdfOptsBytes
}
func (pk *SSHPrivKey) keyBlob(c *SSHCrypt, encrypt bool) (*[]byte, error) {
// TODO: error handling for each <buf>.Write()?
var keypairBytes bytes.Buffer // (4.0's children)
var pubkeyBytes bytes.Buffer // 4.0.0 children (4.0.0 itself is handled before writing to keypairBytes)
var privkeyBytes bytes.Buffer // 4.0.1 (and children)
pubkeyName := []byte(pk.PublicKey.KeyType) // (4.0.0.0.0, cast to var because I'm lazy)
pubkeyBytes.Write(getBytelenByteArr(pubkeyName)) // 4.0.0.0
pubkeyBytes.Write(pubkeyName) // 4.0.0.0.0
var keypairBytes bytes.Buffer // (4.0's children)
var pubkeyBytes bytes.Buffer // 4.0.0 children (4.0.0 itself is handled before writing to keypairBytes)
var privkeyBytes bytes.Buffer // 4.0.1 (and children)
pubkeyName := []byte(pk.PublicKey.KeyType) // (4.0.0.0.0, cast to var because I'm lazy)
pubkeyBytes.Write(getBytelenByteArr(pubkeyName)) // 4.0.0.0
pubkeyBytes.Write(pubkeyName) // 4.0.0.0.0
// TODO: Optimize?
/*
THE PUBLIC KEY
@@ -280,17 +282,17 @@ func (pk *SSHPrivKey) keyBlob(c *SSHCrypt, encrypt bool) (*[]byte, error) {
pubkeyBytes.Write(pk.PublicKey.Key.([]byte)) // 4.0.0.1.0
case KeyRsa:
// How messy.
var en bytes.Buffer // 4.0.0.1 and 4.0.0.2
var en bytes.Buffer // 4.0.0.1 and 4.0.0.2
// TODO: does e need getByteInt()?
e := pk.PublicKey.Key.E.Bytes() // 4.0.0.1.0
e := pk.PublicKey.Key.E.Bytes() // 4.0.0.1.0
// TODO: does n need nullbyte prefix?
n := pk.PublicKey.Key.N.Bytes() // 4.0.0.2.0
en.Write(getBytelenByteArr(e)) // 4.0.0.1
en.Write(e) // 4.0.0.1.0
en.Write(getBytelenByteArr(n)) // 4.0.0.2
en.Write(n) // 4.0.0.2.0
pubkeyBytes.Write(getBytelenByteArr(en.Bytes())) // 4.0.0
if _, err := en.WriteTo(&pubkeyBytes); err != nil { // (4.0.0 children)
n := pk.PublicKey.Key.N.Bytes() // 4.0.0.2.0
en.Write(getBytelenByteArr(e)) // 4.0.0.1
en.Write(e) // 4.0.0.1.0
en.Write(getBytelenByteArr(n)) // 4.0.0.2
en.Write(n) // 4.0.0.2.0
pubkeyBytes.Write(getBytelenByteArr(en.Bytes())) // 4.0.0
if _, err := en.WriteTo(&pubkeyBytes); err != nil { // (4.0.0 children)
return nil, err
}
}
@@ -300,7 +302,7 @@ func (pk *SSHPrivKey) keyBlob(c *SSHCrypt, encrypt bool) (*[]byte, error) {
*/
// First we need two checksums.
for i := 1; i <= 2; i++ {
privkeyBytes.Write(pk.Checksum) // 4.0.1.0 and 4.0.1.1
privkeyBytes.Write(pk.Checksum) // 4.0.1.0 and 4.0.1.1
}
// And then add the public keys. Yes, the public keys are included in the private keys.
privkeyBytes.Write(getBytelenByteArr(pubkeyName)) // 4.0.1.2.0
@@ -308,57 +310,57 @@ func (pk *SSHPrivKey) keyBlob(c *SSHCrypt, encrypt bool) (*[]byte, error) {
switch pk.PublicKey.KeyType {
case KeyEd25519:
// This is easy.
privkeyBytes.Write(pubkeyBytes.Bytes()) // 4.0.1.2.1
if _, err := pubkeyBytes.WriteTo(&privkeyBytes); err != nil { // 4.0.1.2.1.0
privkeyBytes.Write(pubkeyBytes.Bytes()) // 4.0.1.2.1
if _, err := pubkeyBytes.WriteTo(&privkeyBytes); err != nil { // 4.0.1.2.1.0
return nil, err
}
case KeyRsa:
// This is not. We more or less have to do the same thing as the public key, BUT with e and n flipped. Gorram it.
var ne bytes.Buffer // (4.0.1.2 children)
var ne bytes.Buffer // (4.0.1.2 children)
// TODO: does n need nullbyte prefix?
n := pk.PublicKey.Key.N.Bytes() // 4.0.1.2.1.0
n := pk.PublicKey.Key.N.Bytes() // 4.0.1.2.1.0
// TODO: does e need getByteInt()?
e := pk.PublicKey.Key.E.Bytes() // 4.0.1.2.2.0
ne.Write(getBytelenByteArr(n)) // 4.0.1.2.1
ne.Write(n) // 4.0.1.2.1.0
ne.Write(getBytelenByteArr(e)) // 4.0.1.2.2
ne.Write(e) // 4.0.1.2.2.0
if _, err := ne.WriteTo(&privkeyBytes); err != nil { // (4.0.1.2 children)
e := pk.PublicKey.Key.E.Bytes() // 4.0.1.2.2.0
ne.Write(getBytelenByteArr(n)) // 4.0.1.2.1
ne.Write(n) // 4.0.1.2.1.0
ne.Write(getBytelenByteArr(e)) // 4.0.1.2.2
ne.Write(e) // 4.0.1.2.2.0
if _, err := ne.WriteTo(&privkeyBytes); err != nil { // (4.0.1.2 children)
return nil, err
}
}
// And then we add the *actual* private keys.
switch pk.PublicKey.KeyType {
case KeyEd25519:
privkeyBytes.Write(getBytelenByteArr(pk.KeyAlt)) // 4.0.1.3
privkeyBytes.Write(pk.KeyAlt) // 4.0.1.3.0
privkeyBytes.Write(getBytelenByteArr(pk.KeyAlt)) // 4.0.1.3
privkeyBytes.Write(pk.KeyAlt) // 4.0.1.3.0
case KeyRsa:
var dcpq bytes.Buffer // 4.0.1.3 to 4.0.1.6
d := pk.Key.D.Bytes() // 4.0.1.3.0
crt := pk.Key.Precomputed.Qinv.Bytes() // 4.0.1.4.0
var dcpq bytes.Buffer // 4.0.1.3 to 4.0.1.6
d := pk.Key.D.Bytes() // 4.0.1.3.0
crt := pk.Key.Precomputed.Qinv.Bytes() // 4.0.1.4.0
// TODO: does p need nullbyte prefix?
p := pk.Key.Primes[0].Bytes() // 4.0.1.5.0
p := pk.Key.Primes[0].Bytes() // 4.0.1.5.0
// TODO: does q need nullbyte prefix?
q := pk.Key.Primes[1].Bytes() // 4.0.1.6.0
dcpq.Write(getBytelenByteArr(d)) // 4.0.1.3
dcpq.Write(d) // 4.0.1.3.0
dcpq.Write(getBytelenByteArr(crt)) // 4.0.1.4
dcpq.Write(crt) // 4.0.1.4.0
dcpq.Write(getBytelenByteArr(p)) // 4.0.1.5
dcpq.Write(p) // 4.0.1.5.0
dcpq.Write(getBytelenByteArr(q)) // 4.0.1.6
dcpq.Write(q) // 4.0.1.6.0
if _, err := dcpq.WriteTo(&privkeyBytes); err != nil { // 4.0.1.3 to 4.0.1.6
q := pk.Key.Primes[1].Bytes() // 4.0.1.6.0
dcpq.Write(getBytelenByteArr(d)) // 4.0.1.3
dcpq.Write(d) // 4.0.1.3.0
dcpq.Write(getBytelenByteArr(crt)) // 4.0.1.4
dcpq.Write(crt) // 4.0.1.4.0
dcpq.Write(getBytelenByteArr(p)) // 4.0.1.5
dcpq.Write(p) // 4.0.1.5.0
dcpq.Write(getBytelenByteArr(q)) // 4.0.1.6
dcpq.Write(q) // 4.0.1.6.0
if _, err := dcpq.WriteTo(&privkeyBytes); err != nil { // 4.0.1.3 to 4.0.1.6
return nil, err
}
}
// Add the comment.
privkeyBytes.Write(getBytelenByteArr([]byte(pk.Comment))) // 4.0.1.4 (ED25519), 4.0.1.7 (RSA)
privkeyBytes.Write([]byte(pk.Comment)) // 4.0.1.4.0 (ED25519), 4.0.1.7.0 (RSA)
privkeyBytes.Write(getBytelenByteArr([]byte(pk.Comment))) // 4.0.1.4 (ED25519), 4.0.1.7 (RSA)
privkeyBytes.Write([]byte(pk.Comment)) // 4.0.1.4.0 (ED25519), 4.0.1.7.0 (RSA)
// Add padding
pad := 0
n := 0
for len(privkeyBytes.Bytes()) % pk.BlockSize != 0 { // 4.0.1.5 (ED25519), 4.0.1.8 (RSA)
for len(privkeyBytes.Bytes())%pk.BlockSize != 0 { // 4.0.1.5 (ED25519), 4.0.1.8 (RSA)
n++
pad = n & pk.BlockSize
privkeyBytes.Write(getSingleByteInt(pad))
@@ -377,15 +379,15 @@ func (pk *SSHPrivKey) keyBlob(c *SSHCrypt, encrypt bool) (*[]byte, error) {
encBytes = []byte{}
}
// Get the respective lengths and add child buffers to buffer.
keypairBytes.Write(getByteInt(len(pubkeyBytes.Bytes()))) // 4.0.0
if _, err := pubkeyBytes.WriteTo(&keypairBytes); err != nil { // (4.0.0 children)
keypairBytes.Write(getByteInt(len(pubkeyBytes.Bytes()))) // 4.0.0
if _, err := pubkeyBytes.WriteTo(&keypairBytes); err != nil { // (4.0.0 children)
return nil, err
}
keypairBytes.Write(getByteInt(len(privkeyBytes.Bytes()))) // 4.0.1
if _, err := privkeyBytes.WriteTo(&keypairBytes); err != nil { // (4.0.1 children)
keypairBytes.Write(getByteInt(len(privkeyBytes.Bytes()))) // 4.0.1
if _, err := privkeyBytes.WriteTo(&keypairBytes); err != nil { // (4.0.1 children)
return nil, err
}
// Done!
kpSlice := keypairBytes.Bytes()
return &kpSlice, nil
}
}