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
 5package ssh
 6
 7// Message authentication support
 8
 9import (
10	"crypto/fips140"
11	"crypto/hmac"
12	"crypto/sha1"
13	"crypto/sha256"
14	"crypto/sha512"
15	"hash"
16	"slices"
17)
18
19type macMode struct {
20	keySize int
21	etm     bool
22	new     func(key []byte) hash.Hash
23}
24
25// truncatingMAC wraps around a hash.Hash and truncates the output digest to
26// a given size.
27type truncatingMAC struct {
28	length int
29	hmac   hash.Hash
30}
31
32func (t truncatingMAC) Write(data []byte) (int, error) {
33	return t.hmac.Write(data)
34}
35
36func (t truncatingMAC) Sum(in []byte) []byte {
37	out := t.hmac.Sum(in)
38	return out[:len(in)+t.length]
39}
40
41func (t truncatingMAC) Reset() {
42	t.hmac.Reset()
43}
44
45func (t truncatingMAC) Size() int {
46	return t.length
47}
48
49func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
50
51// macModes defines the supported MACs. MACs not included are not supported
52// and will not be negotiated, even if explicitly configured. When FIPS mode is
53// enabled, only FIPS-approved algorithms are included.
54var macModes = map[string]*macMode{}
55
56func init() {
57	macModes[HMACSHA512ETM] = &macMode{64, true, func(key []byte) hash.Hash {
58		return hmac.New(sha512.New, key)
59	}}
60	macModes[HMACSHA256ETM] = &macMode{32, true, func(key []byte) hash.Hash {
61		return hmac.New(sha256.New, key)
62	}}
63	macModes[HMACSHA512] = &macMode{64, false, func(key []byte) hash.Hash {
64		return hmac.New(sha512.New, key)
65	}}
66	macModes[HMACSHA256] = &macMode{32, false, func(key []byte) hash.Hash {
67		return hmac.New(sha256.New, key)
68	}}
69
70	if fips140.Enabled() {
71		defaultMACs = slices.DeleteFunc(defaultMACs, func(algo string) bool {
72			_, ok := macModes[algo]
73			return !ok
74		})
75		return
76	}
77
78	macModes[HMACSHA1] = &macMode{20, false, func(key []byte) hash.Hash {
79		return hmac.New(sha1.New, key)
80	}}
81	macModes[InsecureHMACSHA196] = &macMode{20, false, func(key []byte) hash.Hash {
82		return truncatingMAC{12, hmac.New(sha1.New, key)}
83	}}
84}