adding documentation/analysis of key format

This commit is contained in:
brent s. 2020-09-11 23:06:51 -04:00
parent 456284a697
commit 6e032d8969
Signed by: bts
GPG Key ID: 8C004C2F93481F6B
11 changed files with 267 additions and 124 deletions

View File

@ -1,21 +1,12 @@
package sshkeys

// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key

// Needed for V1 key format.
const (
AuthMagic string = "openssh-key-v1"
KeyV1Magic string = "openssh-key-v1"
)

type EncryptedSSHKey2 struct {
SSHKey2
Salt string
Rounds uint32
}
type SSHKey2 struct {
CipherName string
KDFName string
KDFOpts string
NumKeys int
Keys []string
Encrypted []string
}
// Key cipher names.
const (
CipherED25519 = iota
CipherRSA = iota
)

23
sshkeys/func.go Normal file
View File

@ -0,0 +1,23 @@
package sshkeys

func (k *EncryptedSSHKeyV1) GeneratePrivate(keyType uint8) error {
return nil
}

func (k *EncryptedSSHKeyV1) GeneratePublic(keyType uint8) error {
if err := k.GeneratePrivate(keyType); err != nil {
return err
}
return nil
}

func (k *SSHKeyV1) GeneratePrivate(keyType uint8) error {
return nil
}

func (k *SSHKeyV1) GeneratePublic(keyType uint8) error {
if err := k.GeneratePrivate(keyType); err != nil {
return err
}
return nil
}

6
sshkeys/interface.go Normal file
View File

@ -0,0 +1,6 @@
package sshkeys

type OpenSSHKeypair interface {
GeneratePrivate(keyType uint8) error
GeneratePublic(keyType uint8) error
}

View File

@ -1,102 +0,0 @@

# PLAINTEXT
The following is a plaintext key (no passphrase provided).

## Private

### Private ("PEM"-like format):

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBEOIvJc2hN1mhXExEiv/ISyYO7prFixOl80R9zw52XsAAAAJjPbUqwz21K
sAAAAAtzc2gtZWQyNTUxOQAAACBEOIvJc2hN1mhXExEiv/ISyYO7prFixOl80R9zw52XsA
AAAEBqSF+KwoLTOqI6+TnpcaZY4ckcamLrBF8CvtJbNZflJ0Q4i8lzaE3WaFcTESK/8hLJ
g7umsWLE6XzRH3PDnZewAAAAElRoaXMgaXMgYSB0ZXN0IGtleQECAw==
-----END OPENSSH PRIVATE KEY-----

### Private (Hex):

00000000: 6f70 656e 7373 682d 6b65 792d 7631 0000 openssh-key-v1..
00000010: 0000 046e 6f6e 6500 0000 046e 6f6e 6500 ...none....none.
00000020: 0000 0000 0000 0100 0000 3300 0000 0b73 ..........3....s
00000030: 7368 2d65 6432 3535 3139 0000 0020 4438 sh-ed25519... D8
00000040: 8bc9 7368 4dd6 6857 1311 22bf f212 c983 ..shM.hW..".....
00000050: bba6 b162 c4e9 7cd1 1f73 c39d 97b0 0000 ...b..|..s......
00000060: 0098 cf6d 4ab0 cf6d 4ab0 0000 000b 7373 ...mJ..mJ.....ss
00000070: 682d 6564 3235 3531 3900 0000 2044 388b h-ed25519... D8.
00000080: c973 684d d668 5713 1122 bff2 12c9 83bb .shM.hW.."......
00000090: a6b1 62c4 e97c d11f 73c3 9d97 b000 0000 ..b..|..s.......
000000a0: 406a 485f 8ac2 82d3 3aa2 3af9 39e9 71a6 @jH_....:.:.9.q.
000000b0: 58e1 c91c 6a62 eb04 5f02 bed2 5b35 97e5 X...jb.._...[5..
000000c0: 2744 388b c973 684d d668 5713 1122 bff2 'D8..shM.hW.."..
000000d0: 12c9 83bb a6b1 62c4 e97c d11f 73c3 9d97 ......b..|..s...
000000e0: b000 0000 1254 6869 7320 6973 2061 2074 .....This is a t
000000f0: 6573 7420 6b65 7901 0203 est key...


## Public

### .pub format

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEQ4i8lzaE3WaFcTESK/8hLJg7umsWLE6XzRH3PDnZew This is a test key

### Hex

00000000: 0000 000b 7373 682d 6564 3235 3531 3900 ....ssh-ed25519.
00000010: 0000 2044 388b c973 684d d668 5713 1122 .. D8..shM.hW.."
00000020: bff2 12c9 83bb a6b1 62c4 e97c d11f 73c3 ........b..|..s.
00000030: 9d97 b0 ...


# ENCRYPTED

The following uses the bcrypt encryption. The passphrase is "test".

## Private

### "PEM"-like format

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBQEy9ykA
1o4KMfnXW28KW8AAAAZAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIL+iAxqlRjET5A4W
iWr1A8Upnq12sJy2OEb0HMTeF0D2AAAAoMSXd80NGn0323ehgUmRJ4+M6Z1XLixma5O5mG
dCXGDaRlL924VVCYUytRvu7ilZ+dtc9aCQUFJyDF3iXyxN2H68x7teo9e8vqzGtzLkw5KV
2Zkal+8/CDj4qb/UPts0AxiWSQiPbPt4lG+5FONYrGq8ZGkQcvXyeIU02dQtf0BrxQkLMN
8jy33YxcuTjkH6zW446IRbgWC/+EBZgRjUR8I=
-----END OPENSSH PRIVATE KEY-----

### Hex

00000000: 6f70 656e 7373 682d 6b65 792d 7631 0000 openssh-key-v1..
00000010: 0000 0a61 6573 3235 362d 6374 7200 0000 ...aes256-ctr...
00000020: 0662 6372 7970 7400 0000 1800 0000 1050 .bcrypt........P
00000030: 132f 7290 0d68 e0a3 1f9d 75b6 f0a5 bc00 ./r..h....u.....
00000040: 0000 6400 0000 0100 0000 3300 0000 0b73 ..d.......3....s
00000050: 7368 2d65 6432 3535 3139 0000 0020 bfa2 sh-ed25519... ..
00000060: 031a a546 3113 e40e 1689 6af5 03c5 299e ...F1.....j...).
00000070: ad76 b09c b638 46f4 1cc4 de17 40f6 0000 .v...8F.....@...
00000080: 00a0 c497 77cd 0d1a 7d37 db77 a181 4991 ....w...}7.w..I.
00000090: 278f 8ce9 9d57 2e2c 666b 93b9 9867 425c '....W.,fk...gB\
000000a0: 60da 4652 fddb 8555 0985 32b5 1bee ee29 `.FR...U..2....)
000000b0: 59f9 db5c f5a0 9050 5272 0c5d e25f 2c4d Y..\...PRr.]._,M
000000c0: d87e bcc7 bb5e a3d7 bcbe acc6 b732 e4c3 .~...^.......2..
000000d0: 9295 d999 1a97 ef3f 0838 f8a9 bfd4 3edb .......?.8....>.
000000e0: 3403 1896 4908 8f6c fb78 946f b914 e358 4...I..l.x.o...X
000000f0: ac6a bc64 6910 72f5 f278 8534 d9d4 2d7f .j.di.r..x.4..-.
00000100: 406b c509 0b30 df23 cb7d d8c5 cb93 8e41 @k...0.#.}.....A
00000110: facd 6e38 e884 5b81 60bf f840 5981 18d4 ..n8..[.`..@Y...
00000120: 47c2 G.


## Public

### .pub format

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL+iAxqlRjET5A4WiWr1A8Upnq12sJy2OEb0HMTeF0D2 This is a test key

### Hex

00000000: 0000 000b 7373 682d 6564 3235 3531 3900 ....ssh-ed25519.
00000010: 0000 20bf a203 1aa5 4631 13e4 0e16 896a .. .....F1.....j
00000020: f503 c529 9ead 76b0 9cb6 3846 f41c c4de ...)..v...8F....
00000030: 1740 f6 .@.

View File

@ -0,0 +1,65 @@
The following uses the bcrypt encryption. The passphrase is "test".

The new "v1" format contains the header "-----BEGIN OPENSSH PRIVATE KEY-----"
and the footer "-----END OPENSSH PRIVATE KEY-----".

All length ints are uint32, network-byte order.

PEM:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBQEy9ykA
1o4KMfnXW28KW8AAAAZAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIL+iAxqlRjET5A4W
iWr1A8Upnq12sJy2OEb0HMTeF0D2AAAAoMSXd80NGn0323ehgUmRJ4+M6Z1XLixma5O5mG
dCXGDaRlL924VVCYUytRvu7ilZ+dtc9aCQUFJyDF3iXyxN2H68x7teo9e8vqzGtzLkw5KV
2Zkal+8/CDj4qb/UPts0AxiWSQiPbPt4lG+5FONYrGq8ZGkQcvXyeIU02dQtf0BrxQkLMN
8jy33YxcuTjkH6zW446IRbgWC/+EBZgRjUR8I=
-----END OPENSSH PRIVATE KEY-----

HEX:
00000000: 6f70 656e 7373 682d 6b65 792d 7631 0000 openssh-key-v1..
00000010: 0000 0a61 6573 3235 362d 6374 7200 0000 ...aes256-ctr...
00000020: 0662 6372 7970 7400 0000 1800 0000 1050 .bcrypt........P
00000030: 132f 7290 0d68 e0a3 1f9d 75b6 f0a5 bc00 ./r..h....u.....
00000040: 0000 6400 0000 0100 0000 3300 0000 0b73 ..d.......3....s
00000050: 7368 2d65 6432 3535 3139 0000 0020 bfa2 sh-ed25519... ..
00000060: 031a a546 3113 e40e 1689 6af5 03c5 299e ...F1.....j...).
00000070: ad76 b09c b638 46f4 1cc4 de17 40f6 0000 .v...8F.....@...
00000080: 00a0 c497 77cd 0d1a 7d37 db77 a181 4991 ....w...}7.w..I.
00000090: 278f 8ce9 9d57 2e2c 666b 93b9 9867 425c '....W.,fk...gB\
000000a0: 60da 4652 fddb 8555 0985 32b5 1bee ee29 `.FR...U..2....)
000000b0: 59f9 db5c f5a0 9050 5272 0c5d e25f 2c4d Y..\...PRr.]._,M
000000c0: d87e bcc7 bb5e a3d7 bcbe acc6 b732 e4c3 .~...^.......2..
000000d0: 9295 d999 1a97 ef3f 0838 f8a9 bfd4 3edb .......?.8....>.
000000e0: 3403 1896 4908 8f6c fb78 946f b914 e358 4...I..l.x.o...X
000000f0: ac6a bc64 6910 72f5 f278 8534 d9d4 2d7f .j.di.r..x.4..-.
00000100: 406b c509 0b30 df23 cb7d d8c5 cb93 8e41 @k...0.#.}.....A
00000110: facd 6e38 e884 5b81 60bf f840 5981 18d4 ..n8..[.`..@Y...
00000120: 47c2 G.

ANNOTATED HEX:
0 6f70656e7373682d6b65792d763100 ("openssh-key-v1" + 0x00)
1.0 0000000a (10)
1.0.0 6165733235362d637472 ("aes256-ctr")
2.0 00000006 (6)
2.0.0 626372797074 ("bcrypt")
3.0 00000018 (24)
3.0.0 -
3.0.0.0 00000010 (16)
3.0.0.0.0 50132f72900d68e0a31f9d75b6f0a5bc (bytes)
3.0.0.1 00000064 (83)
4.0 00000001 (1)
4.0.0 00000033 (51)
4.0.0.0 0000000b (11)
4.0.0.0.0 7373682d65643235353139 ("ssh-ed25519")
4.0.0.1 00000020 (32)
4.0.0.1.0 bfa2031aa5463113e40e16896af503c5299ead76b09cb63846f41cc4de1740f6 (bytes)
4.0.1 000000a0 (160)
4.0.1 (AES256-CBC encrypted block) (bytes)
c49777cd0d1a7d37db77a1814991278f8ce99d57
2e2c666b93b99867425c60da4652fddb85550985
32b51beeee2959f9db5cf5a0905052720c5de25f
2c4dd87ebcc7bb5ea3d7bcbeacc6b732e4c39295
d9991a97ef3f0838f8a9bfd43edb340318964908
8f6cfb78946fb914e358ac6abc64691072f5f278
8534d9d42d7f406bc5090b30df23cb7dd8c5cb93
8e41facd6e38e8845b8160bff840598118d447c2

View File

@ -0,0 +1,16 @@
The following uses the bcrypt encryption. The passphrase is "test".

PEM:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL+iAxqlRjET5A4WiWr1A8Upnq12sJy2OEb0HMTeF0D2 This is a test key

HEX:
00000000: 0000 000b 7373 682d 6564 3235 3531 3900 ....ssh-ed25519.
00000010: 0000 20bf a203 1aa5 4631 13e4 0e16 896a .. .....F1.....j
00000020: f503 c529 9ead 76b0 9cb6 3846 f41c c4de ...)..v...8F....
00000030: 1740 f6 .@.

ANNOTATED HEX:
0 0000000b (11)
0.0 7373682d65643235353139 ("ssh-ed25519")
1 00000020 (32)
1.1 bfa2031aa5463113e40e16896af503c5299ead76b09cb63846f41cc4de1740f6 (bytes)

45
sshkeys/ref/format Normal file
View File

@ -0,0 +1,45 @@
ANNOTATED HEX REFERENCE:

PRIVATE:
0 "openssh-key-v1" string plus terminating nullbyte
1.0 uint32 allocator for 1.0.0
1.0.0 cipher name (string) - if not encrypted (no passphrase), "none"
2.0 uint32 allocator for 2.0.0
2.0.0 KDF name (string) - if not encrypted (no passphrase), "none"
3.0 uint32 allocator for 3.0.0 (nullbyte if unencrypted key)
3.0.0 (virtual) KDF options. This is "missing" if it is an unencrypted key.
3.0.0.0 uint32 allocator for 3.0.0.0.0
3.0.0.0.0 Salt/IV (bytes)
3.0.0.1 Number of rounds/"work factor" (uint32)
4.0 uint32 allocator for # of keys (currently unused; hardcoded to 1 (left zero-padded 0x01))
4.0.0 uint32 allocator for public key #1 (4.0.0.0 to 4.0.0.1, inclusive)
4.0.0.0 uint32 allocator for 4.0.0.0.0
4.0.0.0.0 public key #1 keytype (string)
4.0.0.1 uint32 allocator for 4.0.0.1.0
4.0.0.1.0 public key #1 payload (bytes)
4.0.1 uint32 allocator for private key #1 (4.0.1.0 to 4.0.1.5, inclusive?)[0]
4.0.1.0 Checksum (random uint32) #1 (should match 4.0.1.1)
4.0.1.1 Checksum (random uint32) #2 (should match 4.0.1.0)
4.0.1.2 (virtual) Copy of public key (copy of 4.0.0.0 to 4.0.0.1, inclusive)
4.0.1.2.0 uint32 allocator for 4.0.1.2.0.0
4.0.1.2.0.0 public key #1 keytype (string)
4.0.1.2.1 uint32 allocator for 4.0.1.2.1.0
4.0.1.2.1.0 public key #1 payload (bytes)
4.0.1.3 uint32 allocator for 4.0.1.3.0
4.0.1.3.0 Private key #1 (bytes)
4.0.1.4 uint3 allocator for 4.0.1.4.0
4.0.1.4.0 Comment for key #1 (string)
4.0.1.5 Sequential padding to align private key to cipher blocksize (8 for unencrypted keys)[1].


[0] If it is an encrypted key, everything below 4.0.1 is AES256-CBC encrypted.
[1] Pad determined by: 8 - ((4.0.1.3 + 4.0.1.4) % 8) (??)



PUBLIC:
(Each .pub file's Base64 string contains 4.0.0.0 to 4.0.0.1 inclusive above)
0 uint32 allocator for 0.0
0.0 Public key keytype (string)
1 uint32 allocator for 1.0
1.0 Public key payload (bytes)

62
sshkeys/ref/plain/private Normal file
View File

@ -0,0 +1,62 @@
The following is a plaintext key (no passphrase provided).

The new "v1" format contains the header "-----BEGIN OPENSSH PRIVATE KEY-----"
and the footer "-----END OPENSSH PRIVATE KEY-----".

All length ints are uint32, network-byte order.

PEM:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBEOIvJc2hN1mhXExEiv/ISyYO7prFixOl80R9zw52XsAAAAJjPbUqwz21K
sAAAAAtzc2gtZWQyNTUxOQAAACBEOIvJc2hN1mhXExEiv/ISyYO7prFixOl80R9zw52XsA
AAAEBqSF+KwoLTOqI6+TnpcaZY4ckcamLrBF8CvtJbNZflJ0Q4i8lzaE3WaFcTESK/8hLJ
g7umsWLE6XzRH3PDnZewAAAAElRoaXMgaXMgYSB0ZXN0IGtleQECAw==
-----END OPENSSH PRIVATE KEY-----

HEX (only base64 string above):
00000000: 6f70 656e 7373 682d 6b65 792d 7631 0000 openssh-key-v1..
00000010: 0000 046e 6f6e 6500 0000 046e 6f6e 6500 ...none....none.
00000020: 0000 0000 0000 0100 0000 3300 0000 0b73 ..........3....s
00000030: 7368 2d65 6432 3535 3139 0000 0020 4438 sh-ed25519... D8
00000040: 8bc9 7368 4dd6 6857 1311 22bf f212 c983 ..shM.hW..".....
00000050: bba6 b162 c4e9 7cd1 1f73 c39d 97b0 0000 ...b..|..s......
00000060: 0098 cf6d 4ab0 cf6d 4ab0 0000 000b 7373 ...mJ..mJ.....ss
00000070: 682d 6564 3235 3531 3900 0000 2044 388b h-ed25519... D8.
00000080: c973 684d d668 5713 1122 bff2 12c9 83bb .shM.hW.."......
00000090: a6b1 62c4 e97c d11f 73c3 9d97 b000 0000 ..b..|..s.......
000000a0: 406a 485f 8ac2 82d3 3aa2 3af9 39e9 71a6 @jH_....:.:.9.q.
000000b0: 58e1 c91c 6a62 eb04 5f02 bed2 5b35 97e5 X...jb.._...[5..
000000c0: 2744 388b c973 684d d668 5713 1122 bff2 'D8..shM.hW.."..
000000d0: 12c9 83bb a6b1 62c4 e97c d11f 73c3 9d97 ......b..|..s...
000000e0: b000 0000 1254 6869 7320 6973 2061 2074 .....This is a t
000000f0: 6573 7420 6b65 7901 0203 est key...

ANNOTATED HEX:
0 6f70656e7373682d6b65792d763100 ("openssh-key-v1" + 0x00)
1.0 00000004 (4)
1.0.0 6e6f6e65 ("none")
2.0 00000004 (4)
2.0.0 6e6f6e65 ("none")
3.0 00000000 (0x00)
3.0.0 (N/A)
4.0 00000001 (1)
4.0.0 00000033 (51)
4.0.0.0 0000000b (11)
4.0.0.0.0 7373682d65643235353139 ("ssh-ed25519")
4.0.0.1 00000020 (32)
4.0.0.1.0 44388bc973684dd66857131122bff212c983bba6b162c4e97cd11f73c39d97b0 (bytes)
4.0.1 00000098 (151)
4.0.1.0 cf6d4ab0 (3480046256)
4.0.1.1 cf6d4ab0 (3480046256)
4.0.1.2 -
4.0.1.2.0 0000000b (11)
4.0.1.2.0.0 7373682d65643235353139 ("ssh-ed25519")
4.0.1.2.1 00000020 (32)
4.0.1.2.1.0 44388bc973684dd66857131122bff212c983bba6b162c4e97cd11f73c39d97b0 (bytes)
4.0.1.3 00000040 (64)
4.0.1.3.0 6a485f8ac282d33aa23af939e971a658e1c91c6a62eb045f02bed25b3597e527
44388bc973684dd66857131122bff212c983bba6b162c4e97cd11f73c39d97b0 (bytes)
4.0.1.4 00000012 (18)
4.0.1.4.0 5468697320697320612074657374206b6579 ("This is a test key")
4.0.1.5 010203 ([1 2 3], 3 bytes)

20
sshkeys/ref/plain/public Normal file
View File

@ -0,0 +1,20 @@
The following is a plaintext pubkey (no passphrase provided).

Keys in the "PEM" (.pub) format are prefixed with the key type string and suffixed with the comment string.

All length ints are uint32, network-byte order.

PEM:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEQ4i8lzaE3WaFcTESK/8hLJg7umsWLE6XzRH3PDnZew This is a test key

HEX (only base64 string above):
00000000: 0000 000b 7373 682d 6564 3235 3531 3900 ....ssh-ed25519.
00000010: 0000 2044 388b c973 684d d668 5713 1122 .. D8..shM.hW.."
00000020: bff2 12c9 83bb a6b1 62c4 e97c d11f 73c3 ........b..|..s.
00000030: 9d97 b0 ...

ANNOTATED HEX:
0 0000000b (11)
0.0 7373682d65643235353139 ("ssh-ed25519")
1 00000020 (32)
1.1 44388bc973684dd66857131122bff212c983bba6b162c4e97cd11f73c39d97b0 (bytes)

7
sshkeys/ref/sources Normal file
View File

@ -0,0 +1,7 @@
https://peterlyons.com/problog/2017/12/openssh-ed25519-private-key-file-format/
https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
canonical: https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.key?annotate=HEAD
https://stackoverflow.com/a/56300901/733214
https://stackoverflow.com/a/59283692/733214
https://coolaj86.com/articles/the-openssh-private-key-format/
https://coolaj86.com/articles/the-ssh-public-key-format/

View File

@ -1,11 +1,21 @@
package sshkeys

type SSHPubkey struct {
// Raw ???
B64 string
Comment string
// EncryptedSSHKeyV1 represents an encrypted private key.
type EncryptedSSHKeyV1 struct {
SSHKeyV1
Salt string
Rounds uint32
Passphrase string
}

type SSHPrivateKey struct {
// SSHKeyV1 represents an unencrypted private key.
// We don't bother with the legacy (pre v1) keys. Sorry not sorry.
// Patch your shit.
type SSHKeyV1 struct {
CipherName string
KDFName string
KDFOpts string
NumKeys uint32
Publickey string
Privatekey string
}