From c9f5d617ba7d4fe7a33f7e57ca70fc28c9b491b4 Mon Sep 17 00:00:00 2001 From: Simon Bein Date: Mon, 5 May 2025 11:54:29 +0200 Subject: [PATCH 1/2] add unit-test for K8sNameHash On-behalf-of: SAP Signed-off-by: Simon Bein --- pkg/controller/utils_test.go | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 pkg/controller/utils_test.go diff --git a/pkg/controller/utils_test.go b/pkg/controller/utils_test.go new file mode 100644 index 0000000..14b2b28 --- /dev/null +++ b/pkg/controller/utils_test.go @@ -0,0 +1,50 @@ +package controller + +import ( + "fmt" + "testing" + + "k8s.io/apimachinery/pkg/util/validation" +) + +func TestK8sNameHash(t *testing.T) { + tt := []struct { + input []string + expHash string + }{ + { + []string{"test1"}, + "wrckybtbh7enmn4vx2nnbpvpkuarsnvm", + }, + { + // check that the same string produces the same hash + []string{"test1"}, + "wrckybtbh7enmn4vx2nnbpvpkuarsnvm", + }, + { + []string{"bla"}, + "76tha37scj5hjglta4tvn6b4kmxeh3ic", + }, + { + []string{"some other test", "this is a very, very long string"}, + "fkkzqgh27xym6tqbswyql3wy4atsf6pt", + }, + } + + for _, tc := range tt { + t.Run(fmt.Sprint(tc.input), func(t *testing.T) { + res := K8sNameHash(tc.input...) + + if res != tc.expHash { + t.Errorf("exp hash %q, got %q", tc.expHash, res) + } + + // ensure the result is a valid DNS1123Subdomain + if errs := validation.IsDNS1123Subdomain(res); errs != nil { + t.Errorf("value %q is invalid: %v", res, errs) + } + + }) + } + +} From c81eae93074d921d826467f65de780ead0952748 Mon Sep 17 00:00:00 2001 From: Simon Bein Date: Mon, 5 May 2025 11:57:03 +0200 Subject: [PATCH 2/2] use fips-compliant sha256 hash On-behalf-of: SAP Signed-off-by: Simon Bein --- pkg/controller/utils.go | 11 ++++++----- pkg/controller/utils_test.go | 8 ++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/pkg/controller/utils.go b/pkg/controller/utils.go index f9c1f45..44423a5 100644 --- a/pkg/controller/utils.go +++ b/pkg/controller/utils.go @@ -1,7 +1,7 @@ package controller import ( - "crypto/sha1" + "crypto/sha256" "encoding/base32" "reflect" "strings" @@ -10,15 +10,16 @@ import ( ) const ( - maxLength int = 63 - Base32EncodeStdLowerCase = "abcdefghijklmnopqrstuvwxyz234567" + Base32EncodeStdLowerCase = "abcdefghijklmnopqrstuvwxyz234567" ) -// K8sNameHash takes any number of string arguments and computes a hash out of it, which is then base32-encoded to be a valid k8s resource name. +// K8sNameHash takes any number of string arguments and computes a hash out of it, which is then base32-encoded to be a valid DNS1123Subdomain k8s resource name // The arguments are joined with '/' before being hashed. func K8sNameHash(ids ...string) string { name := strings.Join(ids, "/") - h := sha1.New() + // since we are not worried about length-extension attacks (in fact we are not even using hashing for + // any security purposes), use sha2 for better performance compared to sha3 + h := sha256.New() _, _ = h.Write([]byte(name)) // we need base32 encoding as some base64 (even url safe base64) characters are not supported by k8s // see https://kubernetes.io/docs/concepts/overview/working-with-objects/names/ diff --git a/pkg/controller/utils_test.go b/pkg/controller/utils_test.go index 14b2b28..431615b 100644 --- a/pkg/controller/utils_test.go +++ b/pkg/controller/utils_test.go @@ -14,20 +14,20 @@ func TestK8sNameHash(t *testing.T) { }{ { []string{"test1"}, - "wrckybtbh7enmn4vx2nnbpvpkuarsnvm", + "dnhq5gcrs4mzrzzsa6cujsllg3b5ahhn67fkgmrvtvxr3a2woaka", }, { // check that the same string produces the same hash []string{"test1"}, - "wrckybtbh7enmn4vx2nnbpvpkuarsnvm", + "dnhq5gcrs4mzrzzsa6cujsllg3b5ahhn67fkgmrvtvxr3a2woaka", }, { []string{"bla"}, - "76tha37scj5hjglta4tvn6b4kmxeh3ic", + "jxz4h5upzsb3e7u5ileqimnhesm7c6dvzanftg2wnsmitoljm4bq", }, { []string{"some other test", "this is a very, very long string"}, - "fkkzqgh27xym6tqbswyql3wy4atsf6pt", + "rjphpfjbmwn6qqydv6xhtmj3kxrlzepn2tpwy4okw2ypoc3nlffq", }, }