From b7b140e8856cc19f9976fe305c188c12a81cd9fe Mon Sep 17 00:00:00 2001 From: Louis Cailliot <108886762+IceManGreen@users.noreply.github.com> Date: Fri, 2 Aug 2024 17:12:58 +0200 Subject: [PATCH] feature: support for aes-cbc then hmac direct enc (#17) --- .github/ISSUE_TEMPLATE/bug_report.md | 32 +++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++ .github/pull_request_template.md | 34 ++++ .gitignore | 34 +++- LICENCE.txt | 2 +- README.md | 12 +- aes_cbc_cryptor.go | 92 +++++++++ aes_cbc_cryptor_test.go | 116 +++++++++++ aes_gcm_cryptor.go | 8 +- aes_gcm_cryptor_test.go | 4 +- asymmetric_decryption_key_store.go | 21 ++ asymmetric_decryption_key_store_test.go | 2 +- common_test.go | 40 ++++ config.json | 5 + ec_verifier_test.go | 4 +- ecdsa_signer.go | 4 +- ecdsa_signer_test.go | 4 +- ecdsa_verifier.go | 4 +- errors.go | 2 +- examples/jwe/jwe.go | 10 +- examples/jwt/jwt.go | 6 +- go.mod | 24 ++- go.sum | 36 ++-- helpers.go | 22 ++- helpers_test.go | 15 +- hmac_sha_cryptor.go | 60 ++++++ hmac_sha_cryptor_test.go | 51 +++++ hsm/asymmetric_decryption_key.go | 6 +- hsm/asymmetric_decryption_key_store.go | 4 +- integration_test.go | 4 +- interfaces.go | 38 +++- jose/jwe.go | 182 +++++++++++++++++- jose/jwk.go | 2 +- jose/jwk_test.go | 2 +- jose/jwks.go | 2 +- jose/jwks_test.go | 2 +- jose/jws.go | 2 +- jose/jws_test.go | 2 +- jose/jwt.go | 2 +- jose/jwt_test.go | 2 +- jose/types.go | 19 +- jose/types_test.go | 2 +- ...cryptor.go => jwe_direct_decryptor_aead.go | 26 +-- ...st.go => jwe_direct_decryptor_aead_test.go | 24 +-- jwe_direct_decryptor_block.go | 96 +++++++++ ...cryptor.go => jwe_direct_encryptor_aead.go | 22 +-- ...st.go => jwe_direct_encryptor_aead_test.go | 12 +- jwe_direct_encryptor_block.go | 107 ++++++++++ jwe_direct_encryptor_block_test.go | 113 +++++++++++ jwe_hmac_verifier.go | 68 +++++++ jwe_hmac_verifier_test.go | 25 +++ jwe_key_encryption_decryptor.go | 23 ++- jwe_key_encryption_decryptor_test.go | 2 +- jwe_key_encryption_encryptor.go | 25 ++- jwe_key_encryption_encryptor_test.go | 2 +- jwks_truststore.go | 4 +- jwks_truststore_test.go | 4 +- jwt_signer.go | 4 +- jwt_signer_test.go | 4 +- jwt_verifier.go | 4 +- jwt_verifier_test.go | 4 +- key_generator.go | 6 +- key_generator_test.go | 4 +- keystore.go | 4 +- keystore_test.go | 4 +- rsa_private.go | 23 ++- rsa_private_test.go | 2 +- rsa_public.go | 23 ++- rsa_public_test.go | 4 +- signer.go | 4 +- signer_test.go | 4 +- verifier.go | 4 +- verifier_test.go | 4 +- 73 files changed, 1423 insertions(+), 167 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/pull_request_template.md create mode 100644 aes_cbc_cryptor.go create mode 100644 aes_cbc_cryptor_test.go create mode 100644 common_test.go create mode 100644 config.json create mode 100644 hmac_sha_cryptor.go create mode 100644 hmac_sha_cryptor_test.go rename jwe_direct_decryptor.go => jwe_direct_decryptor_aead.go (74%) rename jwe_direct_decryptor_test.go => jwe_direct_decryptor_aead_test.go (90%) create mode 100644 jwe_direct_decryptor_block.go rename jwe_direct_encryptor.go => jwe_direct_encryptor_aead.go (79%) rename jwe_direct_encryptor_test.go => jwe_direct_encryptor_aead_test.go (92%) create mode 100644 jwe_direct_encryptor_block.go create mode 100644 jwe_direct_encryptor_block_test.go create mode 100644 jwe_hmac_verifier.go create mode 100644 jwe_hmac_verifier_test.go diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..72f9a7f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,32 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "[BUG]" +labels: bug +assignees: '' + +--- + +## Describe the bug +> A clear and concise description of what the bug is. + +## How To Reproduce +> Steps to reproduce the behavior: +> 1. Go to '...' +> 2. Click on '....' +> 3. Scroll down to '....' +> 4. See error + +## Expected behavior +> A clear and concise description of what you expected to happen. + +## Logs or Screenshots +> If applicable, add screenshots to help explain your problem. + +## Desktop (please complete the following information): +> - OS: [e.g. iOS] +> - Browser [e.g. chrome, safari] +> - Version [e.g. 22] + +## Additional context +> Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..cfbbcd6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "[NEW]" +labels: enhancement +assignees: '' + +--- + +## Is your feature request related to a problem? Please describe. +> A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +## Describe the solution you'd like +> A clear and concise description of what you want to happen. + +## Describe alternatives you've considered +> A clear and concise description of any alternative solutions or features you've considered. + +## Additional context +> Add any other context or screenshots about the feature request here. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..4fc0499 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,34 @@ + + +#### Proposed Changes #### + + + +#### Types of Changes #### + + + +#### Verification #### + + + +#### Testing #### + + + +#### Linked Issues #### + + + +#### User-Facing Change #### + +```release-note + +``` + +#### Further Comments #### + + diff --git a/.gitignore b/.gitignore index 4b1fcb0..627eac7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,34 @@ -/.idea/ +# IntelliJ project files +.idea +*.iml +out +gen +build/ +.DS_Store +generated/ +deployed.json +.socket coverage.out + +### Go template +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +vendor/ + +# Go workspace file +go.work diff --git a/LICENCE.txt b/LICENCE.txt index a2056f7..f75906f 100644 --- a/LICENCE.txt +++ b/LICENCE.txt @@ -1,6 +1,6 @@ MIT License. -Copyright 2019 Thales e-Security, Inc +Copyright 2024 Thales Group Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index b5690c5..6ef4834 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.com/ThalesIgnite/gose.svg?branch=master)](https://travis-ci.com/ThalesIgnite/gose) + # GOSE - JOSE and friends for the Go developer ## Overview @@ -7,6 +7,9 @@ GOSE is JOSE/JWT/JWK/JWS/JWKS implemented in Go with Helpers, and examples. It contains implementations of the JOSE suite of types and helpers for many different use cases. +## Known Issues + +* Direct encryption with AEAD mechanisms is not completely following [RFC 7516](https://tools.ietf.org/html/rfc7516) ## Mission @@ -20,6 +23,11 @@ It contains implementations of the JOSE suite of types and helpers for many diff Examples are provided under the `/examples` folder to illustrate correct use of this package. +## Vulnerability check +```sh +$ govulncheck ./... ─╯ +Scanning your code and 139 packages across 9 dependent modules for known vulnerabilities... - +No vulnerabilities found. +``` diff --git a/aes_cbc_cryptor.go b/aes_cbc_cryptor.go new file mode 100644 index 0000000..32a892e --- /dev/null +++ b/aes_cbc_cryptor.go @@ -0,0 +1,92 @@ +// Copyright 2024 Thales Group +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package gose + +import ( + "crypto/cipher" + "github.com/ThalesGroup/gose/jose" +) + +// AesCbcCryptor provides AES CBC encryption and decryption functions. +// It implements BlockEcryptionKey +type AesCbcCryptor struct { + kid string + alg jose.Alg + blockCipher cipher.BlockMode +} + +// NewAesCbcCryptor create a new instance of an AesCbcCryptor from the supplied parameters. +// It implements AeadEncryptionKey +func NewAesCbcCryptor(blockCipher cipher.BlockMode, kid string, alg jose.Alg) BlockEncryptionKey { + return &AesCbcCryptor{ + kid: kid, + alg: alg, + blockCipher: blockCipher, + } +} + +func (cryptor *AesCbcCryptor) trimSize(input []byte) (res []byte) { + blockSize := cryptor.blockCipher.BlockSize() + if len(input) % blockSize != 0 { + multiplier := len(input) / blockSize + res = make([]byte, (multiplier + 1)*blockSize) + copy(res, input) + return + } + return input +} + +func (cryptor *AesCbcCryptor) Kid() string { + return cryptor.kid +} + +func (cryptor *AesCbcCryptor) Algorithm() jose.Alg { + return cryptor.alg +} + +func getDestinationSize(inputLength int, blockSize int) int { + var finalSize int + if multiplier := inputLength / blockSize; multiplier > 0 { + finalSize = multiplier*blockSize + blockSize + } else { + finalSize = blockSize + } + return finalSize +} + +func (cryptor *AesCbcCryptor) Seal(plaintext []byte) []byte { + src := cryptor.trimSize(plaintext) + dstSize := getDestinationSize(len(plaintext), cryptor.blockCipher.BlockSize()) + dst := make([]byte, dstSize) + cryptor.blockCipher.CryptBlocks(dst, src) + return dst +} + +func (cryptor *AesCbcCryptor) Open(ciphertext []byte) []byte { + dstSize := getDestinationSize(len(ciphertext), cryptor.blockCipher.BlockSize()) + dst := make([]byte, dstSize) + cryptor.blockCipher.CryptBlocks(dst, ciphertext) + return dst +} + + + diff --git a/aes_cbc_cryptor_test.go b/aes_cbc_cryptor_test.go new file mode 100644 index 0000000..ec2653c --- /dev/null +++ b/aes_cbc_cryptor_test.go @@ -0,0 +1,116 @@ +// Copyright 2024 Thales Group +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package gose + +import ( + "crypto/rand" + "github.com/ThalesGroup/gose/jose" + "github.com/stretchr/testify/require" + "testing" +) + + + +func TestAesCbcCryptor(t *testing.T) { + var err error + iv := make([]byte, 16) + _, err = rand.Read(iv) + require.NoError(t, err) + + expectedKid := "aes0" + expectedAlg := jose.AlgA256CBC + + // mocking the block mode cipher + mc1 := &MockBlockMode{} + mc1.On("BlockSize").Return(len(iv)) + require.NoError(t, err) + c1 := NewAesCbcCryptor(mc1, expectedKid, expectedAlg) + + t.Run("testKid", func(t *testing.T) { + testKid(t, expectedKid, c1) + }) + + t.Run("testAlgorithm", func(t *testing.T) { + testAlgorithm(t, expectedAlg, c1) + }) + + t.Run("testSeal", func(t *testing.T) { + // mocking the block mode cipher for encryption + mc2 := &MockBlockMode{ + mode: ModeEncrypt, + } + mc2.On("BlockSize").Return(len(iv)) + require.NoError(t, err) + c2 := NewAesCbcCryptor(mc2, expectedKid, expectedAlg) + testSeal(t, c2) + }) + + t.Run("testOpen", func(t *testing.T) { + // mocking the block mode cipher for decryption + mc3 := &MockBlockMode{ + mode: ModeDecrypt, + } + mc3.On("BlockSize").Return(len(iv)) + require.NoError(t, err) + c3 := NewAesCbcCryptor(mc3, expectedKid, expectedAlg) + testOpen(t, c3) + }) +} + + +func testKid(t *testing.T, expectedKid string, cryptor BlockEncryptionKey){ + kid := cryptor.Kid() + require.Equal(t, expectedKid, kid) +} + +func testAlgorithm(t *testing.T, expectedAlg jose.Alg, cryptor BlockEncryptionKey){ + alg := cryptor.Algorithm() + require.Equal(t, expectedAlg, alg) +} + +func testSeal(t *testing.T, cryptor BlockEncryptionKey){ + small := []byte("ping") + cSmall := cryptor.Seal(small) + require.Equal(t, 0, len(cSmall)%16) + require.NotEqual(t, small, cSmall) + require.Contains(t, string(cSmall), mockExpectedCiphertext) + + big := []byte("pingpingpingpingpingpingpingpingpingping") + cBig := cryptor.Seal(big) + require.Equal(t, 0, len(cBig)%16) + require.NotEqual(t, big, cBig) + require.Contains(t, string(cBig), mockExpectedCiphertext) +} + +func testOpen(t *testing.T, cryptor BlockEncryptionKey){ + small := []byte("ping") + cSmall := cryptor.Open(small) + require.Equal(t, 0, len(cSmall)%16) + require.NotEqual(t, small, cSmall) + require.Contains(t, string(cSmall), mockExpectedCleartext) + + big := []byte("pingpingpingpingpingpingpingpingpingping") + cBig := cryptor.Open(big) + require.Equal(t, 0, len(cBig)%16) + require.NotEqual(t, big, cBig) + require.Contains(t, string(cBig), mockExpectedCleartext) +} diff --git a/aes_gcm_cryptor.go b/aes_gcm_cryptor.go index dcceb60..186c3f1 100644 --- a/aes_gcm_cryptor.go +++ b/aes_gcm_cryptor.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -26,7 +26,7 @@ import ( "crypto/rand" "io" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" ) var validEncryptionOpts = []jose.KeyOps{jose.KeyOpsEncrypt} @@ -105,7 +105,7 @@ func (cryptor *AesGcmCryptor) Seal(operation jose.KeyOps, nonce, plaintext, aad } // NewAesGcmCryptorFromJwk create a new instance of an AesGCmCryptor from a JWK. -func NewAesGcmCryptorFromJwk(jwk jose.Jwk, required []jose.KeyOps) (AuthenticatedEncryptionKey, error) { +func NewAesGcmCryptorFromJwk(jwk jose.Jwk, required []jose.KeyOps) (AeadEncryptionKey, error) { /* Check jwk can be used to encrypt or decrypt */ ops := intersection(validCryptorOpts, jwk.Ops()) if len(ops) == 0 { @@ -126,7 +126,7 @@ func NewAesGcmCryptorFromJwk(jwk jose.Jwk, required []jose.KeyOps) (Authenticate } // NewAesGcmCryptor create a new instance of an AesGCmCryptor from the supplied parameters. -func NewAesGcmCryptor(aead cipher.AEAD, rng io.Reader, kid string, alg jose.Alg, operations []jose.KeyOps) (AuthenticatedEncryptionKey, error) { +func NewAesGcmCryptor(aead cipher.AEAD, rng io.Reader, kid string, alg jose.Alg, operations []jose.KeyOps) (AeadEncryptionKey, error) { return &AesGcmCryptor{ kid: kid, alg: alg, diff --git a/aes_gcm_cryptor_test.go b/aes_gcm_cryptor_test.go index 25a245f..76da7a5 100644 --- a/aes_gcm_cryptor_test.go +++ b/aes_gcm_cryptor_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -25,7 +25,7 @@ import ( "crypto/rand" "testing" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/asymmetric_decryption_key_store.go b/asymmetric_decryption_key_store.go index 6fec6ab..970e12a 100644 --- a/asymmetric_decryption_key_store.go +++ b/asymmetric_decryption_key_store.go @@ -1,3 +1,24 @@ +// Copyright 2024 Thales Group +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + package gose // AsymmetricDecryptionKeyStoreImpl implements the AsymmetricDecryptionKeyStore interface providing AsymmetricDecryptionKey diff --git a/asymmetric_decryption_key_store_test.go b/asymmetric_decryption_key_store_test.go index b181b5d..7d37ed3 100644 --- a/asymmetric_decryption_key_store_test.go +++ b/asymmetric_decryption_key_store_test.go @@ -1,7 +1,7 @@ package gose import ( - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "testing" diff --git a/common_test.go b/common_test.go new file mode 100644 index 0000000..fc9b7e9 --- /dev/null +++ b/common_test.go @@ -0,0 +1,40 @@ +package gose + +import ( + "github.com/stretchr/testify/mock" +) + +const ( + ModeEncrypt = iota // blockModeCloser is in encrypt mode + ModeDecrypt // blockModeCloser is in decrypt mode + +) + +const ( + mockExpectedCleartext = "decrypted" + mockExpectedCiphertext = "encrypted" +) + +type MockBlockMode struct { + mock.Mock + mode int +} + +func (mbm *MockBlockMode) BlockSize() int { + args := mbm.Called() + return args.Get(0).(int) +} + +// In order to simulate a behavior tangible for tests, i.e encrypt or decrypt according to the mode, we simply return a +// string that inform us if we properly were in the encrypt or decrypt mode +func (mbm *MockBlockMode) CryptBlocks(dst, src []byte) { + switch mbm.mode { + case ModeDecrypt: + copy(dst, mockExpectedCleartext) + case ModeEncrypt: + + copy(dst, mockExpectedCiphertext) + default: + panic("unexpected mode") + } +} diff --git a/config.json b/config.json new file mode 100644 index 0000000..fb6e592 --- /dev/null +++ b/config.json @@ -0,0 +1,5 @@ +{ + "Path" : "/usr/lib/softhsm/libsofthsm2.so", + "TokenLabel": "token1", + "Pin": "mypin" +} \ No newline at end of file diff --git a/ec_verifier_test.go b/ec_verifier_test.go index 3b53b63..0ebc21a 100644 --- a/ec_verifier_test.go +++ b/ec_verifier_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -29,7 +29,7 @@ import ( "encoding/pem" "testing" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/ecdsa_signer.go b/ecdsa_signer.go index 48ac4f7..356c2dc 100644 --- a/ecdsa_signer.go +++ b/ecdsa_signer.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -29,7 +29,7 @@ import ( "crypto/rand" "crypto/x509" "encoding/pem" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "math/big" ) diff --git a/ecdsa_signer_test.go b/ecdsa_signer_test.go index 6a9b1e3..852c842 100644 --- a/ecdsa_signer_test.go +++ b/ecdsa_signer_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -30,7 +30,7 @@ import ( "encoding/pem" "testing" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/ecdsa_verifier.go b/ecdsa_verifier.go index f2228d9..b1d2182 100644 --- a/ecdsa_verifier.go +++ b/ecdsa_verifier.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -28,7 +28,7 @@ import ( "encoding/pem" "math/big" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/sirupsen/logrus" ) diff --git a/errors.go b/errors.go index 8f609f7..dfcafa0 100644 --- a/errors.go +++ b/errors.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the diff --git a/examples/jwe/jwe.go b/examples/jwe/jwe.go index 395bf53..1dbfeb9 100644 --- a/examples/jwe/jwe.go +++ b/examples/jwe/jwe.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -23,8 +23,8 @@ package main import ( "fmt" - "github.com/ThalesIgnite/gose" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose" + "github.com/ThalesGroup/gose/jose" "os" ) @@ -57,7 +57,7 @@ func main() { fmt.Printf("Created encryption key JWK: %s\n", marshalled) // Create an encryptor using our key. - encryptor := gose.NewJweDirectEncryptorImpl(key, false) + encryptor := gose.NewJweDirectEncryptorAead(key, false) // Our encryptor accepts both secret data ti be encrypted as well as additional data to be included in the JWE as an // authenticated and non-repudiable value. The aad value is included in the JWE header in the _thales_aad field. @@ -72,7 +72,7 @@ func main() { if err != nil { fail(err) } - decryptor := gose.NewJweDirectDecryptorImpl([]gose.AuthenticatedEncryptionKey{key}) + decryptor := gose.NewJweDirectDecryptorAeadImpl([]gose.AeadEncryptionKey{key}) // Decrypt a JWE blob verifying it's authenticity in the process. plaintext, aad, err := decryptor.Decrypt(jwe) diff --git a/examples/jwt/jwt.go b/examples/jwt/jwt.go index 505c046..5de0694 100644 --- a/examples/jwt/jwt.go +++ b/examples/jwt/jwt.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -25,8 +25,8 @@ import ( "encoding/json" "errors" "fmt" - "github.com/ThalesIgnite/gose" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose" + "github.com/ThalesGroup/gose/jose" "os" "time" ) diff --git a/go.mod b/go.mod index 1b71473..6508ab4 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,21 @@ -module github.com/ThalesIgnite/gose +module github.com/ThalesGroup/gose require ( - github.com/ThalesIgnite/crypto11 v1.2.3 - github.com/google/uuid v1.1.2 - github.com/sirupsen/logrus v1.7.0 - github.com/stretchr/testify v1.3.0 - golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd // indirect + github.com/ThalesGroup/crypto11 v1.2.6 + github.com/google/uuid v1.5.0 + github.com/sirupsen/logrus v1.9.3 + github.com/stretchr/testify v1.7.0 ) -go 1.13 +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/miekg/pkcs11 v1.1.1 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/objx v0.1.0 // indirect + github.com/thales-e-security/pool v0.0.2 // indirect + golang.org/x/sys v0.16.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect +) + +go 1.21.6 diff --git a/go.sum b/go.sum index 07f3601..8632374 100644 --- a/go.sum +++ b/go.sum @@ -1,26 +1,28 @@ -github.com/ThalesIgnite/crypto11 v1.2.3 h1:yZq53pQfwUxUNU2K5syfwTVN5dFpnr/oUPueo4uLRUc= -github.com/ThalesIgnite/crypto11 v1.2.3/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/ThalesGroup/crypto11 v1.2.6 h1:KixeJpVw3Y9gLSsz393XHh/Pez7q+KBXit4TQebmOz4= +github.com/ThalesGroup/crypto11 v1.2.6/go.mod h1:Grol7G+6zQdI94hGq+j702L1QFHSlJA5lBLl8uWAhG0= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f h1:eVB9ELsoq5ouItQBr5Tj334bhPJG/MX+m7rTchmzVUQ= -github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= +github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg= github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers.go b/helpers.go index f6bdb6f..6e69715 100644 --- a/helpers.go +++ b/helpers.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -42,7 +42,7 @@ import ( "encoding/json" "log" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" ) const ( @@ -370,7 +370,7 @@ func JwkToString(jwk jose.Jwk) (string, error) { return string(b), nil } -func base64EncodeInt32(val uint32) string { +func base64EncodeUInt32(val uint32) string { var buf bytes.Buffer if err := binary.Write(&buf, binary.BigEndian, &val); err != nil { log.Panicf("%s", err) @@ -378,6 +378,22 @@ func base64EncodeInt32(val uint32) string { return base64.RawURLEncoding.EncodeToString(buf.Bytes()) } +func uintToBytesBigEndian(val uint64) []byte { + var buf bytes.Buffer + if err := binary.Write(&buf, binary.BigEndian, &val); err != nil { + log.Panicf("%s", err) + } + return buf.Bytes() +} + +func concatByteArrays(slices [][]byte) []byte { + var tmp []byte + for _, s := range slices { + tmp = append(tmp, s...) + } + return tmp +} + //JwkFromPrivateKey builds JWK, from a crypto.Signer, with certificates, and scoped to certain operations, or errors func JwkFromPrivateKey(privateKey crypto.Signer, operations []jose.KeyOps, certs []*x509.Certificate) (jose.Jwk, error) { var jwk jose.Jwk diff --git a/helpers_test.go b/helpers_test.go index b2acc7f..7457f7a 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -25,11 +25,12 @@ import ( "crypto/cipher" "crypto/rand" "crypto/rsa" + "encoding/binary" "math/big" "regexp" "testing" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -410,3 +411,13 @@ func TestJwtToString(t *testing.T) { }) } } + +func TestUintToBytesBigEndian(t *testing.T) { + var val1 uint64 + val1 = 42 + be1 := uintToBytesBigEndian(val1) + require.NotEmpty(t, be1) + + val2 := binary.BigEndian.Uint64(be1) + require.Equal(t, val1, val2) +} diff --git a/hmac_sha_cryptor.go b/hmac_sha_cryptor.go new file mode 100644 index 0000000..f99d6b1 --- /dev/null +++ b/hmac_sha_cryptor.go @@ -0,0 +1,60 @@ +// Copyright 2024 Thales Group +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package gose + +import ( + "hash" +) + +// HmacShaCryptor provides HMAC SHA functions. +// It implements the HmacKey interface. +// The hash SHA mechanism is held directly by the key corresponding to the key id (kid). +// It means that if the key provides SHA-256 mechanism, then the Hash is SHA-256 +type HmacShaCryptor struct { + kid string + hash hash.Hash +} + +func (h HmacShaCryptor) Kid() string { + return h.kid +} + +// Hash returns the result from the SHA operation executed by the provided key +func (h HmacShaCryptor) Hash(input []byte) []byte { + // preprocess the size of the final output + outputSize := h.hash.Size() + // Sum() concatenates the input with the hash result + appendedOutput := h.hash.Sum(input) + // extract the hash result from the hash output + res := make([]byte, outputSize) + copy(res, appendedOutput[len(input):]) + return res +} + +// NewHmacShaCryptor create a new instance of an HmacShaCryptor from the supplied parameters. +// It implements HmacKey +func NewHmacShaCryptor(kid string, hash hash.Hash) HmacKey { + return &HmacShaCryptor{ + kid: kid, + hash: hash, + } +} diff --git a/hmac_sha_cryptor_test.go b/hmac_sha_cryptor_test.go new file mode 100644 index 0000000..c5c2bc9 --- /dev/null +++ b/hmac_sha_cryptor_test.go @@ -0,0 +1,51 @@ + +// Copyright 2024 Thales Group +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package gose + +import ( + "crypto/sha256" + "github.com/stretchr/testify/require" + "testing" +) + +func TestHmacShaCryptor(t *testing.T) { + kid := "hmac-0" + cryptor := NewHmacShaCryptor(kid, sha256.New()) + t.Run("testHmacKid", func(t *testing.T) { + testHmacKid(t, cryptor, kid) + }) + t.Run("testHmacHash", func(t *testing.T) { + testHmacHash(t, cryptor, []byte("hashme")) + }) +} + +func testHmacKid(t *testing.T, cryptor HmacKey, kid string) { + require.Equal(t, kid, cryptor.Kid()) +} + +func testHmacHash(t *testing.T, cryptor HmacKey, input []byte) { + sha := cryptor.Hash(input) + require.NotEmpty(t, sha) + require.Equal(t, 32, len(sha)) + require.NotContains(t, string(sha), string(input)) +} diff --git a/hsm/asymmetric_decryption_key.go b/hsm/asymmetric_decryption_key.go index 137333c..5953817 100644 --- a/hsm/asymmetric_decryption_key.go +++ b/hsm/asymmetric_decryption_key.go @@ -4,9 +4,9 @@ import ( "crypto" "crypto/rsa" "crypto/x509" - "github.com/ThalesIgnite/crypto11" - "github.com/ThalesIgnite/gose" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/crypto11" + "github.com/ThalesGroup/gose" + "github.com/ThalesGroup/gose/jose" ) // AsymmetricDecryptionKey implements RSA OAEP using SHA1 decryption. diff --git a/hsm/asymmetric_decryption_key_store.go b/hsm/asymmetric_decryption_key_store.go index 3cd3986..002b9a9 100644 --- a/hsm/asymmetric_decryption_key_store.go +++ b/hsm/asymmetric_decryption_key_store.go @@ -1,8 +1,8 @@ package hsm import ( - "github.com/ThalesIgnite/crypto11" - "github.com/ThalesIgnite/gose" + "github.com/ThalesGroup/crypto11" + "github.com/ThalesGroup/gose" ) // AsymmetricDecryptionKeyStore implements the AsymmetricDecryptionKeyStore interface providing key lookup diff --git a/integration_test.go b/integration_test.go index 71a0515..76bf703 100644 --- a/integration_test.go +++ b/integration_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -25,7 +25,7 @@ import ( "bytes" "testing" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/interfaces.go b/interfaces.go index 7f66f4e..a747480 100644 --- a/interfaces.go +++ b/interfaces.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -26,7 +26,7 @@ import ( "crypto/x509" "fmt" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" ) //InvalidFormat is an interface for handling invalid format errors @@ -109,8 +109,8 @@ type AsymmetricDecryptionKey interface { Encryptor() (AsymmetricEncryptionKey, error) } -// AuthenticatedEncryptionKey implements authenticated encryption and decryption. -type AuthenticatedEncryptionKey interface { +// AeadEncryptionKey implements authenticated encryption and decryption. +type AeadEncryptionKey interface { Key Algorithmed // GenerateNonce generates a nonce of the correct size for use in Sealinging operations. @@ -121,6 +121,22 @@ type AuthenticatedEncryptionKey interface { Open(operation jose.KeyOps, nonce, ciphertext, aad, tag []byte) (plaintext []byte, err error) } +// BlockEncryptionKey implements encryption and decryption operations with block modes and symmetric keys +type BlockEncryptionKey interface { + Key + Algorithmed + // Seal the given plaintext returning ciphertext + Seal(plaintext []byte) []byte + // Open and validate the given ciphertext + Open(ciphertext []byte) []byte +} + +type HmacKey interface { + Key + // Hash method gets bytes as input and sum it all to return a hashed result in a 32 bytes array + Hash(input []byte) []byte +} + // JwtSigner implements generation of signed compact JWTs as defined by https://tools.ietf.org/html/rfc7519. type JwtSigner interface { // Issuer returns the identity of the issuing authority @@ -157,3 +173,17 @@ type JweEncryptor interface { type JweDecryptor interface { Decrypt(jwe string) (plaintext, aad []byte, err error) } + +type JweHmacVerifier interface { + // ComputeHash computes the authentication Tag for of a Jwe by hashing the concatenated values in argument + // aad is the protected header of the JWE encoded in b64 + // IV is the initialization vector of the JWE recipient for the encryption/decryption operations + // Ciphertext is the result of the encryption operation using the current IV + // AL is representing the number of bits (length) in AAD expressed as a big-endian 64-bit unsigned integer + // Returns the hash result of a hmac operation given the concatenated slice of the values above + ComputeHash(aad []byte, iv []byte, ciphertext []byte) []byte + // VerifyCompact a compact jwe (rfc 7516) in input and computes its authentication TAG with a hmac operation with + // the authentication TAG in the JWE. + // Returns false if the integrity check fails, i.e the tags are different + VerifyCompact(jwe jose.JweRfc7516Compact,) (result bool, err error) +} diff --git a/jose/jwe.go b/jose/jwe.go index 1da9ee9..7ac8f9f 100644 --- a/jose/jwe.go +++ b/jose/jwe.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -24,6 +24,7 @@ package jose import ( "encoding/base64" "encoding/json" + "fmt" "strings" ) @@ -34,6 +35,7 @@ type JweCustomHeaderFields struct { } // JweHeader JWE header fields. +// DEPRECATED type JweHeader struct { JwsHeader JweCustomHeaderFields @@ -41,29 +43,135 @@ type JweHeader struct { Zip Zip `json:"zip,omitempty"` } +// JwePerRecipientUnprotectedHeader +// +// JSON object that contains Header Parameters that apply to a single +// recipient of the JWE. These Header Parameter values are not +// integrity protected. This can only be present when using the JWE +// JSON Serialization. +type JwePerRecipientUnprotectedHeader struct { + PlaintextLength int `json:"plaintextLength"` +} + +// JweSharedUnprotectedHeader +// JSON object that contains the Header Parameters that apply to all +// recipients of the JWE that are not integrity protected. This can +// only be present when using the JWE JSON Serialization. +type JweSharedUnprotectedHeader struct{} + +// JweProtectedHeader +// JSON object that contains the Header Parameters that are integrity +// protected by the authenticated encryption operation. These +// parameters apply to all recipients of the JWE. For the JWE +// Compact Serialization, this comprises the entire JOSE Header. For +// the JWE JSON Serialization, this is one component of the JOSE +// Header. +type JweProtectedHeader struct { + JwsHeader + JweCustomHeaderFields + Enc Enc `json:"enc"` + Zip Zip `json:"zip,omitempty"` +} + +// HeaderRfc7516 +// For a JWE, the JOSE Header members are the union of the members of : +// o JWE Protected Header +// o JWE Shared Unprotected Header +// o JWE Per-Recipient Unprotected Header +type HeaderRfc7516 struct { + JweProtectedHeader + JweSharedUnprotectedHeader + JwePerRecipientUnprotectedHeader +} + +type JweRfc7516Compact struct { + ProtectedHeader JweProtectedHeader + EncryptedKey []byte + InitializationVector []byte + Ciphertext []byte + AuthenticationTag []byte +} + +type JweRfc7516 struct { + Header HeaderRfc7516 + EncryptedKey []byte + InitializationVector []byte + Ciphertext []byte + AuthenticationTag []byte + AAD []byte +} + // Jwe representation of a JWE. +// Beware : this Jwe implementation does not respect rfc 7516. Use JweRfc7516 instead. +// DEPRECATED type Jwe struct { Header JweHeader MarshalledHeader []byte EncryptedKey []byte Iv []byte Ciphertext []byte - Plaintext []byte - Tag []byte + Tag []byte + Plaintext []byte } // MarshalHeader marshal JWE header. Note this is not guaranteed to result in the same marshaled representation across // invocations. func (jwe *Jwe) MarshalHeader() (err error) { - var headerBytes []byte - if headerBytes, err = json.Marshal(jwe.Header); err != nil { + var marshalledHeader []byte + if marshalledHeader, err = jwe.Header.MarshalHeader(); err != nil { return } - jwe.MarshalledHeader = []byte(base64.RawURLEncoding.EncodeToString(headerBytes)) + jwe.MarshalledHeader = marshalledHeader return } -//Unmarshal to body string, or error +func (jweHeader *JweHeader) MarshalHeader() (marshalledHeader []byte, err error) { + var headerBytes []byte + if headerBytes, err = json.Marshal(jweHeader); err != nil { + return nil, err + } + return []byte(base64.RawURLEncoding.EncodeToString(headerBytes)), nil +} + +func (jweProtectedHeader *JweProtectedHeader) MarshalProtectedHeader() (marshalledHeader []byte, err error) { + var headerBytes []byte + if headerBytes, err = json.Marshal(jweProtectedHeader); err != nil { + return nil, err + } + return []byte(base64.RawURLEncoding.EncodeToString(headerBytes)), nil +} + +func concatByteArrays(slices [][]byte) []byte { + var tmp []byte + for _, s := range slices { + tmp = append(tmp, s...) + } + return tmp +} + +func (jweHeader *HeaderRfc7516) MarshallHeader() (marshalledHeader []byte, err error) { + var protectedHeaderBytes []byte + var sharedUnprotectedHeaderBytes []byte + var perRecipientUnprotectedHeaderBytes []byte + if protectedHeaderBytes, err = jweHeader.MarshalProtectedHeader(); err != nil { + return nil, err + } + if sharedUnprotectedHeaderBytes, err = json.Marshal(jweHeader.JweSharedUnprotectedHeader); err != nil { + return nil, err + } + if perRecipientUnprotectedHeaderBytes, err = json.Marshal(jweHeader.JwePerRecipientUnprotectedHeader); err != nil { + return nil, err + } + encodedHeaders := [][]byte{ + []byte(base64.RawURLEncoding.EncodeToString(protectedHeaderBytes)), + []byte(base64.RawURLEncoding.EncodeToString(sharedUnprotectedHeaderBytes)), + []byte(base64.RawURLEncoding.EncodeToString(perRecipientUnprotectedHeaderBytes)), + } + return concatByteArrays(encodedHeaders), nil +} + +// Unmarshal to body string, or error +// DEPRECATED : does not match the proper JWE structure as defined in rfc 7516 func (jwe *Jwe) Unmarshal(src string) (err error) { /* Compact JWS encoding. */ parts := strings.Split(src, ".") @@ -96,7 +204,49 @@ func (jwe *Jwe) Unmarshal(src string) (err error) { return } -// Marshal marshal a JWE to it's compact representation. +func (jwe *JweRfc7516Compact) Unmarshal(src string) (err error) { + // Compact JWE are divided in 5 parts : + // o Protected Header + // o Encrypted Key + // o Initialization Vector + // o Ciphertext + // o Authentication Tag + parts := strings.Split(src, ".") + if len(parts) != 5 { + err = ErrJweFormat + return + } + // Unmarshall JWE Protected Header + var marshalledHeader []byte + if marshalledHeader, err = base64.RawURLEncoding.DecodeString(parts[0]); err != nil { + return + } + if err = json.Unmarshal(marshalledHeader, &jwe.ProtectedHeader); err != nil { + return + } + // JWE Encrypted Key + // can be a zero length key in scenarios such as direct encoding. + if len(parts[1]) > 0 { + if jwe.EncryptedKey, err = base64.RawURLEncoding.DecodeString(parts[1]); err != nil { + return + } + } + // JWE Initialization Vector + if jwe.InitializationVector, err = base64.RawURLEncoding.DecodeString(parts[2]); err != nil { + return + } + // JWE Ciphertext + if jwe.Ciphertext, err = base64.RawURLEncoding.DecodeString(parts[3]); err != nil { + return + } + // Authentication Tag + if jwe.AuthenticationTag, err = base64.RawURLEncoding.DecodeString(parts[4]); err != nil { + return + } + return +} + +// Marshal a JWE to it's compact representation. func (jwe *Jwe) Marshal() string { stringz := []string{ string(jwe.MarshalledHeader), @@ -107,3 +257,19 @@ func (jwe *Jwe) Marshal() string { } return strings.Join(stringz, ".") } + +// Marshal a JWE to it's compact representation. +func (jwe *JweRfc7516Compact) Marshal() (marshalledJwe string, err error) { + var marshalledHeader []byte + if marshalledHeader, err = jwe.ProtectedHeader.MarshalProtectedHeader(); err != nil { + return "", fmt.Errorf("error marshalling the JWE header: %v", err) + } + stringz := []string{ + string(marshalledHeader), + base64.RawURLEncoding.EncodeToString(jwe.EncryptedKey), + base64.RawURLEncoding.EncodeToString(jwe.InitializationVector), + base64.RawURLEncoding.EncodeToString(jwe.Ciphertext), + base64.RawURLEncoding.EncodeToString(jwe.AuthenticationTag), + } + return strings.Join(stringz, "."), nil +} diff --git a/jose/jwk.go b/jose/jwk.go index 050115a..ae8cdbc 100644 --- a/jose/jwk.go +++ b/jose/jwk.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the diff --git a/jose/jwk_test.go b/jose/jwk_test.go index 52df4bf..4cd77db 100644 --- a/jose/jwk_test.go +++ b/jose/jwk_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the diff --git a/jose/jwks.go b/jose/jwks.go index f911a6d..09cbc7b 100644 --- a/jose/jwks.go +++ b/jose/jwks.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the diff --git a/jose/jwks_test.go b/jose/jwks_test.go index 17084bb..03cc2f4 100644 --- a/jose/jwks_test.go +++ b/jose/jwks_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the diff --git a/jose/jws.go b/jose/jws.go index 1c78a26..6578b42 100644 --- a/jose/jws.go +++ b/jose/jws.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the diff --git a/jose/jws_test.go b/jose/jws_test.go index 45f6db7..6328d72 100644 --- a/jose/jws_test.go +++ b/jose/jws_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the diff --git a/jose/jwt.go b/jose/jwt.go index 1f62db4..6aa8d11 100644 --- a/jose/jwt.go +++ b/jose/jwt.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the diff --git a/jose/jwt_test.go b/jose/jwt_test.go index 40ea4e5..13edb9a 100644 --- a/jose/jwt_test.go +++ b/jose/jwt_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the diff --git a/jose/types.go b/jose/types.go index 4fd0c09..b4ee61b 100644 --- a/jose/types.go +++ b/jose/types.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -52,6 +52,19 @@ type Enc string // Zip is a type representing values destined for the `zip` field in a JWE header. type Zip string +type Header struct { + Alg Alg `json:"alg"` + Jku string `json:"jku,omitempty"` + //jwkFields []jwkFields `json:"jwk,omitempty"` TODO finish this + Kid string `json:"kid,omitempty"` + X5U string `json:"x5u,omitempty"` + X5C [][]byte `json:"x5c,omitempty"` + X5T *Blob `json:"x5t,omitempty"` + X5T256 *Blob `json:"x5t#S256,omitempty"` + Typ JwsType `json:"typ,omitempty"` + Cty JwsType `json:"cty,omitempty"` +} + const ( // Supported Algorithms @@ -79,6 +92,8 @@ const ( AlgA192GCM Alg = "A192GCM" //AlgA256GCM AES GCM using 256-bit key AlgA256GCM Alg = "A256GCM" + //AlgA256CBC AES CBC using 256-bit key + AlgA256CBC Alg = "A256CBC" // AlgDir direct encryption for use with JWEs AlgDir Alg = "dir" // AlgRSAOAEP RSA OAEP Key encryption for use with JWEs @@ -133,6 +148,8 @@ const ( EncA192GCM Enc = "A192GCM" // EncA256GCM AES GCM 256 Enc type EncA256GCM Enc = "A256GCM" + // EncA256CBC AES CBC 256 Enc type + EncA256CBC Enc = "A256CBC" // DeflateZip deflate type DeflateZip Zip = "DEF" diff --git a/jose/types_test.go b/jose/types_test.go index e950e72..6b519f1 100644 --- a/jose/types_test.go +++ b/jose/types_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the diff --git a/jwe_direct_decryptor.go b/jwe_direct_decryptor_aead.go similarity index 74% rename from jwe_direct_decryptor.go rename to jwe_direct_decryptor_aead.go index 3e3b8e7..14cee48 100644 --- a/jwe_direct_decryptor.go +++ b/jwe_direct_decryptor_aead.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -21,17 +21,17 @@ package gose -import "github.com/ThalesIgnite/gose/jose" +import "github.com/ThalesGroup/gose/jose" -var _ JweDecryptor = (*JweDirectDecryptorImpl)(nil) +var _ JweDecryptor = (*JweDirectDecryptorAeadImpl)(nil) -// JweDirectDecryptorImpl is a concrete implementation of the JweDirectDecryptor interface. -type JweDirectDecryptorImpl struct { - keystore map[string]AuthenticatedEncryptionKey +// JweDirectDecryptorAeadImpl is a concrete implementation of the JweDirectDecryptor interface. +type JweDirectDecryptorAeadImpl struct { + keystore map[string]AeadEncryptionKey } // Decrypt and verify the given JWE returning both the plaintext and AAD. -func (decryptor *JweDirectDecryptorImpl) Decrypt(jwe string) (plaintext, aad []byte, err error) { +func (decryptor *JweDirectDecryptorAeadImpl) Decrypt(jwe string) (plaintext, aad []byte, err error) { var jweStruct jose.Jwe if err = jweStruct.Unmarshal(jwe); err != nil { @@ -50,14 +50,14 @@ func (decryptor *JweDirectDecryptorImpl) Decrypt(jwe string) (plaintext, aad []b return } - var key AuthenticatedEncryptionKey + var key AeadEncryptionKey var exists bool if key, exists = decryptor.keystore[jweStruct.Header.Kid]; !exists { err = ErrUnknownKey return } - enc, ok := algToEncMap[key.Algorithm()] + enc, ok := gcmAlgToEncMap[key.Algorithm()] if !ok { err = ErrInvalidEncryption return @@ -80,11 +80,11 @@ func (decryptor *JweDirectDecryptorImpl) Decrypt(jwe string) (plaintext, aad []b return } -// NewJweDirectDecryptorImpl create a new instance of a JweDirectDecryptorImpl. -func NewJweDirectDecryptorImpl(keys []AuthenticatedEncryptionKey) *JweDirectDecryptorImpl { +// NewJweDirectDecryptorAeadImpl create a new instance of a JweDirectDecryptorAeadImpl. +func NewJweDirectDecryptorAeadImpl(keys []AeadEncryptionKey) *JweDirectDecryptorAeadImpl { // Create map out of our list of keys. The map is keyed in Kid. - decryptor := &JweDirectDecryptorImpl{ - keystore: map[string]AuthenticatedEncryptionKey{}, + decryptor := &JweDirectDecryptorAeadImpl{ + keystore: map[string]AeadEncryptionKey{}, } for _, key := range keys { decryptor.keystore[key.Kid()] = key diff --git a/jwe_direct_decryptor_test.go b/jwe_direct_decryptor_aead_test.go similarity index 90% rename from jwe_direct_decryptor_test.go rename to jwe_direct_decryptor_aead_test.go index 45a5487..cf347bc 100644 --- a/jwe_direct_decryptor_test.go +++ b/jwe_direct_decryptor_aead_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -27,7 +27,7 @@ import ( "github.com/stretchr/testify/mock" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -36,7 +36,7 @@ import ( func TestNewJweDirectDecryptorImpl(t *testing.T) { keyMock := &authenticatedEncryptionKeyMock{} keyMock.On("Kid").Return("unique").Once() - decryptor := NewJweDirectDecryptorImpl([]AuthenticatedEncryptionKey{keyMock}) + decryptor := NewJweDirectDecryptorAeadImpl([]AeadEncryptionKey{keyMock}) require.NotNil(t, decryptor) assert.NotNil(t, decryptor.keystore) } @@ -44,7 +44,7 @@ func TestNewJweDirectDecryptorImpl(t *testing.T) { func TestJweDirectDecryptorImpl_Decrypt_InvalidJweFormat(t *testing.T) { keyMock := &authenticatedEncryptionKeyMock{} keyMock.On("Kid").Return("unique").Once() - decryptor := NewJweDirectDecryptorImpl([]AuthenticatedEncryptionKey{keyMock}) + decryptor := NewJweDirectDecryptorAeadImpl([]AeadEncryptionKey{keyMock}) require.NotNil(t, decryptor) pt, aad, err := decryptor.Decrypt("not a jwe") @@ -57,7 +57,7 @@ func TestJweDirectDecryptorImpl_Decrypt_InvalidJweFormat(t *testing.T) { func TestJweDirectDecryptorImpl_Decrypt_ZipCompressionNotSupport(t *testing.T) { keyMock := &authenticatedEncryptionKeyMock{} keyMock.On("Kid").Return("unique").Once() - decryptor := NewJweDirectDecryptorImpl([]AuthenticatedEncryptionKey{keyMock}) + decryptor := NewJweDirectDecryptorAeadImpl([]AeadEncryptionKey{keyMock}) require.NotNil(t, decryptor) fakeJwe := &jose.Jwe{ @@ -91,7 +91,7 @@ func TestJweDirectDecryptorImpl_Decrypt_ZipCompressionNotSupport(t *testing.T) { func TestJweDirectDecryptorImpl_Decrypt_InvalidKeyId(t *testing.T) { keyMock := &authenticatedEncryptionKeyMock{} keyMock.On("Kid").Return("unique").Once() - decryptor := NewJweDirectDecryptorImpl([]AuthenticatedEncryptionKey{keyMock}) + decryptor := NewJweDirectDecryptorAeadImpl([]AeadEncryptionKey{keyMock}) require.NotNil(t, decryptor) fakeJwe := &jose.Jwe{ @@ -124,7 +124,7 @@ func TestJweDirectDecryptorImpl_Decrypt_InvalidKeyId(t *testing.T) { func TestJweDirectDecryptorImpl_Decrypt_UnknownKeyId(t *testing.T) { keyMock := &authenticatedEncryptionKeyMock{} keyMock.On("Kid").Return("unique").Once() - decryptor := NewJweDirectDecryptorImpl([]AuthenticatedEncryptionKey{keyMock}) + decryptor := NewJweDirectDecryptorAeadImpl([]AeadEncryptionKey{keyMock}) require.NotNil(t, decryptor) fakeJwe := &jose.Jwe{ @@ -158,7 +158,7 @@ func TestJweDirectDecryptorImpl_Decrypt_InvalidKeyAlg(t *testing.T) { keyMock := &authenticatedEncryptionKeyMock{} keyMock.On("Kid").Return("unique").Once() keyMock.On("Algorithm").Return(jose.AlgES256).Once() - decryptor := NewJweDirectDecryptorImpl([]AuthenticatedEncryptionKey{keyMock}) + decryptor := NewJweDirectDecryptorAeadImpl([]AeadEncryptionKey{keyMock}) require.NotNil(t, decryptor) fakeJwe := &jose.Jwe{ @@ -192,7 +192,7 @@ func TestJweDirectDecryptorImpl_Decrypt_InvalidJweAlg(t *testing.T) { keyMock := &authenticatedEncryptionKeyMock{} keyMock.On("Kid").Return("unique").Once() keyMock.On("Algorithm").Return(jose.AlgA256GCM).Once() - decryptor := NewJweDirectDecryptorImpl([]AuthenticatedEncryptionKey{keyMock}) + decryptor := NewJweDirectDecryptorAeadImpl([]AeadEncryptionKey{keyMock}) require.NotNil(t, decryptor) fakeJwe := &jose.Jwe{ @@ -226,7 +226,7 @@ func TestJweDirectDecryptorImpl_Decrypt_InvalidJweEnc(t *testing.T) { keyMock := &authenticatedEncryptionKeyMock{} keyMock.On("Kid").Return("unique").Once() keyMock.On("Algorithm").Return(jose.AlgA256GCM).Once() - decryptor := NewJweDirectDecryptorImpl([]AuthenticatedEncryptionKey{keyMock}) + decryptor := NewJweDirectDecryptorAeadImpl([]AeadEncryptionKey{keyMock}) require.NotNil(t, decryptor) fakeJwe := &jose.Jwe{ @@ -262,7 +262,7 @@ func TestJweDirectDecryptorImpl_Decrypt_InvalidCiphertextOrTag(t *testing.T) { keyMock.On("Algorithm").Return(jose.AlgA256GCM).Once() keyMock.On("Kid").Return("unique").Once() keyMock.On("Open", jose.KeyOpsDecrypt, []byte("iv"), []byte("encrypted"), mock.Anything, []byte("tag")).Return([]byte(nil), expectedError).Once() - decryptor := NewJweDirectDecryptorImpl([]AuthenticatedEncryptionKey{keyMock}) + decryptor := NewJweDirectDecryptorAeadImpl([]AeadEncryptionKey{keyMock}) require.NotNil(t, decryptor) fakeJwe := &jose.Jwe{ @@ -296,7 +296,7 @@ func TestJweDirectDecryptorImpl_Decrypt(t *testing.T) { keyMock := &authenticatedEncryptionKeyMock{} keyMock.On("Algorithm").Return(jose.AlgA256GCM).Once() keyMock.On("Kid").Return("unique").Once() - decryptor := NewJweDirectDecryptorImpl([]AuthenticatedEncryptionKey{keyMock}) + decryptor := NewJweDirectDecryptorAeadImpl([]AeadEncryptionKey{keyMock}) require.NotNil(t, decryptor) fakeJwe := &jose.Jwe{ diff --git a/jwe_direct_decryptor_block.go b/jwe_direct_decryptor_block.go new file mode 100644 index 0000000..6d45aaf --- /dev/null +++ b/jwe_direct_decryptor_block.go @@ -0,0 +1,96 @@ +// Copyright 2024 Thales Group +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package gose + +import ( + "encoding/binary" + "fmt" + "github.com/ThalesGroup/gose/jose" +) + +type JweDirectDecryptorBlock struct { + aesKey BlockEncryptionKey + jweVerifier JweHmacVerifierImpl +} + +// Decrypt and verify the given JWE returning the plaintext. +// never return a non nil aad. aad is just here to satisfy the JweDecryptor interface +func (decryptor *JweDirectDecryptorBlock) Decrypt(marshalledJwe string) (plaintext, aad []byte, err error) { + // The following steps respect the RFC7516 decryption instructions : + // https://datatracker.ietf.org/doc/html/rfc7516 + // The message decryption process is the reverse of the encryption + // process. The order of the steps is not significant in cases where + // there are no dependencies between the inputs and outputs of the + // steps. If any of these steps fail, the encrypted content cannot be + // validated. + var jwe jose.JweRfc7516Compact + if err = jwe.Unmarshal(marshalledJwe); err != nil { + return nil, nil, fmt.Errorf("error unmarshalling the jwe: %v", err) + } + // check the algorithm in header + if jwe.ProtectedHeader.Alg != decryptor.aesKey.Algorithm() { + return nil, nil, fmt.Errorf("error checking the JWE protected header's algorthim. algorithm is '%v' but expected is '%v'", jwe.ProtectedHeader.Alg, decryptor.aesKey.Algorithm()) + } + // check the keys for direct encryption + if jwe.ProtectedHeader.Kid != decryptor.aesKey.Kid() { + return nil, nil, fmt.Errorf("error checking the Key ID for decryption. ID is '%v' but expected is '%v'", jwe.ProtectedHeader.Kid, decryptor.aesKey.Kid()) + } + // check that the CEK is empty for direct encryption + if len(jwe.EncryptedKey) != 0 { + return nil, nil, fmt.Errorf("error checking the encrypted key. Should be empty for empty encryption but was '%d' bytes long", len(jwe.EncryptedKey)) + } + + // INTEGRITY CHECK before decryption + integrity, err := decryptor.jweVerifier.VerifyCompact(jwe); + if err != nil { + return nil, nil, err + } + if ! integrity { + return nil, nil, fmt.Errorf("error corrupted jwe : integrity check failed") + } + + // decryption + if jwe.ProtectedHeader.Zip != "" { + err = ErrZipCompressionNotSupported + return + } + plaintextBlock := decryptor.aesKey.Open(jwe.Ciphertext) + + // get the size of the final plaintext + //input, err := jwe.ProtectedHeader.OtherAad.MarshalJSON() + data := jwe.ProtectedHeader.OtherAad.B + plaintextLength := binary.BigEndian.Uint64(data) + plaintext = make([]byte, plaintextLength) + copy(plaintext, plaintextBlock[:plaintextLength]) + + return plaintext, nil, nil +} + +// NewJweDirectDecryptorBlock create a new instance of a JweDirectDecryptorBlock. +func NewJweDirectDecryptorBlock(aesKey BlockEncryptionKey, hmacKey HmacKey) *JweDirectDecryptorBlock { + // Create map out of our list of keys. The map is keyed in Kid. + decryptor := &JweDirectDecryptorBlock{ + aesKey: aesKey, + jweVerifier: JweHmacVerifierImpl{hmacKey: hmacKey}, + } + return decryptor +} diff --git a/jwe_direct_encryptor.go b/jwe_direct_encryptor_aead.go similarity index 79% rename from jwe_direct_encryptor.go rename to jwe_direct_encryptor_aead.go index eac16f7..22b6b25 100644 --- a/jwe_direct_encryptor.go +++ b/jwe_direct_encryptor_aead.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -22,25 +22,25 @@ package gose import ( - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" ) var ( - algToEncMap = map[jose.Alg]jose.Enc{ + gcmAlgToEncMap = map[jose.Alg]jose.Enc{ jose.AlgA128GCM: jose.EncA128GCM, jose.AlgA192GCM: jose.EncA192GCM, jose.AlgA256GCM: jose.EncA256GCM, } ) -// JweDirectEncryptionEncryptorImpl implementation of JweDirectEncryptionEncryptor interface. -type JweDirectEncryptionEncryptorImpl struct { - key AuthenticatedEncryptionKey +// JweDirectEncryptorAead implementation of JweDirectEncryptionEncryptor interface. +type JweDirectEncryptorAead struct { + key AeadEncryptionKey externalIV bool } // Encrypt encrypt and authenticate the given plaintext and AAD returning a compact JWE. -func (encryptor *JweDirectEncryptionEncryptorImpl) Encrypt(plaintext, aad []byte) (string, error) { +func (encryptor *JweDirectEncryptorAead) Encrypt(plaintext, aad []byte) (string, error) { var nonce []byte var err error if !encryptor.externalIV { @@ -65,7 +65,7 @@ func (encryptor *JweDirectEncryptionEncryptorImpl) Encrypt(plaintext, aad []byte Alg: jose.AlgDir, Kid: encryptor.key.Kid(), }, - Enc: algToEncMap[encryptor.key.Algorithm()], + Enc: gcmAlgToEncMap[encryptor.key.Algorithm()], JweCustomHeaderFields: customHeaderFields, }, EncryptedKey: []byte{}, @@ -94,9 +94,9 @@ func (encryptor *JweDirectEncryptionEncryptorImpl) Encrypt(plaintext, aad []byte return jwe.Marshal(), nil } -// NewJweDirectEncryptorImpl construct an instance of a JweDirectEncryptionEncryptorImpl. -func NewJweDirectEncryptorImpl(key AuthenticatedEncryptionKey, externalIV bool) *JweDirectEncryptionEncryptorImpl { - return &JweDirectEncryptionEncryptorImpl{ +// NewJweDirectEncryptorAead construct an instance of a JweDirectEncryptorAead. +func NewJweDirectEncryptorAead(key AeadEncryptionKey, externalIV bool) *JweDirectEncryptorAead { + return &JweDirectEncryptorAead{ key: key, externalIV: externalIV, } diff --git a/jwe_direct_encryptor_test.go b/jwe_direct_encryptor_aead_test.go similarity index 92% rename from jwe_direct_encryptor_test.go rename to jwe_direct_encryptor_aead_test.go index 6cb5ba4..81ad16d 100644 --- a/jwe_direct_encryptor_test.go +++ b/jwe_direct_encryptor_aead_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -25,7 +25,7 @@ import ( "log" "testing" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/assert" @@ -72,7 +72,7 @@ func (encryptor *authenticatedEncryptionKeyMock) Marshal() (string, error) { func TestNewJweEncryptorImpl(t *testing.T) { keyMock := &authenticatedEncryptionKeyMock{} - encryptor := NewJweDirectEncryptorImpl(keyMock, false) + encryptor := NewJweDirectEncryptorAead(keyMock, false) assert.NotNil(t, encryptor) } @@ -83,7 +83,7 @@ func TestJweDirectEncryptionEncryptorImpl_Encrypt(t *testing.T) { keyMock.On("Algorithm").Return(jose.AlgA256GCM).Once() keyMock.On("Seal", jose.KeyOpsEncrypt, []byte("nonce"), []byte("something"), mock.Anything).Return([]byte("encrypted"), []byte("tag"), nil).Once() - encryptor := NewJweDirectEncryptorImpl(keyMock, false) + encryptor := NewJweDirectEncryptorAead(keyMock, false) jwe, err := encryptor.Encrypt([]byte("something"), []byte("else")) assert.NoError(t, err) @@ -105,7 +105,7 @@ func TestExampleJweDirectEncryptionEncryptorImpl_EncryptDecrypt(t *testing.T) { aad := []byte("some_data_to_authenticate") // Create a JWE cryptor - jweEncryptor := NewJweDirectEncryptorImpl(cryptor, false) + jweEncryptor := NewJweDirectEncryptorAead(cryptor, false) // Now encrypt jwe, err := jweEncryptor.Encrypt(toEncrypt, aad) @@ -117,7 +117,7 @@ func TestExampleJweDirectEncryptionEncryptorImpl_EncryptDecrypt(t *testing.T) { log.Printf("Created JWE: %s", jwe) // Now to decrypt - jweDecryptor := NewJweDirectDecryptorImpl([]AuthenticatedEncryptionKey{cryptor}) + jweDecryptor := NewJweDirectDecryptorAeadImpl([]AeadEncryptionKey{cryptor}) recoveredPlaintext, recoveredAad, err := jweDecryptor.Decrypt(jwe) if err != nil { diff --git a/jwe_direct_encryptor_block.go b/jwe_direct_encryptor_block.go new file mode 100644 index 0000000..d03a5a5 --- /dev/null +++ b/jwe_direct_encryptor_block.go @@ -0,0 +1,107 @@ +// Copyright 2024 Thales Group +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package gose + +import ( + "fmt" + "github.com/ThalesGroup/gose/jose" +) + +var ( + cbcAlgToEncMap = map[jose.Alg]jose.Enc{ + jose.AlgA256CBC: jose.EncA256CBC, + } +) + +// JweDirectEncryptorBlock +// implementation of JweDirectEncryptionEncryptor interface for BlockMode which is more efficient than Block for bulk +// operations +type JweDirectEncryptorBlock struct { + aesKey BlockEncryptionKey + iv []byte + jweVerifier JweHmacVerifierImpl +} + +// makeJwe builds the JWE structure +func (encryptor *JweDirectEncryptorBlock) makeJweProtectedHeader() *jose.JweProtectedHeader { + return &jose.JweProtectedHeader{ + JwsHeader: jose.JwsHeader{ + Alg: encryptor.aesKey.Algorithm(), + Kid: encryptor.aesKey.Kid(), + Typ: "JWT", + Cty: "JWT", + }, + Enc: cbcAlgToEncMap[encryptor.aesKey.Algorithm()], + } +} + +// Encrypt encrypts the given plaintext and returns a compact JWE. +// WARNING aad is useless here : according to RFC7516, the AAD is computed from the JWE's private header +// It is just here to statisfy the interface implementation +func (encryptor *JweDirectEncryptorBlock) Encrypt(plaintext, aad []byte) (string, error) { + // The following steps respect the RFC7516 Appendix B for AES CBC and HMAC encryption instructions : + // https://datatracker.ietf.org/doc/html/rfc7516#appendix-B + var err error + // iv + iv := encryptor.iv + // JWE header + jweProtectedHeader := encryptor.makeJweProtectedHeader() + // AAD + // = ASCII(BASE64URL(UTF8(JWE Protected Header))) + if aad, err = jweProtectedHeader.MarshalProtectedHeader(); err != nil { + return "", fmt.Errorf("error marshalling the JWE Header: %v", err) + } + // Encrypt Plaintext to Create Ciphertext + ciphertext := encryptor.aesKey.Seal(plaintext) + // HMAC computation + outputHmac := encryptor.jweVerifier.ComputeHash(aad, iv, ciphertext) + // Create Authentication Tag + // = the first half of the hash + // THE TAG HAS TO BE VERIFIED WHEN THIS SAME JWE IS USED FOR DECRYPTION. + // BEWARE that taking half of the hash for integrity check is part of the rfc 7516 : + // https://datatracker.ietf.org/doc/html/rfc7516#appendix-B.7 + // I am not sure if we have to follow the specifications or get the max of the length of the hash to maximize the security + //tag := outputHmac[:(len(outputHmac) / 2)] + tag := outputHmac + + // Create the JWE + // we store the length of the plaintext in the additional data held by the protected header. + // It can be used to return the proper plaintext after decryption. + jweProtectedHeader.OtherAad = &jose.Blob{B: uintToBytesBigEndian(uint64(len(plaintext)))} + jwe := &jose.JweRfc7516Compact{ + ProtectedHeader: *jweProtectedHeader, + EncryptedKey: nil, + InitializationVector: iv, + Ciphertext: ciphertext, + AuthenticationTag: tag, + } + return jwe.Marshal() +} + +// NewJweDirectEncryptorBlock construct an instance of a JweDirectEncryptorBlock. +func NewJweDirectEncryptorBlock(aesKey BlockEncryptionKey, hmacKey HmacKey, iv []byte) *JweDirectEncryptorBlock { + return &JweDirectEncryptorBlock{ + aesKey: aesKey, + iv: iv, + jweVerifier: JweHmacVerifierImpl{hmacKey: hmacKey}, + } +} diff --git a/jwe_direct_encryptor_block_test.go b/jwe_direct_encryptor_block_test.go new file mode 100644 index 0000000..e62605d --- /dev/null +++ b/jwe_direct_encryptor_block_test.go @@ -0,0 +1,113 @@ +// Copyright 2024 Thales Group +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package gose + +import ( + "crypto/rand" + "crypto/sha256" + "encoding/base64" + "github.com/ThalesGroup/gose/jose" + "github.com/stretchr/testify/require" + "strings" + "testing" +) + +func requireNoIssue(t *testing.T, o interface{}, err error) { + require.NoError(t, err) + require.NotNil(t, o) +} + +func TestJweDirectEncryptorBlock(t *testing.T) { + // vars + blockSize := 16 + iv := make([]byte, blockSize) + _, err := rand.Read(iv) + require.NoError(t, err) + require.NotEmpty(t, iv) + expectedAesKid := "aes0" + expectedHmacKid := "hmac0" + expectedAlg := jose.AlgA256CBC + + // mocking the block mode cipher for encryption + mcEnc := &MockBlockMode{ + mode: ModeEncrypt, + } + bekEnc := NewAesCbcCryptor(mcEnc, expectedAesKid, expectedAlg) + hk := NewHmacShaCryptor(expectedHmacKid, sha256.New()) + encryptor := NewJweDirectEncryptorBlock(bekEnc, hk, iv) + mcEnc.On("BlockSize").Return(len(iv)) + + // mocking the block mode cipher for decryption + mcDec := &MockBlockMode{ + mode: ModeDecrypt, + } + mcDec.On("BlockSize").Return(len(iv)) + require.NoError(t, err) + bekDec := NewAesCbcCryptor(mcDec, expectedAesKid, expectedAlg) + decryptor := NewJweDirectDecryptorBlock(bekDec, hk) + + // running tests + t.Run("testEncryptDecrypt", func(t *testing.T) { + testEncryptDecrypt(t, encryptor, decryptor, iv) + }) +} + +func testEncryptDecrypt(t *testing.T, cryptor *JweDirectEncryptorBlock, decryptor *JweDirectDecryptorBlock, expectedIV []byte) { + // ********** + // ENCRYPTION + // ********** + marshalledJwe, err := cryptor.Encrypt([]byte(mockExpectedCleartext), nil) + require.NoError(t, err) + require.NotEmpty(t, marshalledJwe) + // verify the structure + splits := strings.Split(marshalledJwe, ".") + require.Equal(t, 5, len(splits)) + // For direct encryption, the encrypted key is nil + // we expected an empty string for the second part of the JWE + require.Empty(t, splits[1]) + // other parts should not be empty + require.NotEmpty(t, splits[0]) + require.NotEmpty(t, splits[2]) + require.NotEmpty(t, splits[3]) + require.NotEmpty(t, splits[4]) + // verify structure + iv, err := base64.RawURLEncoding.DecodeString(splits[2]) + require.NoError(t, err) + require.Equal(t, expectedIV, iv) + ciphertext, err := base64.RawURLEncoding.DecodeString(splits[3]) + require.NoError(t, err) + require.Contains(t, string(ciphertext), mockExpectedCiphertext) + + // ********** + // DECRYPTION + // ********** + plaintext, _, err := decryptor.Decrypt(marshalledJwe) + require.NoError(t, err) + + // decryption + require.NotEmpty(t, plaintext) + require.Equal(t, mockExpectedCleartext, string(plaintext)) +} + + + + diff --git a/jwe_hmac_verifier.go b/jwe_hmac_verifier.go new file mode 100644 index 0000000..0fabd98 --- /dev/null +++ b/jwe_hmac_verifier.go @@ -0,0 +1,68 @@ +// Copyright 2024 Thales Group +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package gose + +import ( + "bytes" + "fmt" + "github.com/ThalesGroup/gose/jose" +) + +// JweHmacVerifierImpl implements the JWE Verification API +type JweHmacVerifierImpl struct { + hmacKey HmacKey +} + +func computeAL(aad []byte) []byte { + // AL = AAD length + // is the octet string representing the number of bits in AAD expressed as a big-endian 64-bit unsigned integer + return uintToBytesBigEndian(uint64(len(aad))) +} + +func (verifier *JweHmacVerifierImpl) VerifyCompact(jwe jose.JweRfc7516Compact) (result bool, err error){ + // AAD + // = ASCII(BASE64URL(UTF8(JWE Protected Header))) + var aad []byte + if aad, err = jwe.ProtectedHeader.MarshalProtectedHeader(); err != nil { + return false, fmt.Errorf("error marshalling the JWE Header: %v", err) + } + // Input HMAC computation + // Concatenate the AAD, the Initialization Vector, the ciphertext and the AL value. + inputHmac := concatByteArrays([][]byte{aad, jwe.InitializationVector, jwe.Ciphertext, computeAL(aad)}) + // compute the hash of it + outputHmac := verifier.hmacKey.Hash(inputHmac) + return bytes.Compare(outputHmac, jwe.AuthenticationTag) == 0, nil +} + +func (verifier *JweHmacVerifierImpl) ComputeHash(aad []byte, iv []byte, ciphertext []byte) []byte { + // Encrypt Plaintext to Create Ciphertext + // Input HMAC computation + // Concatenate the AAD, the Initialization Vector, the ciphertext and the AL value. + inputHmac := concatByteArrays([][]byte{aad, iv, ciphertext, computeAL(aad)}) + // compute the hash of it + return verifier.hmacKey.Hash(inputHmac) +} + +// NewJweHmacVerifier creates a JWT Verifier for a given truststore +func NewJweHmacVerifier(hmacKey HmacKey) *JweHmacVerifierImpl { + return &JweHmacVerifierImpl{hmacKey: hmacKey} +} diff --git a/jwe_hmac_verifier_test.go b/jwe_hmac_verifier_test.go new file mode 100644 index 0000000..81d48d5 --- /dev/null +++ b/jwe_hmac_verifier_test.go @@ -0,0 +1,25 @@ +// Copyright 2024 Thales Group +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package gose + +// JweHmacVerifierImpl implements the JWE Verification API + diff --git a/jwe_key_encryption_decryptor.go b/jwe_key_encryption_decryptor.go index f0d88e6..4d4b68d 100644 --- a/jwe_key_encryption_decryptor.go +++ b/jwe_key_encryption_decryptor.go @@ -1,9 +1,30 @@ +// Copyright 2024 Thales Group +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + package gose import ( "crypto/aes" "crypto/cipher" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" ) // JweRsaKeyEncryptionDecryptorImpl implements RSA Key Encryption CEK mode. diff --git a/jwe_key_encryption_decryptor_test.go b/jwe_key_encryption_decryptor_test.go index b719572..e788744 100644 --- a/jwe_key_encryption_decryptor_test.go +++ b/jwe_key_encryption_decryptor_test.go @@ -2,7 +2,7 @@ package gose import ( "bytes" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "math/rand" diff --git a/jwe_key_encryption_encryptor.go b/jwe_key_encryption_encryptor.go index faedcb0..748181d 100644 --- a/jwe_key_encryption_encryptor.go +++ b/jwe_key_encryption_encryptor.go @@ -1,10 +1,31 @@ +// Copyright 2024 Thales Group +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + package gose import ( "crypto" "crypto/rand" "crypto/rsa" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" ) // JweRsaKeyEncryptionEncryptorImpl implements RSA Key Encryption CEK mode. @@ -49,7 +70,7 @@ func (e *JweRsaKeyEncryptionEncryptorImpl) Encrypt(plaintext, aad []byte) (strin Alg: jose.AlgRSAOAEP, Kid: e.recipientJwk.Kid(), }, - Enc: algToEncMap[cekJwk.Alg()], + Enc: gcmAlgToEncMap[cekJwk.Alg()], JweCustomHeaderFields: customHeaderFields, }, EncryptedKey: encryptedKey, diff --git a/jwe_key_encryption_encryptor_test.go b/jwe_key_encryption_encryptor_test.go index 0c02076..769993e 100644 --- a/jwe_key_encryption_encryptor_test.go +++ b/jwe_key_encryption_encryptor_test.go @@ -1,7 +1,7 @@ package gose import ( - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "testing" diff --git a/jwks_truststore.go b/jwks_truststore.go index e3e273f..aa7fc77 100644 --- a/jwks_truststore.go +++ b/jwks_truststore.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -29,7 +29,7 @@ import ( "strings" "sync" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" ) // Interface wrapper to allow mocking of http client. diff --git a/jwks_truststore_test.go b/jwks_truststore_test.go index 4b83d91..fb57812 100644 --- a/jwks_truststore_test.go +++ b/jwks_truststore_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -28,7 +28,7 @@ import ( "net/http" "testing" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" diff --git a/jwt_signer.go b/jwt_signer.go index ef100ab..eb85408 100644 --- a/jwt_signer.go +++ b/jwt_signer.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -26,7 +26,7 @@ import ( "log" "time" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/google/uuid" ) diff --git a/jwt_signer_test.go b/jwt_signer_test.go index 9c68d36..38efb68 100644 --- a/jwt_signer_test.go +++ b/jwt_signer_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -28,7 +28,7 @@ import ( "strings" "testing" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" diff --git a/jwt_verifier.go b/jwt_verifier.go index 156b94d..0d96aab 100644 --- a/jwt_verifier.go +++ b/jwt_verifier.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -25,7 +25,7 @@ import ( "fmt" "time" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" ) // JwtVerifierImpl implements the JWT Verification API diff --git a/jwt_verifier_test.go b/jwt_verifier_test.go index 6384ba1..dab33f1 100644 --- a/jwt_verifier_test.go +++ b/jwt_verifier_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -31,7 +31,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" ) const ( diff --git a/key_generator.go b/key_generator.go index 0882424..ca5ec4a 100644 --- a/key_generator.go +++ b/key_generator.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -28,7 +28,7 @@ import ( "crypto/rsa" "crypto/x509" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" ) const minimumRsaKeySize = 2048 // The minimum RSA key size allowable as defined https://tools.ietf.org/html/rfc7518#section-3.5 @@ -118,7 +118,7 @@ func (g *ECDSASigningKeyGenerator) Generate(alg jose.Alg, operations []jose.KeyO type AuthenticatedEncryptionKeyGenerator struct{} // Generate generate a Generate and JWK representation. -func (g *AuthenticatedEncryptionKeyGenerator) Generate(alg jose.Alg, operations []jose.KeyOps) (AuthenticatedEncryptionKey, jose.Jwk, error) { +func (g *AuthenticatedEncryptionKeyGenerator) Generate(alg jose.Alg, operations []jose.KeyOps) (AeadEncryptionKey, jose.Jwk, error) { sz, ok := authenticatedEncryptionAlgs[alg] if !ok { return nil, nil, ErrInvalidAlgorithm diff --git a/key_generator_test.go b/key_generator_test.go index 2fb449d..7249db0 100644 --- a/key_generator_test.go +++ b/key_generator_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -25,7 +25,7 @@ import ( "fmt" "testing" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/keystore.go b/keystore.go index c50c5c5..65fc356 100644 --- a/keystore.go +++ b/keystore.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -28,7 +28,7 @@ import ( "encoding/json" "sync" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" ) //TrustKeyStoreImpl implements the Trust Store API diff --git a/keystore_test.go b/keystore_test.go index d7a39bf..69f3bf0 100644 --- a/keystore_test.go +++ b/keystore_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -24,7 +24,7 @@ package gose import ( "testing" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" ) diff --git a/rsa_private.go b/rsa_private.go index dae2a55..5c317e1 100644 --- a/rsa_private.go +++ b/rsa_private.go @@ -1,3 +1,24 @@ +// Copyright 2024 Thales Group +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + package gose import ( @@ -7,7 +28,7 @@ import ( "crypto/rsa" "crypto/x509" "encoding/pem" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/sirupsen/logrus" ) diff --git a/rsa_private_test.go b/rsa_private_test.go index e789413..790640b 100644 --- a/rsa_private_test.go +++ b/rsa_private_test.go @@ -6,7 +6,7 @@ import ( "crypto/rsa" "crypto/x509" "encoding/pem" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "testing" diff --git a/rsa_public.go b/rsa_public.go index 930678e..0cb646b 100644 --- a/rsa_public.go +++ b/rsa_public.go @@ -1,3 +1,24 @@ +// Copyright 2024 Thales Group +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + package gose import ( @@ -7,7 +28,7 @@ import ( "crypto/rsa" "crypto/x509" "encoding/pem" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/sirupsen/logrus" ) diff --git a/rsa_public_test.go b/rsa_public_test.go index f794b2b..0c59bfd 100644 --- a/rsa_public_test.go +++ b/rsa_public_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -31,7 +31,7 @@ import ( "encoding/pem" "testing" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/signer.go b/signer.go index 58b3b61..fcca7f7 100644 --- a/signer.go +++ b/signer.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -30,7 +30,7 @@ import ( "crypto/x509" "encoding/pem" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/sirupsen/logrus" ) diff --git a/signer_test.go b/signer_test.go index 7e7e449..ea7e9a7 100644 --- a/signer_test.go +++ b/signer_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -29,7 +29,7 @@ import ( "crypto" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) diff --git a/verifier.go b/verifier.go index 5b555ad..c3fa305 100644 --- a/verifier.go +++ b/verifier.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -25,7 +25,7 @@ import ( "crypto/x509" "math" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" ) var ( diff --git a/verifier_test.go b/verifier_test.go index a359e28..cb303e0 100644 --- a/verifier_test.go +++ b/verifier_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 Thales e-Security, Inc +// Copyright 2024 Thales Group // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -26,7 +26,7 @@ import ( "crypto/rsa" "testing" - "github.com/ThalesIgnite/gose/jose" + "github.com/ThalesGroup/gose/jose" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" )