88 "io/ioutil"
99 "net/http"
1010 "os"
11+ "regexp"
1112 "strings"
1213 "sync"
1314 "sync/atomic"
@@ -18,30 +19,108 @@ type member struct {
1819 Keys []string
1920}
2021
21- func main () {
22- ms := getMembers ()
23- ms = getKeys (ms )
24- printReport (ms )
22+ type keyTable struct {
23+ keyDsaSize uint32
24+ keyEcdsaSize uint32
25+ keyEd25519Size uint32
26+ keyRsaSize uint32
27+ keyStrongRsaSize uint32
28+ keyWeakRsaSize uint32
29+ userDsaSize uint32
30+ userEcdsaSize uint32
31+ userEd25519Size uint32
32+ userRsaSize uint32
33+ userWithKeySize uint32
34+ userWithoutKeySize uint32
35+ userWithMultipleKeySize uint32
36+ keySize uint32
37+ strongKeySize uint32
38+ weakKeySize uint32
39+ userSize uint32
40+ userWithStrongKeySize uint32
41+ userWithWeakKeySize uint32
42+ userWithWeakKey []member
43+ }
44+
45+ func printReport (kt keyTable ) {
46+ withKey := [][]string {
47+ {"users with keys" ,
48+ "DSA" ,
49+ fmt .Sprintf ("%d (%.2f%%)" , kt .keyDsaSize , float32 (kt .keyDsaSize )/ float32 (kt .keySize )* 100 ),
50+ fmt .Sprintf ("%d (%.2f%%)" , kt .userDsaSize , float32 (kt .userDsaSize )/ float32 (kt .userSize )* 100 )},
51+ {"" ,
52+ "ECDSA" ,
53+ fmt .Sprintf ("%d (%.2f%%)" , kt .keyEcdsaSize , float32 (kt .keyEcdsaSize )/ float32 (kt .keySize )* 100 ),
54+ fmt .Sprintf ("%d (%.2f%%)" , kt .userEcdsaSize , float32 (kt .userEcdsaSize )/ float32 (kt .userSize )* 100 )},
55+ {"" ,
56+ "Ed25519" ,
57+ fmt .Sprintf ("%d (%.2f%%)" , kt .keyEd25519Size , float32 (kt .keyEd25519Size )/ float32 (kt .keySize )* 100 ),
58+ fmt .Sprintf ("%d (%.2f%%)" , kt .userEd25519Size , float32 (kt .userEd25519Size )/ float32 (kt .userSize )* 100 )},
59+ {"" ,
60+ "RSA" ,
61+ fmt .Sprintf ("%d (%.2f%%)" , kt .keyRsaSize , float32 (kt .keyRsaSize )/ float32 (kt .keySize )* 100 ),
62+ fmt .Sprintf ("%d (%.2f%%)" , kt .userRsaSize , float32 (kt .userRsaSize )/ float32 (kt .userSize )* 100 )},
63+ }
64+
65+ withoutKey := [][]string {
66+ {"users without keys" ,
67+ "" ,
68+ "" ,
69+ fmt .Sprintf ("%d (%.2f%%)" , kt .userWithoutKeySize , float32 (kt .userWithoutKeySize )/ float32 (kt .userSize )* 100 )},
70+ }
71+
72+ withMultipleKey := [][]string {{"users with multiple keys" ,
73+ "" ,
74+ "" ,
75+ fmt .Sprintf ("%d (%.2f%%)" , kt .userWithMultipleKeySize , float32 (kt .userWithMultipleKeySize )/ float32 (kt .userSize )* 100 )},
76+ }
77+
78+ strongKey := [][]string {
79+ {"users with strong keys" ,
80+ "" ,
81+ fmt .Sprintf ("%d (%.2f%%)" , kt .strongKeySize , float32 (kt .strongKeySize )/ float32 (kt .keySize )* 100 ),
82+ fmt .Sprintf ("%d (%.2f%%)" , kt .userWithStrongKeySize , float32 (kt .userWithStrongKeySize )/ float32 (kt .userWithKeySize )* 100 )},
83+ }
84+
85+ weakKey := [][]string {
86+ {"users with weak keys" ,
87+ "" ,
88+ fmt .Sprintf ("%d (%.2f%%)" , kt .weakKeySize , float32 (kt .weakKeySize )/ float32 (kt .keySize )* 100 ),
89+ fmt .Sprintf ("%d (%.2f%%)" , kt .userWithWeakKeySize , float32 (kt .userWithWeakKeySize )/ float32 (kt .userWithKeySize )* 100 )},
90+ }
91+
92+ t := tablewriter .NewWriter (os .Stdout )
93+ t .SetHeader ([]string {"description" , "key type" , "# of keys" , "# of users" })
94+ t .SetHeaderColor (tablewriter.Colors {tablewriter .FgCyanColor },
95+ tablewriter.Colors {tablewriter .FgCyanColor },
96+ tablewriter.Colors {tablewriter .FgCyanColor },
97+ tablewriter.Colors {tablewriter .FgCyanColor })
98+ t .SetFooter ([]string {"" , "total" , fmt .Sprintf ("%d" , kt .keySize ), fmt .Sprintf ("%d" , kt .userSize )})
99+ t .SetFooterColor (tablewriter.Colors {tablewriter .FgCyanColor },
100+ tablewriter.Colors {tablewriter .FgCyanColor },
101+ tablewriter.Colors {tablewriter .FgCyanColor },
102+ tablewriter.Colors {tablewriter .FgCyanColor })
103+ t .SetRowLine (true )
104+ t .AppendBulk (withKey )
105+ t .AppendBulk (withoutKey )
106+ t .AppendBulk (withMultipleKey )
107+ t .AppendBulk (strongKey )
108+ t .AppendBulk (weakKey )
109+ t .Render ()
110+
111+ if len (kt .userWithWeakKey ) > 0 {
112+ zap .S ().Info ("users with weak keys:" )
113+ for _ , m := range kt .userWithWeakKey {
114+ zap .S ().Infof ("%s" , m .Login )
115+ }
116+ }
25117}
26118
27- func printReport (ms []member ) {
119+ func generateKeyTable (ms []member ) keyTable {
28120 var wg sync.WaitGroup
29121
30- var (
31- keyDsaSize uint32
32- keyEddsaSize uint32
33- keyEd25519Size uint32
34- keyRsaSize uint32
35- userDsaSize uint32
36- userEddsaSize uint32
37- userEd25519Size uint32
38- userRsaSize uint32
39- userWithKeySize uint32
40- userWithoutKeySize uint32
41- userWithMultipleKeySize uint32
42- totalKeySize uint32
43- totalUserSize = len (ms )
44- )
122+ var kt keyTable
123+ kt .userSize = uint32 (len (ms ))
45124
46125 for _ , m := range ms {
47126 wg .Add (1 )
@@ -51,44 +130,68 @@ func printReport(ms []member) {
51130 defer wg .Done ()
52131
53132 var (
54- hasDsa bool
55- hasRsa bool
56- hasEddsa bool
57- hasEd25519 bool
133+ hasDsa bool
134+ hasEcdsa bool
135+ hasEd25519 bool
136+ hasRsa bool
137+ userHasStrongRsa bool
58138 )
59139
60140 for _ , key := range m .Keys {
61- atomic .AddUint32 (& totalKeySize , 1 )
141+ atomic .AddUint32 (& kt . keySize , 1 )
62142
63143 switch {
64144 case strings .Contains (key , "ssh-dsa" ):
65- atomic .AddUint32 (& keyDsaSize , 1 )
66145 hasDsa = true
67- case strings .Contains (key , "ssh-rsa" ):
68- atomic .AddUint32 (& keyRsaSize , 1 )
69- hasRsa = true
146+ atomic .AddUint32 (& kt .keyDsaSize , 1 )
147+ atomic .AddUint32 (& kt .weakKeySize , 1 )
70148 case strings .Contains (key , "ssh-eddsa" ):
71- atomic .AddUint32 (& keyEddsaSize , 1 )
72- hasEddsa = true
149+ hasEcdsa = true
150+ atomic .AddUint32 (& kt .keyEcdsaSize , 1 )
151+ atomic .AddUint32 (& kt .weakKeySize , 1 )
73152 case strings .Contains (key , "ssh-ed25519" ):
74- atomic .AddUint32 (& keyEd25519Size , 1 )
75153 hasEd25519 = true
154+ atomic .AddUint32 (& kt .keyEd25519Size , 1 )
155+ atomic .AddUint32 (& kt .strongKeySize , 1 )
156+ case strings .Contains (key , "ssh-rsa" ):
157+ hasRsa = true
158+ atomic .AddUint32 (& kt .keyRsaSize , 1 )
159+ if isRsaStrong (key ) {
160+ userHasStrongRsa = true
161+ atomic .AddUint32 (& kt .keyStrongRsaSize , 1 )
162+ atomic .AddUint32 (& kt .strongKeySize , 1 )
163+ } else {
164+ userHasStrongRsa = false
165+ atomic .AddUint32 (& kt .keyWeakRsaSize , 1 )
166+ atomic .AddUint32 (& kt .weakKeySize , 1 )
167+ }
76168 }
77169 }
78170
79171 switch {
80172 case hasDsa :
81- atomic .AddUint32 (& userDsaSize , 1 )
82- case hasRsa :
83- atomic .AddUint32 (& userRsaSize , 1 )
84- case hasEddsa :
85- atomic .AddUint32 (& userEddsaSize , 1 )
173+ atomic .AddUint32 (& kt .userDsaSize , 1 )
174+ atomic .AddUint32 (& kt .userWithWeakKeySize , 1 )
175+ kt .userWithWeakKey = append (kt .userWithWeakKey , m )
176+ case hasEcdsa :
177+ atomic .AddUint32 (& kt .userEcdsaSize , 1 )
178+ atomic .AddUint32 (& kt .userWithWeakKeySize , 1 )
179+ kt .userWithWeakKey = append (kt .userWithWeakKey , m )
86180 case hasEd25519 :
87- atomic .AddUint32 (& userEd25519Size , 1 )
181+ atomic .AddUint32 (& kt .userEd25519Size , 1 )
182+ atomic .AddUint32 (& kt .userWithStrongKeySize , 1 )
183+ case hasRsa :
184+ atomic .AddUint32 (& kt .userRsaSize , 1 )
185+ if userHasStrongRsa {
186+ atomic .AddUint32 (& kt .userWithStrongKeySize , 1 )
187+ } else {
188+ atomic .AddUint32 (& kt .userWithWeakKeySize , 1 )
189+ kt .userWithWeakKey = append (kt .userWithWeakKey , m )
190+ }
88191 }
89192
90193 if len (m .Keys ) == 0 {
91- atomic .AddUint32 (& userWithoutKeySize , 1 )
194+ atomic .AddUint32 (& kt . userWithoutKeySize , 1 )
92195 if * showUsers == "without" || * showUsers == "all" {
93196 zap .S ().Infow ("retrieved keys" ,
94197 "user" , m .Login ,
@@ -98,7 +201,7 @@ func printReport(ms []member) {
98201 }
99202
100203 if len (m .Keys ) > 0 {
101- atomic .AddUint32 (& userWithKeySize , 1 )
204+ atomic .AddUint32 (& kt . userWithKeySize , 1 )
102205 if * showUsers == "with" || * showUsers == "all" {
103206 zap .S ().Infow ("retrieved keys" ,
104207 "user" , m .Login ,
@@ -108,7 +211,7 @@ func printReport(ms []member) {
108211 }
109212
110213 if len (m .Keys ) > 1 {
111- atomic .AddUint32 (& userWithMultipleKeySize , 1 )
214+ atomic .AddUint32 (& kt . userWithMultipleKeySize , 1 )
112215 if * showUsers == "multiple" || * showUsers == "all" {
113216 zap .S ().Infow ("retrieved keys" ,
114217 "user" , m .Login ,
@@ -120,47 +223,13 @@ func printReport(ms []member) {
120223 }
121224 wg .Wait ()
122225
123- withKey := [][]string {
124- {"users with keys" , "DSA" ,
125- fmt .Sprintf ("%d (%.2f%%)" , keyDsaSize , float32 (keyDsaSize )/ float32 (totalKeySize )* 100 ),
126- fmt .Sprintf ("%d (%.2f%%)" , userDsaSize , float32 (userDsaSize )/ float32 (totalUserSize )* 100 )},
127- {"" , "RSA" ,
128- fmt .Sprintf ("%d (%.2f%%)" , keyRsaSize , float32 (keyRsaSize )/ float32 (totalKeySize )* 100 ),
129- fmt .Sprintf ("%d (%.2f%%)" , userRsaSize , float32 (userRsaSize )/ float32 (totalUserSize )* 100 )},
130- {"" , "ECDSA" ,
131- fmt .Sprintf ("%d (%.2f%%)" , keyEddsaSize , float32 (keyEddsaSize )/ float32 (totalKeySize )* 100 ),
132- fmt .Sprintf ("%d (%.2f%%)" , userEddsaSize , float32 (userEddsaSize )/ float32 (totalUserSize )* 100 )},
133- {"" , "Ed25519" ,
134- fmt .Sprintf ("%d (%.2f%%)" , keyEd25519Size , float32 (keyEd25519Size )/ float32 (totalKeySize )* 100 ),
135- fmt .Sprintf ("%d (%.2f%%)" , userEd25519Size , float32 (userEd25519Size )/ float32 (totalUserSize )* 100 )},
136- }
137-
138- withoutKey := [][]string {
139- {"users without keys" , "" , "" , fmt .Sprintf ("%d (%.2f%%)" , userWithoutKeySize , float32 (userWithoutKeySize )/ float32 (totalUserSize )* 100 )},
140- }
141-
142- withMultipleKey := [][]string {
143- {"users with multiple keys" , "" , "" , fmt .Sprintf ("%d (%.2f%%)" , userWithMultipleKeySize , float32 (userWithMultipleKeySize )/ float32 (totalUserSize )* 100 )},
144- }
226+ return kt
227+ }
145228
146- t := tablewriter .NewWriter (os .Stdout )
147- t .SetHeader ([]string {"description" , "key type" , "# of keys" , "# of users" })
148- t .SetHeaderColor (tablewriter.Colors {tablewriter .FgCyanColor },
149- tablewriter.Colors {tablewriter .FgCyanColor },
150- tablewriter.Colors {tablewriter .FgCyanColor },
151- tablewriter.Colors {tablewriter .FgCyanColor },
152- )
153- t .SetFooter ([]string {"" , "total" , fmt .Sprintf ("%d" , totalKeySize ), fmt .Sprintf ("%d" , totalUserSize )})
154- t .SetFooterColor (tablewriter.Colors {tablewriter .FgCyanColor },
155- tablewriter.Colors {tablewriter .FgCyanColor },
156- tablewriter.Colors {tablewriter .FgCyanColor },
157- tablewriter.Colors {tablewriter .FgCyanColor },
158- )
159- t .SetRowLine (true )
160- t .AppendBulk (withKey )
161- t .AppendBulk (withoutKey )
162- t .AppendBulk (withMultipleKey )
163- t .Render ()
229+ func isRsaStrong (key string ) bool {
230+ r := regexp .MustCompile (`(ssh-rsa) (.*)` )
231+ keyArray := r .FindStringSubmatch (key )
232+ return len (keyArray [2 ]) >= 372
164233}
165234
166235func getKeys (ms []member ) []member {
@@ -250,3 +319,7 @@ func getMembers() []member {
250319
251320 return members
252321}
322+
323+ func main () {
324+ printReport (generateKeyTable (getKeys (getMembers ())))
325+ }
0 commit comments