openssh.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. // Copyright 2012 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Code originally from https://go-review.googlesource.com/c/crypto/+/218620
  5. // TODO: replace with upstream once the above change is merged and released.
  6. package format
  7. import (
  8. "crypto"
  9. "crypto/ed25519"
  10. "crypto/rand"
  11. "encoding/binary"
  12. "encoding/pem"
  13. "fmt"
  14. "golang.org/x/crypto/ssh"
  15. )
  16. const privateKeyAuthMagic = "openssh-key-v1\x00"
  17. type openSSHEncryptedPrivateKey struct {
  18. CipherName string
  19. KDFName string
  20. KDFOptions string
  21. KeysCount uint32
  22. PubKey []byte
  23. KeyBlocks []byte
  24. }
  25. type openSSHPrivateKey struct {
  26. Check1 uint32
  27. Check2 uint32
  28. Keytype string
  29. Rest []byte `ssh:"rest"`
  30. }
  31. type openSSHEd25519PrivateKey struct {
  32. Pub []byte
  33. Priv []byte
  34. Comment string
  35. Pad []byte `ssh:"rest"`
  36. }
  37. func OpenSSHPrivateKey(key crypto.PrivateKey, comment string) (*pem.Block, error) {
  38. var check uint32
  39. if err := binary.Read(rand.Reader, binary.BigEndian, &check); err != nil {
  40. return nil, err
  41. }
  42. var pk1 openSSHPrivateKey
  43. pk1.Check1 = check
  44. pk1.Check2 = check
  45. var w openSSHEncryptedPrivateKey
  46. w.KeysCount = 1
  47. if k, ok := key.(*ed25519.PrivateKey); ok {
  48. key = *k
  49. }
  50. switch k := key.(type) {
  51. case ed25519.PrivateKey:
  52. pub, priv := k[32:], k
  53. key := openSSHEd25519PrivateKey{
  54. Pub: pub,
  55. Priv: priv,
  56. Comment: comment,
  57. }
  58. pk1.Keytype = ssh.KeyAlgoED25519
  59. pk1.Rest = ssh.Marshal(key)
  60. w.PubKey = ssh.Marshal(struct {
  61. KeyType string
  62. Pub []byte
  63. }{
  64. ssh.KeyAlgoED25519, pub,
  65. })
  66. default:
  67. return nil, fmt.Errorf("ssh: unknown key type %T", k)
  68. }
  69. w.KeyBlocks = openSSHPadding(ssh.Marshal(pk1), 8)
  70. w.CipherName, w.KDFName, w.KDFOptions = "none", "none", ""
  71. return &pem.Block{
  72. Type: "OPENSSH PRIVATE KEY",
  73. Bytes: append([]byte(privateKeyAuthMagic), ssh.Marshal(w)...),
  74. }, nil
  75. }
  76. func openSSHPadding(block []byte, blocksize int) []byte {
  77. for i, j := 0, len(block); (j+i)%blocksize != 0; i++ {
  78. block = append(block, byte(i+1))
  79. }
  80. return block
  81. }