...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package ssh
17
18 import (
19 "crypto/rand"
20 "crypto/sha256"
21 "crypto/sha512"
22 "hash"
23 "io"
24
25 "golang.org/x/crypto/ssh"
26 )
27
28
29 type MessageWrapper struct {
30 Namespace string
31 Reserved string
32 HashAlgorithm string
33 Hash string
34 }
35
36
37 type WrappedSig struct {
38 MagicHeader [6]byte
39 Version uint32
40 PublicKey string
41 Namespace string
42 Reserved string
43 HashAlgorithm string
44 Signature string
45 }
46
47 const (
48 magicHeader = "SSHSIG"
49 defaultHashAlgorithm = "sha512"
50 )
51
52 var supportedHashAlgorithms = map[string]func() hash.Hash{
53 "sha256": sha256.New,
54 "sha512": sha512.New,
55 }
56
57 func sign(s ssh.AlgorithmSigner, m io.Reader) (*ssh.Signature, error) {
58 hf := sha512.New()
59 if _, err := io.Copy(hf, m); err != nil {
60 return nil, err
61 }
62 mh := hf.Sum(nil)
63
64 sp := MessageWrapper{
65 Namespace: "file",
66 HashAlgorithm: defaultHashAlgorithm,
67 Hash: string(mh),
68 }
69
70 dataMessageWrapper := ssh.Marshal(sp)
71 dataMessageWrapper = append([]byte(magicHeader), dataMessageWrapper...)
72
73
74
75
76 algo := ""
77 if s.PublicKey().Type() == ssh.KeyAlgoRSA {
78 algo = ssh.KeyAlgoRSASHA512
79 }
80 sig, err := s.SignWithAlgorithm(rand.Reader, dataMessageWrapper, algo)
81 if err != nil {
82 return nil, err
83 }
84 return sig, nil
85 }
86
87 func Sign(sshPrivateKey string, data io.Reader) ([]byte, error) {
88 s, err := ssh.ParsePrivateKey([]byte(sshPrivateKey))
89 if err != nil {
90 return nil, err
91 }
92
93 as, ok := s.(ssh.AlgorithmSigner)
94 if !ok {
95 return nil, err
96 }
97
98 sig, err := sign(as, data)
99 if err != nil {
100 return nil, err
101 }
102
103 armored := Armor(sig, s.PublicKey())
104 return armored, nil
105 }
106
View as plain text