diff --git a/cmd/server/setup.go b/cmd/server/setup.go index f8a34ae0ae..5728a8b153 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -25,8 +25,8 @@ import ( "strings" "time" - "github.com/google/tink/go/subtle/random" "github.com/rs/zerolog/log" + "github.com/tink-crypto/tink-go/v2/subtle/random" "github.com/urfave/cli/v3" "go.woodpecker-ci.org/woodpecker/v3/server" diff --git a/go.mod b/go.mod index 7562be0a70..f4fe2fbbb3 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,6 @@ require ( github.com/go-viper/mapstructure/v2 v2.4.0 github.com/golang-jwt/jwt/v5 v5.3.0 github.com/google/go-github/v80 v80.0.0 - github.com/google/tink/go v1.7.0 github.com/hashicorp/go-hclog v1.6.3 github.com/hashicorp/go-plugin v1.7.0 github.com/jellydator/ttlcache/v3 v3.4.0 @@ -51,6 +50,7 @@ require ( github.com/swaggo/files v1.0.1 github.com/swaggo/gin-swagger v1.6.1 github.com/swaggo/swag v1.16.6 + github.com/tink-crypto/tink-go/v2 v2.5.0 github.com/urfave/cli-docs/v3 v3.1.1-0.20251022123016-72b87d11c482 github.com/urfave/cli/v3 v3.6.1 github.com/xeipuuv/gojsonschema v1.2.0 @@ -216,7 +216,6 @@ require ( golang.org/x/sys v0.39.0 // indirect golang.org/x/time v0.14.0 // indirect golang.org/x/tools v0.39.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index c5153ca3df..b90ba0705a 100644 --- a/go.sum +++ b/go.sum @@ -264,8 +264,6 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w= -github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -562,6 +560,8 @@ github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI= github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/tink-crypto/tink-go/v2 v2.5.0 h1:B8KLF6AofxdBIE4UJIaFbmoj5/1ehEtt7/MmzfI4Zpw= +github.com/tink-crypto/tink-go/v2 v2.5.0/go.mod h1:2WbBA6pfNsAfBwDCggboaHeB2X29wkU8XHtGwh2YIk8= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= diff --git a/server/api/login.go b/server/api/login.go index aaade3a4d3..ed777297f6 100644 --- a/server/api/login.go +++ b/server/api/login.go @@ -24,8 +24,8 @@ import ( "time" "github.com/gin-gonic/gin" - "github.com/google/tink/go/subtle/random" "github.com/rs/zerolog/log" + "github.com/tink-crypto/tink-go/v2/subtle/random" "go.woodpecker-ci.org/woodpecker/v3/server" "go.woodpecker-ci.org/woodpecker/v3/server/forge" diff --git a/server/api/repo.go b/server/api/repo.go index be109a043b..ef07bbb1d7 100644 --- a/server/api/repo.go +++ b/server/api/repo.go @@ -24,8 +24,8 @@ import ( "time" "github.com/gin-gonic/gin" - "github.com/google/tink/go/subtle/random" "github.com/rs/zerolog/log" + "github.com/tink-crypto/tink-go/v2/subtle/random" "go.woodpecker-ci.org/woodpecker/v3/server" "go.woodpecker-ci.org/woodpecker/v3/server/forge" diff --git a/server/api/user.go b/server/api/user.go index 9e048e6aa5..8d69d18914 100644 --- a/server/api/user.go +++ b/server/api/user.go @@ -20,8 +20,8 @@ import ( "strconv" "github.com/gin-gonic/gin" - "github.com/google/tink/go/subtle/random" "github.com/rs/zerolog/log" + "github.com/tink-crypto/tink-go/v2/subtle/random" "go.woodpecker-ci.org/woodpecker/v3/server" "go.woodpecker-ci.org/woodpecker/v3/server/model" diff --git a/server/api/users.go b/server/api/users.go index 414cae6519..872e95d1b4 100644 --- a/server/api/users.go +++ b/server/api/users.go @@ -22,7 +22,7 @@ import ( "strconv" "github.com/gin-gonic/gin" - "github.com/google/tink/go/subtle/random" + "github.com/tink-crypto/tink-go/v2/subtle/random" "go.woodpecker-ci.org/woodpecker/v3/server/model" "go.woodpecker-ci.org/woodpecker/v3/server/router/middleware/session" diff --git a/server/model/agent.go b/server/model/agent.go index 5e2fefb233..8390e349e8 100644 --- a/server/model/agent.go +++ b/server/model/agent.go @@ -18,7 +18,7 @@ import ( "encoding/base32" "fmt" - "github.com/google/tink/go/subtle/random" + "github.com/tink-crypto/tink-go/v2/subtle/random" "go.woodpecker-ci.org/woodpecker/v3/pipeline" ) diff --git a/server/services/encryption/aes.go b/server/services/encryption/aes.go index 00d6e3983b..e238779181 100644 --- a/server/services/encryption/aes.go +++ b/server/services/encryption/aes.go @@ -19,7 +19,7 @@ import ( "encoding/base64" "fmt" - "github.com/google/tink/go/subtle/random" + "github.com/tink-crypto/tink-go/v2/subtle/random" "go.woodpecker-ci.org/woodpecker/v3/server/services/encryption/types" "go.woodpecker-ci.org/woodpecker/v3/server/store" diff --git a/server/services/encryption/aes_test.go b/server/services/encryption/aes_test.go index 1a2bc5abb1..cd2eb995ce 100644 --- a/server/services/encryption/aes_test.go +++ b/server/services/encryption/aes_test.go @@ -15,10 +15,12 @@ package encryption import ( + "encoding/base64" "testing" - "github.com/google/tink/go/subtle/random" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tink-crypto/tink-go/v2/subtle/random" ) func TestShortMessageLongKey(t *testing.T) { @@ -48,3 +50,115 @@ func TestLongMessageShortKey(t *testing.T) { assert.NoError(t, err) assert.Equal(t, input, output) } + +func TestEncryptDecryptWithAssociatedData(t *testing.T) { + aes := &aesEncryptionService{} + err := aes.loadCipher(string(random.GetRandomBytes(32))) + require.NoError(t, err) + + plaintext := "secret-value-12345" + associatedData := "repo:123" + + ciphertext, err := aes.Encrypt(plaintext, associatedData) + require.NoError(t, err) + + // Decrypt with correct associated data should succeed + decrypted, err := aes.Decrypt(ciphertext, associatedData) + require.NoError(t, err) + assert.Equal(t, plaintext, decrypted) + + // Decrypt with wrong associated data should fail + _, err = aes.Decrypt(ciphertext, "repo:456") + assert.Error(t, err, "decryption should fail with wrong associated data") + + // Decrypt with empty associated data should fail + _, err = aes.Decrypt(ciphertext, "") + assert.Error(t, err, "decryption should fail with missing associated data") +} + +func TestEncryptProducesUniqueCiphertexts(t *testing.T) { + aes := &aesEncryptionService{} + err := aes.loadCipher(string(random.GetRandomBytes(32))) + require.NoError(t, err) + + plaintext := "same-message" + ciphertexts := make(map[string]bool) + + // Encrypt the same message multiple times + for range 100 { + ct, err := aes.Encrypt(plaintext, "") + require.NoError(t, err) + assert.False(t, ciphertexts[ct], "ciphertext should be unique due to random nonce") + ciphertexts[ct] = true + } +} + +func TestDecryptTamperedCiphertext(t *testing.T) { + aes := &aesEncryptionService{} + err := aes.loadCipher(string(random.GetRandomBytes(32))) + require.NoError(t, err) + + plaintext := "sensitive-data" + ciphertext, err := aes.Encrypt(plaintext, "") + require.NoError(t, err) + + // Decode, tamper, re-encode + decoded, err := base64.StdEncoding.DecodeString(ciphertext) + require.NoError(t, err) + + // Tamper with the ciphertext (flip a bit in the middle) + if len(decoded) > AES_GCM_SIV_NonceSize+1 { + decoded[AES_GCM_SIV_NonceSize+1] ^= 0xFF + } + tampered := base64.StdEncoding.EncodeToString(decoded) + + _, err = aes.Decrypt(tampered, "") + assert.Error(t, err, "decryption of tampered ciphertext should fail") +} + +func TestDecryptInvalidBase64(t *testing.T) { + aes := &aesEncryptionService{} + err := aes.loadCipher(string(random.GetRandomBytes(32))) + require.NoError(t, err) + + _, err = aes.Decrypt("not-valid-base64!!!", "") + assert.Error(t, err, "decryption of invalid base64 should fail") +} + +func TestDecryptTruncatedCiphertext(t *testing.T) { + aes := &aesEncryptionService{} + err := aes.loadCipher(string(random.GetRandomBytes(32))) + require.NoError(t, err) + + plaintext := "test-message" + ciphertext, err := aes.Encrypt(plaintext, "") + require.NoError(t, err) + + // Truncate the ciphertext + decoded, err := base64.StdEncoding.DecodeString(ciphertext) + require.NoError(t, err) + + truncated := base64.StdEncoding.EncodeToString(decoded[:len(decoded)/2]) + _, err = aes.Decrypt(truncated, "") + assert.Error(t, err, "decryption of truncated ciphertext should fail") +} + +func TestRandomBytesUniqueness(t *testing.T) { + seen := make(map[string]bool) + + for range 1000 { + bytes := random.GetRandomBytes(32) + key := string(bytes) + assert.False(t, seen[key], "random bytes should be unique") + seen[key] = true + } +} + +func TestRandomBytesLength(t *testing.T) { + tests := []uint32{1, 12, 16, 32, 64, 128, 256} + + for _, length := range tests { + bytes := random.GetRandomBytes(length) + assert.Len(t, bytes, int(length), "random bytes should have requested length") + } +} diff --git a/server/services/encryption/tink.go b/server/services/encryption/tink.go index 033315be7b..0b59a993c4 100644 --- a/server/services/encryption/tink.go +++ b/server/services/encryption/tink.go @@ -19,7 +19,7 @@ import ( "fmt" "github.com/fsnotify/fsnotify" - "github.com/google/tink/go/tink" + "github.com/tink-crypto/tink-go/v2/tink" "go.woodpecker-ci.org/woodpecker/v3/server/services/encryption/types" "go.woodpecker-ci.org/woodpecker/v3/server/store" diff --git a/server/services/encryption/tink_keyset.go b/server/services/encryption/tink_keyset.go index a3e7ae4b36..0b989e91a2 100644 --- a/server/services/encryption/tink_keyset.go +++ b/server/services/encryption/tink_keyset.go @@ -20,10 +20,10 @@ import ( "os" "strconv" - "github.com/google/tink/go/aead" - insecure_clear_text_keyset "github.com/google/tink/go/insecurecleartextkeyset" - "github.com/google/tink/go/keyset" "github.com/rs/zerolog/log" + "github.com/tink-crypto/tink-go/v2/aead" + insecure_clear_text_keyset "github.com/tink-crypto/tink-go/v2/insecurecleartextkeyset" + "github.com/tink-crypto/tink-go/v2/keyset" "go.woodpecker-ci.org/woodpecker/v3/server/store/types" )