github.com/lestrrat-go/jwx/v2@v2.0.21/jwe/jwe_test.go (about)

     1  package jwe_test
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"crypto"
     7  	"crypto/ecdsa"
     8  	"crypto/elliptic"
     9  	"crypto/rand"
    10  	"crypto/rsa"
    11  	"encoding/base64"
    12  	"fmt"
    13  	"os"
    14  	"strings"
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/lestrrat-go/jwx/v2/internal/json"
    19  	"github.com/lestrrat-go/jwx/v2/internal/jwxtest"
    20  
    21  	"github.com/lestrrat-go/jwx/v2/jwa"
    22  	"github.com/lestrrat-go/jwx/v2/jwe"
    23  	"github.com/lestrrat-go/jwx/v2/jwk"
    24  	"github.com/lestrrat-go/jwx/v2/x25519"
    25  	"github.com/stretchr/testify/assert"
    26  	"github.com/stretchr/testify/require"
    27  )
    28  
    29  const (
    30  	examplePayload = `The true sign of intelligence is not knowledge but imagination.`
    31  )
    32  
    33  var rsaPrivKey rsa.PrivateKey
    34  
    35  func init() {
    36  	var jwkstr = []byte(`
    37       {"kty":"RSA",
    38        "n":"oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUWcJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3Spsk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2asbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMStPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2djYgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw",
    39        "e":"AQAB",
    40        "d":"kLdtIj6GbDks_ApCSTYQtelcNttlKiOyPzMrXHeI-yk1F7-kpDxY4-WY5NWV5KntaEeXS1j82E375xxhWMHXyvjYecPT9fpwR_M9gV8n9Hrh2anTpTD93Dt62ypW3yDsJzBnTnrYu1iwWRgBKrEYY46qAZIrA2xAwnm2X7uGR1hghkqDp0Vqj3kbSCz1XyfCs6_LehBwtxHIyh8Ripy40p24moOAbgxVw3rxT_vlt3UVe4WO3JkJOzlpUf-KTVI2Ptgm-dARxTEtE-id-4OJr0h-K-VFs3VSndVTIznSxfyrj8ILL6MG_Uv8YAu7VILSB3lOW085-4qE3DzgrTjgyQ",
    41        "p":"1r52Xk46c-LsfB5P442p7atdPUrxQSy4mti_tZI3Mgf2EuFVbUoDBvaRQ-SWxkbkmoEzL7JXroSBjSrK3YIQgYdMgyAEPTPjXv_hI2_1eTSPVZfzL0lffNn03IXqWF5MDFuoUYE0hzb2vhrlN_rKrbfDIwUbTrjjgieRbwC6Cl0",
    42        "q":"wLb35x7hmQWZsWJmB_vle87ihgZ19S8lBEROLIsZG4ayZVe9Hi9gDVCOBmUDdaDYVTSNx_8Fyw1YYa9XGrGnDew00J28cRUoeBB_jKI1oma0Orv1T9aXIWxKwd4gvxFImOWr3QRL9KEBRzk2RatUBnmDZJTIAfwTs0g68UZHvtc",
    43        "dp":"ZK-YwE7diUh0qR1tR7w8WHtolDx3MZ_OTowiFvgfeQ3SiresXjm9gZ5KLhMXvo-uz-KUJWDxS5pFQ_M0evdo1dKiRTjVw_x4NyqyXPM5nULPkcpU827rnpZzAJKpdhWAgqrXGKAECQH0Xt4taznjnd_zVpAmZZq60WPMBMfKcuE",
    44        "dq":"Dq0gfgJ1DdFGXiLvQEZnuKEN0UUmsJBxkjydc3j4ZYdBiMRAy86x0vHCjywcMlYYg4yoC4YZa9hNVcsjqA3FeiL19rk8g6Qn29Tt0cj8qqyFpz9vNDBUfCAiJVeESOjJDZPYHdHY8v1b-o-Z2X5tvLx-TCekf7oxyeKDUqKWjis",
    45        "qi":"VIMpMYbPf47dT1w_zDUXfPimsSegnMOA1zTaX7aGk_8urY6R8-ZW1FxU7AlWAyLWybqq6t16VFd7hQd0y6flUK4SlOydB61gwanOsXGOAOv82cHq0E3eL4HrtZkUuKvnPrMnsUUFlfUdybVzxyjz9JF_XyaY14ardLSjf4L_FNY"
    46       }`)
    47  
    48  	privkey, err := jwk.ParseKey(jwkstr)
    49  	if err != nil {
    50  		panic(err)
    51  	}
    52  
    53  	if err := privkey.Raw(&rsaPrivKey); err != nil {
    54  		panic(err)
    55  	}
    56  }
    57  
    58  func TestSanityCheck_JWEExamplePayload(t *testing.T) {
    59  	expected := []byte{
    60  		84, 104, 101, 32, 116, 114, 117, 101, 32, 115, 105, 103, 110, 32,
    61  		111, 102, 32, 105, 110, 116, 101, 108, 108, 105, 103, 101, 110, 99,
    62  		101, 32, 105, 115, 32, 110, 111, 116, 32, 107, 110, 111, 119, 108,
    63  		101, 100, 103, 101, 32, 98, 117, 116, 32, 105, 109, 97, 103, 105,
    64  		110, 97, 116, 105, 111, 110, 46,
    65  	}
    66  	assert.Equal(t, expected, []byte(examplePayload), "examplePayload OK")
    67  }
    68  
    69  func TestParse(t *testing.T) {
    70  	const s = `eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg.48V1_ALb6US04U3b.5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ`
    71  	t.Run("Compact format", func(t *testing.T) {
    72  		t.Run("Normal", func(t *testing.T) {
    73  			msg, err := jwe.Parse([]byte(s))
    74  			if !assert.NoError(t, err, "Parsing JWE is successful") {
    75  				return
    76  			}
    77  			if !assert.Len(t, msg.Recipients(), 1, "There is exactly 1 recipient") {
    78  				return
    79  			}
    80  		})
    81  
    82  		parts := strings.Split(s, ".")
    83  		t.Run("Missing parts", func(t *testing.T) {
    84  			s2 := strings.Join(parts[:4], ".")
    85  			_, err := jwe.Parse([]byte(s2))
    86  			if !assert.Error(t, err, `should fail to parse compact format with missing parts`) {
    87  				return
    88  			}
    89  		})
    90  		t.Run("Invalid header", func(t *testing.T) {
    91  			s2 := strings.Join(append(append([]string(nil), "!!invalidheader!!"), parts[1:]...), ".")
    92  			_, err := jwe.Parse([]byte(s2))
    93  			if !assert.Error(t, err, `should fail to parse compact format with invalid header`) {
    94  				return
    95  			}
    96  		})
    97  		t.Run("Invalid encrypted key", func(t *testing.T) {
    98  			s2 := strings.Join(append(append(append([]string(nil), parts[0]), "!!invalidenckey!!"), parts[2:]...), ".")
    99  			_, err := jwe.Parse([]byte(s2))
   100  			if !assert.Error(t, err, `should fail to parse compact format with invalid encrypted key`) {
   101  				return
   102  			}
   103  		})
   104  		t.Run("Invalid initialization vector", func(t *testing.T) {
   105  			s2 := strings.Join(append(append(append([]string(nil), parts[:2]...), "!!invalidiv!!"), parts[3:]...), ".")
   106  			_, err := jwe.Parse([]byte(s2))
   107  			if !assert.Error(t, err, `should fail to parse compact format with invalid initialization vector`) {
   108  				return
   109  			}
   110  		})
   111  		t.Run("Invalid content", func(t *testing.T) {
   112  			s2 := strings.Join(append(append(append([]string(nil), parts[:3]...), "!!invalidcontent!!"), parts[4:]...), ".")
   113  			_, err := jwe.Parse([]byte(s2))
   114  			if !assert.Error(t, err, `should fail to parse compact format with invalid content`) {
   115  				return
   116  			}
   117  		})
   118  		t.Run("Invalid tag", func(t *testing.T) {
   119  			s2 := strings.Join(append(parts[:4], "!!invalidtag!!"), ".")
   120  			_, err := jwe.Parse([]byte(s2))
   121  			if !assert.Error(t, err, `should fail to parse compact format with invalid tag`) {
   122  				return
   123  			}
   124  		})
   125  	})
   126  	t.Run("JSON format", func(t *testing.T) {
   127  		msg, err := jwe.Parse([]byte(s))
   128  		if !assert.NoError(t, err, "Parsing JWE is successful") {
   129  			return
   130  		}
   131  
   132  		buf, err := json.Marshal(msg)
   133  		if !assert.NoError(t, err, "Serializing to JSON format should succeed") {
   134  			return
   135  		}
   136  
   137  		msg2, err := jwe.Parse(buf)
   138  		if !assert.NoError(t, err, "Parsing JWE in JSON format should succeed") {
   139  			return
   140  		}
   141  
   142  		if !assert.Equal(t, msg, msg2, "messages should match") {
   143  			return
   144  		}
   145  	})
   146  }
   147  
   148  // This test parses the example found in https://tools.ietf.org/html/rfc7516#appendix-A.1,
   149  // and checks if we can roundtrip to the same compact serialization format.
   150  func TestParse_RSAES_OAEP_AES_GCM(t *testing.T) {
   151  	const payload = `The true sign of intelligence is not knowledge but imagination.`
   152  	const serialized = `eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg.48V1_ALb6US04U3b.5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ`
   153  	var jwkstr = []byte(`
   154       {"kty":"RSA",
   155        "n":"oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUWcJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3Spsk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2asbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMStPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2djYgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw",
   156        "e":"AQAB",
   157        "d":"kLdtIj6GbDks_ApCSTYQtelcNttlKiOyPzMrXHeI-yk1F7-kpDxY4-WY5NWV5KntaEeXS1j82E375xxhWMHXyvjYecPT9fpwR_M9gV8n9Hrh2anTpTD93Dt62ypW3yDsJzBnTnrYu1iwWRgBKrEYY46qAZIrA2xAwnm2X7uGR1hghkqDp0Vqj3kbSCz1XyfCs6_LehBwtxHIyh8Ripy40p24moOAbgxVw3rxT_vlt3UVe4WO3JkJOzlpUf-KTVI2Ptgm-dARxTEtE-id-4OJr0h-K-VFs3VSndVTIznSxfyrj8ILL6MG_Uv8YAu7VILSB3lOW085-4qE3DzgrTjgyQ",
   158        "p":"1r52Xk46c-LsfB5P442p7atdPUrxQSy4mti_tZI3Mgf2EuFVbUoDBvaRQ-SWxkbkmoEzL7JXroSBjSrK3YIQgYdMgyAEPTPjXv_hI2_1eTSPVZfzL0lffNn03IXqWF5MDFuoUYE0hzb2vhrlN_rKrbfDIwUbTrjjgieRbwC6Cl0",
   159        "q":"wLb35x7hmQWZsWJmB_vle87ihgZ19S8lBEROLIsZG4ayZVe9Hi9gDVCOBmUDdaDYVTSNx_8Fyw1YYa9XGrGnDew00J28cRUoeBB_jKI1oma0Orv1T9aXIWxKwd4gvxFImOWr3QRL9KEBRzk2RatUBnmDZJTIAfwTs0g68UZHvtc",
   160        "dp":"ZK-YwE7diUh0qR1tR7w8WHtolDx3MZ_OTowiFvgfeQ3SiresXjm9gZ5KLhMXvo-uz-KUJWDxS5pFQ_M0evdo1dKiRTjVw_x4NyqyXPM5nULPkcpU827rnpZzAJKpdhWAgqrXGKAECQH0Xt4taznjnd_zVpAmZZq60WPMBMfKcuE",
   161        "dq":"Dq0gfgJ1DdFGXiLvQEZnuKEN0UUmsJBxkjydc3j4ZYdBiMRAy86x0vHCjywcMlYYg4yoC4YZa9hNVcsjqA3FeiL19rk8g6Qn29Tt0cj8qqyFpz9vNDBUfCAiJVeESOjJDZPYHdHY8v1b-o-Z2X5tvLx-TCekf7oxyeKDUqKWjis",
   162        "qi":"VIMpMYbPf47dT1w_zDUXfPimsSegnMOA1zTaX7aGk_8urY6R8-ZW1FxU7AlWAyLWybqq6t16VFd7hQd0y6flUK4SlOydB61gwanOsXGOAOv82cHq0E3eL4HrtZkUuKvnPrMnsUUFlfUdybVzxyjz9JF_XyaY14ardLSjf4L_FNY"
   163       }`)
   164  
   165  	privkey, err := jwk.ParseKey(jwkstr)
   166  	if !assert.NoError(t, err, `parsing jwk should succeed`) {
   167  		return
   168  	}
   169  
   170  	var rawkey rsa.PrivateKey
   171  	if !assert.NoError(t, privkey.Raw(&rawkey), `obtaining raw key should succeed`) {
   172  		return
   173  	}
   174  
   175  	msg := jwe.NewMessage()
   176  	plaintext, err := jwe.Decrypt([]byte(serialized), jwe.WithKey(jwa.RSA_OAEP, rawkey), jwe.WithMessage(msg))
   177  	if !assert.NoError(t, err, "jwe.Decrypt should be successful") {
   178  		return
   179  	}
   180  
   181  	if !assert.Equal(t, 1, len(msg.Recipients()), "message recipients header length is 1") {
   182  		return
   183  	}
   184  
   185  	if !assert.Equal(t, payload, string(plaintext), "decrypted value does not match") {
   186  		return
   187  	}
   188  
   189  	templates := []*struct {
   190  		Name     string
   191  		Options  []jwe.EncryptOption
   192  		Expected string
   193  	}{
   194  		{
   195  			Name:     "Compact",
   196  			Options:  []jwe.EncryptOption{jwe.WithCompact()},
   197  			Expected: serialized,
   198  		},
   199  		{
   200  			Name:     "JSON",
   201  			Options:  []jwe.EncryptOption{jwe.WithJSON()},
   202  			Expected: `{"ciphertext":"5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A","iv":"48V1_ALb6US04U3b","protected":"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ","header":{"alg":"RSA-OAEP"},"encrypted_key":"OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg","tag":"XFBoMYUZodetZdvTiFvSkQ"}`,
   203  		},
   204  		{
   205  			Name:    "JSON (Pretty)",
   206  			Options: []jwe.EncryptOption{jwe.WithJSON(jwe.WithPretty(true))},
   207  			Expected: `{
   208    "ciphertext": "5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A",
   209    "iv": "48V1_ALb6US04U3b",
   210    "protected": "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ",
   211    "header": {
   212      "alg": "RSA-OAEP"
   213    },
   214    "encrypted_key": "OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg",
   215    "tag": "XFBoMYUZodetZdvTiFvSkQ"
   216  }`,
   217  		},
   218  	}
   219  
   220  	ntmpl := len(templates)
   221  	testcases := make([]struct {
   222  		Name     string
   223  		Options  []jwe.EncryptOption
   224  		Expected string
   225  	}, ntmpl*2)
   226  
   227  	for i, tmpl := range templates {
   228  		options := make([]jwe.EncryptOption, len(tmpl.Options))
   229  		copy(options, tmpl.Options)
   230  
   231  		for j, compression := range []jwa.CompressionAlgorithm{jwa.NoCompress, jwa.Deflate} {
   232  			compName := compression.String()
   233  			if compName == "" {
   234  				compName = "none"
   235  			}
   236  			tc := testcases[i+j]
   237  			tc.Name = tmpl.Name + " (compression=" + compName + ")"
   238  			tc.Expected = tmpl.Expected
   239  			tc.Options = append(options, jwe.WithCompress(compression))
   240  		}
   241  	}
   242  
   243  	for _, tc := range testcases {
   244  		tc := tc
   245  		t.Run(tc.Name, func(t *testing.T) {
   246  			options := tc.Options
   247  			options = append(options, jwe.WithKey(jwa.RSA_OAEP, rawkey.PublicKey))
   248  
   249  			encrypted, err := jwe.Encrypt(plaintext, options...)
   250  			if !assert.NoError(t, err, "jwe.Encrypt should succeed") {
   251  				return
   252  			}
   253  			t.Logf("%s", encrypted)
   254  
   255  			t.Run("WithKey", func(t *testing.T) {
   256  				plaintext, err = jwe.Decrypt(encrypted, jwe.WithKey(jwa.RSA_OAEP, rawkey))
   257  				if !assert.NoError(t, err, "jwe.Decrypt should succeed") {
   258  					return
   259  				}
   260  
   261  				if !assert.Equal(t, payload, string(plaintext), "jwe.Decrypt should produce the same plaintext") {
   262  					return
   263  				}
   264  			})
   265  			t.Run("WithKeySet", func(t *testing.T) {
   266  				pkJwk, err := jwk.FromRaw(rawkey)
   267  				if !assert.NoError(t, err, `jwk.New should succeed`) {
   268  					return
   269  				}
   270  				// Keys are not going to be selected without an algorithm
   271  				_ = pkJwk.Set(jwe.AlgorithmKey, jwa.RSA_OAEP)
   272  				set := jwk.NewSet()
   273  				set.AddKey(pkJwk)
   274  
   275  				var used interface{}
   276  				plaintext, err = jwe.Decrypt(encrypted, jwe.WithKeySet(set, jwe.WithRequireKid(false)), jwe.WithKeyUsed(&used))
   277  				if !assert.NoError(t, err, "jwe.Decrypt should succeed") {
   278  					return
   279  				}
   280  
   281  				if !assert.Equal(t, payload, string(plaintext), "jwe.Decrypt should produce the same plaintext") {
   282  					return
   283  				}
   284  
   285  				if !assert.Equal(t, pkJwk, used) {
   286  					return
   287  				}
   288  			})
   289  		})
   290  	}
   291  
   292  	// Test direct marshaling and unmarshaling
   293  	t.Run("Marshal/Unmarshal", func(t *testing.T) {
   294  		buf, err := json.Marshal(msg)
   295  		if !assert.NoError(t, err, `json.Marshal should succeed`) {
   296  			return
   297  		}
   298  
   299  		m2 := jwe.NewMessage()
   300  		if !assert.NoError(t, json.Unmarshal(buf, m2), `json.Unmarshal should succeed`) {
   301  			t.Logf("%s", buf)
   302  			return
   303  		}
   304  
   305  		if !assert.Equal(t, msg, m2, `messages should be the same after roundtrip`) {
   306  			return
   307  		}
   308  	})
   309  }
   310  
   311  // https://tools.ietf.org/html/rfc7516#appendix-A.1.
   312  func TestRoundtrip_RSAES_OAEP_AES_GCM(t *testing.T) {
   313  	var plaintext = []byte{
   314  		84, 104, 101, 32, 116, 114, 117, 101, 32, 115, 105, 103, 110, 32,
   315  		111, 102, 32, 105, 110, 116, 101, 108, 108, 105, 103, 101, 110, 99,
   316  		101, 32, 105, 115, 32, 110, 111, 116, 32, 107, 110, 111, 119, 108,
   317  		101, 100, 103, 101, 32, 98, 117, 116, 32, 105, 109, 97, 103, 105,
   318  		110, 97, 116, 105, 111, 110, 46,
   319  	}
   320  
   321  	max := 100
   322  	if testing.Short() {
   323  		max = 1
   324  	}
   325  
   326  	for i := 0; i < max; i++ {
   327  		encrypted, err := jwe.Encrypt(plaintext, jwe.WithKey(jwa.RSA_OAEP, &rsaPrivKey.PublicKey))
   328  		if !assert.NoError(t, err, "Encrypt should succeed") {
   329  			return
   330  		}
   331  
   332  		decrypted, err := jwe.Decrypt(encrypted, jwe.WithKey(jwa.RSA_OAEP, rsaPrivKey))
   333  		if !assert.NoError(t, err, "Decrypt should succeed") {
   334  			return
   335  		}
   336  
   337  		if !assert.Equal(t, plaintext, decrypted, "Decrypted content should match") {
   338  			return
   339  		}
   340  	}
   341  }
   342  
   343  func TestRoundtrip_RSA1_5_A128CBC_HS256(t *testing.T) {
   344  	var plaintext = []byte{
   345  		76, 105, 118, 101, 32, 108, 111, 110, 103, 32, 97, 110, 100, 32,
   346  		112, 114, 111, 115, 112, 101, 114, 46,
   347  	}
   348  
   349  	max := 100
   350  	if testing.Short() {
   351  		max = 1
   352  	}
   353  
   354  	for i := 0; i < max; i++ {
   355  		encrypted, err := jwe.Encrypt(plaintext, jwe.WithKey(jwa.RSA1_5, &rsaPrivKey.PublicKey), jwe.WithContentEncryption(jwa.A128CBC_HS256))
   356  		if !assert.NoError(t, err, "Encrypt is successful") {
   357  			return
   358  		}
   359  
   360  		decrypted, err := jwe.Decrypt(encrypted, jwe.WithKey(jwa.RSA1_5, rsaPrivKey))
   361  		if !assert.NoError(t, err, "Decrypt successful") {
   362  			return
   363  		}
   364  
   365  		if !assert.Equal(t, plaintext, decrypted, "Decrypted correct plaintext") {
   366  			return
   367  		}
   368  	}
   369  }
   370  
   371  // https://tools.ietf.org/html/rfc7516#appendix-A.3. Note that cek is dynamically
   372  // generated, so the encrypted values will NOT match that of the RFC.
   373  func TestEncode_A128KW_A128CBC_HS256(t *testing.T) {
   374  	var plaintext = []byte{
   375  		76, 105, 118, 101, 32, 108, 111, 110, 103, 32, 97, 110, 100, 32,
   376  		112, 114, 111, 115, 112, 101, 114, 46,
   377  	}
   378  	var sharedkey = []byte{
   379  		25, 172, 32, 130, 225, 114, 26, 181, 138, 106, 254, 192, 95, 133, 74, 82,
   380  	}
   381  
   382  	max := 100
   383  	if testing.Short() {
   384  		max = 1
   385  	}
   386  
   387  	for i := 0; i < max; i++ {
   388  		encrypted, err := jwe.Encrypt(plaintext, jwe.WithKey(jwa.A128KW, sharedkey), jwe.WithContentEncryption(jwa.A128CBC_HS256))
   389  		if !assert.NoError(t, err, "Encrypt is successful") {
   390  			return
   391  		}
   392  
   393  		decrypted, err := jwe.Decrypt(encrypted, jwe.WithKey(jwa.A128KW, sharedkey))
   394  		if !assert.NoError(t, err, "Decrypt successful") {
   395  			return
   396  		}
   397  
   398  		if !assert.Equal(t, plaintext, decrypted, "Decrypted correct plaintext") {
   399  			return
   400  		}
   401  	}
   402  }
   403  
   404  //nolint:thelper
   405  func testEncodeECDHWithKey(t *testing.T, privkey interface{}, pubkey interface{}) {
   406  	plaintext := []byte("Lorem ipsum")
   407  
   408  	algorithms := []jwa.KeyEncryptionAlgorithm{
   409  		jwa.ECDH_ES,
   410  		jwa.ECDH_ES_A256KW,
   411  		jwa.ECDH_ES_A192KW,
   412  		jwa.ECDH_ES_A128KW,
   413  	}
   414  
   415  	for _, alg := range algorithms {
   416  		alg := alg
   417  		t.Run(alg.String(), func(t *testing.T) {
   418  			encrypted, err := jwe.Encrypt(plaintext, jwe.WithKey(alg, pubkey))
   419  			if !assert.NoError(t, err, "Encrypt succeeds") {
   420  				return
   421  			}
   422  
   423  			_, err = jwe.Parse(encrypted)
   424  			if !assert.NoError(t, err, `jwe.Parse should succeed`) {
   425  				return
   426  			}
   427  
   428  			decrypted, err := jwe.Decrypt(encrypted, jwe.WithKey(alg, privkey))
   429  			if !assert.NoError(t, err, "Decrypt succeeds") {
   430  				return
   431  			}
   432  			t.Logf("%s", decrypted)
   433  		})
   434  	}
   435  }
   436  
   437  func TestEncode_ECDH(t *testing.T) {
   438  	curves := []elliptic.Curve{
   439  		elliptic.P256(),
   440  		elliptic.P384(),
   441  		elliptic.P521(),
   442  	}
   443  	for _, crv := range curves {
   444  		crv := crv
   445  		t.Run(crv.Params().Name, func(t *testing.T) {
   446  			privkey, err := ecdsa.GenerateKey(crv, rand.Reader)
   447  			if !assert.NoError(t, err, `ecdsa.GenerateKey should succeed`) {
   448  				return
   449  			}
   450  
   451  			testEncodeECDHWithKey(t, privkey, &privkey.PublicKey)
   452  		})
   453  	}
   454  }
   455  
   456  func TestEncode_X25519(t *testing.T) {
   457  	pubkey, privkey, err := x25519.GenerateKey(rand.Reader)
   458  	if !assert.NoError(t, err, `x25519.GenerateKey should succeed`) {
   459  		return
   460  	}
   461  
   462  	testEncodeECDHWithKey(t, privkey, pubkey)
   463  }
   464  
   465  func Test_GHIssue207(t *testing.T) {
   466  	const plaintext = "hi\n"
   467  	var testcases = []struct {
   468  		Algorithm  jwa.KeyEncryptionAlgorithm
   469  		Key        string
   470  		Data       string
   471  		Thumbprint string
   472  		Name       string
   473  	}{
   474  		{
   475  			Name:       `ECDH-ES`,
   476  			Key:        `{"alg":"ECDH-ES","crv":"P-521","d":"ARxUkIjnB7pjFzM2OIIFcclR-4qbZwv7DoC96cksPKyvVWOkEsZ0CK6deM4AC6G5GClR5TXWMQVC_bNDmfuwPPqF","key_ops":["wrapKey","unwrapKey"],"kty":"EC","x":"ACewmG5j0POUDQw3rIqFQozK_6yXUsfNjiZtWqQOU7MXsSKK9RsRS8ySmeTG14heUpbbnrC9VdYKSOUGkYnYUl2Y","y":"ACkXSOma_FP93R3u5uYX7gUOlM0LDkNsij9dVFPbafF8hlfYEnUGit2o-tt7W0Zq3t38jEhpjUoGgM04JDJ6_m0x"}`,
   477  			Data:       `{"ciphertext":"sp0cLt4Rx1p0Ax0Q1OZj7w","header":{"alg":"ECDH-ES","epk":{"crv":"P-521","kty":"EC","x":"APMKQpje5vu39-eS_LX_g15stqbNZ37GgYimW8PZf7d_OOuAygK2YlINYnPoUybrxkoaLRPhbmxc9MBWFdaY8SXx","y":"AMpq4DFi6w-pfnprO58CkfX-ncXtJ8fvox2Ej8Ey3ZY1xjVUtbDJCDCjY53snYaNCEjnFQPAn-IkAG90p2Xcm8ut"}},"iv":"Fjnb5uUWp9euqp1MK_hT4A","protected":"eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0","tag":"6nhiy-vyqwVjpy08jrorTpWqvam66HdKxU36XsE3Z3s"}`,
   478  			Thumbprint: `0_6x6e2sZKeq3ka0QV0PEkJagqg`,
   479  		},
   480  		{
   481  			Name:       `ECDH-ES+A256KW`,
   482  			Key:        `{"alg":"ECDH-ES+A256KW","crv":"P-521","d":"AcH8h_ctsMnopTiCH7wiuM-nAb1CNikC0ubcOZQDLYSVEw93h6_D57aD7DLWbjIsVNzn7Qq8P-kRiTYVoH5GTQVg","key_ops":["wrapKey","unwrapKey"],"kty":"EC","x":"AAQoEbNeiG3ExYj9bJLGFn4h_bFjERfIcmpQMW5KWlFhqcXTFg0g8-5YWjdJXdNmO_2EuaKe7zOvEq8dCFCb12-R","y":"Ad8E2jp6FSCSd8laERqIt67A2T-MIqQE5301jNYb5SMsCSV1rs1McyvhzHaclYcqTUptoA-rW5kNS9N5124XPHky"}`,
   483  			Data:       `{"ciphertext":"evXmzoQ5TWQvEXdpv9ZCBQ","encrypted_key":"ceVsjF-0LhziK75oHRC-C539hlFJMSbub015a3YtIBgCt7c0IRzkzwoOvo_Jf44FXZi0Vd-4fvDjRkZDzx9DcuDd4ASYDLvW","header":{"alg":"ECDH-ES+A256KW","epk":{"crv":"P-521","kty":"EC","x":"Aad7PFl9cct7WcfM3b_LNkhCHfCotW_nRuarX7GACDyyZkr2dd1g6r3rz-8r2-AyOGD9gc2nhrTEjVHT2W7eu65U","y":"Ab0Mj6BK8g3Fok6oyFlkvKOyquEVxeeJOlsyXKYBputPxFT5Gljr2FoJdViAxVspoSiw1K5oG1h59UBJgPWG4GQV"}},"iv":"KsJgq2xyzE1dZi2BM2xf5g","protected":"eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0","tag":"b6m_nW9vfk6xJugm_-Uuj4cbAQh9ECelLc1ZBfO86L0"}`,
   484  			Thumbprint: `G4OtKQL_qr9Q57atNOU6SJnJxB8`,
   485  		},
   486  	}
   487  
   488  	for _, tc := range testcases {
   489  		tc := tc
   490  		t.Run(tc.Name, func(t *testing.T) {
   491  			webKey, err := jwk.ParseKey([]byte(tc.Key))
   492  			if !assert.NoError(t, err, `jwk.ParseKey should succeed`) {
   493  				return
   494  			}
   495  
   496  			thumbprint, err := webKey.Thumbprint(crypto.SHA1)
   497  			if !assert.NoError(t, err, `jwk.Thumbprint should succeed`) {
   498  				return
   499  			}
   500  
   501  			if !assert.Equal(t, base64.RawURLEncoding.EncodeToString(thumbprint), tc.Thumbprint, `thumbprints should match`) {
   502  				return
   503  			}
   504  
   505  			var key ecdsa.PrivateKey
   506  			if !assert.NoError(t, webKey.Raw(&key), `jwk.Raw should succeed`) {
   507  				return
   508  			}
   509  
   510  			decrypted, err := jwe.Decrypt([]byte(tc.Data), jwe.WithKeyProvider(jwe.KeyProviderFunc(func(_ context.Context, sink jwe.KeySink, r jwe.Recipient, _ *jwe.Message) error {
   511  				sink.Key(r.Headers().Algorithm(), &key)
   512  				return nil
   513  			})))
   514  			if !assert.NoError(t, err, `jwe.Decrypt should succeed`) {
   515  				return
   516  			}
   517  
   518  			if !assert.Equal(t, string(decrypted), plaintext, `plaintext should match`) {
   519  				return
   520  			}
   521  		})
   522  	}
   523  }
   524  
   525  // tests direct key encryption by encrypting-decrypting a plaintext
   526  func TestEncode_Direct(t *testing.T) {
   527  	var testcases = []struct {
   528  		Algorithm jwa.ContentEncryptionAlgorithm
   529  		KeySize   int // in bytes
   530  	}{
   531  		{jwa.A128CBC_HS256, 32},
   532  		{jwa.A128GCM, 16},
   533  		{jwa.A192CBC_HS384, 48},
   534  		{jwa.A192GCM, 24},
   535  		{jwa.A256CBC_HS512, 64},
   536  		{jwa.A256GCM, 32},
   537  	}
   538  	plaintext := []byte("Lorem ipsum")
   539  
   540  	for _, tc := range testcases {
   541  		tc := tc
   542  		t.Run(tc.Algorithm.String(), func(t *testing.T) {
   543  			key := make([]byte, tc.KeySize)
   544  			/*
   545  				_, err := rand.Read(key)
   546  				if !assert.NoError(t, err, "Key generation succeeds") {
   547  					return
   548  				}*/
   549  			for n := 0; n < len(key); {
   550  				w := copy(key[n:], []byte(`12345678`))
   551  				n += w
   552  			}
   553  
   554  			encrypted, err := jwe.Encrypt(plaintext, jwe.WithKey(jwa.DIRECT, key), jwe.WithContentEncryption(tc.Algorithm))
   555  			if !assert.NoError(t, err, `jwe.Encrypt should succeed`) {
   556  				return
   557  			}
   558  			decrypted, err := jwe.Decrypt(encrypted, jwe.WithKey(jwa.DIRECT, key))
   559  			if !assert.NoError(t, err, `jwe.Decrypt should succeed`) {
   560  				return
   561  			}
   562  
   563  			assert.Equal(t, plaintext, decrypted, `jwe.Decrypt should match input plaintext`)
   564  		})
   565  	}
   566  }
   567  
   568  // Decrypts messages generated by `jose` tool. It helps check compatibility with other jwx implementations.
   569  func TestDecodePredefined_Direct(t *testing.T) {
   570  	var testcases = []struct {
   571  		Algorithm  jwa.ContentEncryptionAlgorithm
   572  		Key        string // generated with 'jose jwk gen -i '{"alg":"A128GCM"}' -o key.jwk'
   573  		Thumbprint string // generated with 'jose jwk thp -i key.jwk`
   574  		Data       string // generated with 'jose jwe enc -I msg.txt -k key.jwk -o msg.jwe'
   575  	}{
   576  		{
   577  			jwa.A128CBC_HS256,
   578  			`{"alg":"A128GCM","k":"9hexZKVSV9pZhPNzgXiD8g","key_ops":["encrypt","decrypt"],"kty":"oct"}`,
   579  			`RwW22IemrIJLFwlqZ-OQUe_Lnbo`,
   580  			`{"ciphertext":"FX_px9cuyO_hZfo","encrypted_key":"","header":{"alg":"dir"},"iv":"Z9CRJCFPtpEI5Pwq","protected":"eyJlbmMiOiJBMTI4R0NNIn0","tag":"1iq0MNDX40XVtqGYinhUtQ"}`,
   581  		},
   582  		{
   583  			jwa.A128GCM,
   584  			`{"alg":"A128GCM","k":"9hexZKVSV9pZhPNzgXiD8g","key_ops":["encrypt","decrypt"],"kty":"oct"}`,
   585  			`RwW22IemrIJLFwlqZ-OQUe_Lnbo`,
   586  			`{"ciphertext":"FX_px9cuyO_hZfo","encrypted_key":"","header":{"alg":"dir"},"iv":"Z9CRJCFPtpEI5Pwq","protected":"eyJlbmMiOiJBMTI4R0NNIn0","tag":"1iq0MNDX40XVtqGYinhUtQ"}`,
   587  		},
   588  		{
   589  			jwa.A192CBC_HS384,
   590  			`{"alg":"A128GCM","k":"9hexZKVSV9pZhPNzgXiD8g","key_ops":["encrypt","decrypt"],"kty":"oct"}`,
   591  			`RwW22IemrIJLFwlqZ-OQUe_Lnbo`,
   592  			`{"ciphertext":"FX_px9cuyO_hZfo","encrypted_key":"","header":{"alg":"dir"},"iv":"Z9CRJCFPtpEI5Pwq","protected":"eyJlbmMiOiJBMTI4R0NNIn0","tag":"1iq0MNDX40XVtqGYinhUtQ"}`,
   593  		},
   594  		{
   595  			jwa.A192GCM,
   596  			`{"alg":"A128GCM","k":"9hexZKVSV9pZhPNzgXiD8g","key_ops":["encrypt","decrypt"],"kty":"oct"}`,
   597  			`RwW22IemrIJLFwlqZ-OQUe_Lnbo`,
   598  			`{"ciphertext":"FX_px9cuyO_hZfo","encrypted_key":"","header":{"alg":"dir"},"iv":"Z9CRJCFPtpEI5Pwq","protected":"eyJlbmMiOiJBMTI4R0NNIn0","tag":"1iq0MNDX40XVtqGYinhUtQ"}`,
   599  		},
   600  		{
   601  			jwa.A256CBC_HS512,
   602  			`{"alg":"A128GCM","k":"9hexZKVSV9pZhPNzgXiD8g","key_ops":["encrypt","decrypt"],"kty":"oct"}`,
   603  			`RwW22IemrIJLFwlqZ-OQUe_Lnbo`,
   604  			`{"ciphertext":"FX_px9cuyO_hZfo","encrypted_key":"","header":{"alg":"dir"},"iv":"Z9CRJCFPtpEI5Pwq","protected":"eyJlbmMiOiJBMTI4R0NNIn0","tag":"1iq0MNDX40XVtqGYinhUtQ"}`,
   605  		},
   606  		{
   607  			jwa.A256GCM,
   608  			`{"alg":"A128GCM","k":"9hexZKVSV9pZhPNzgXiD8g","key_ops":["encrypt","decrypt"],"kty":"oct"}`,
   609  			`RwW22IemrIJLFwlqZ-OQUe_Lnbo`,
   610  			`{"ciphertext":"FX_px9cuyO_hZfo","encrypted_key":"","header":{"alg":"dir"},"iv":"Z9CRJCFPtpEI5Pwq","protected":"eyJlbmMiOiJBMTI4R0NNIn0","tag":"1iq0MNDX40XVtqGYinhUtQ"}`,
   611  		},
   612  	}
   613  	plaintext := "Lorem ipsum"
   614  
   615  	for _, tc := range testcases {
   616  		tc := tc
   617  		t.Run(tc.Algorithm.String(), func(t *testing.T) {
   618  			webKey, err := jwk.ParseKey([]byte(tc.Key))
   619  			if !assert.NoError(t, err, `jwk.ParseKey should succeed`) {
   620  				return
   621  			}
   622  
   623  			thumbprint, err := webKey.Thumbprint(crypto.SHA1)
   624  			if !assert.NoError(t, err, `jwk.Thumbprint should succeed`) {
   625  				return
   626  			}
   627  
   628  			if !assert.Equal(t, base64.RawURLEncoding.EncodeToString(thumbprint), tc.Thumbprint, `thumbprints should match`) {
   629  				return
   630  			}
   631  
   632  			var key []byte
   633  			if !assert.NoError(t, webKey.Raw(&key), `jwk.Raw should succeed`) {
   634  				return
   635  			}
   636  
   637  			decrypted, err := jwe.Decrypt([]byte(tc.Data), jwe.WithKey(jwa.DIRECT, key))
   638  			if !assert.NoError(t, err, `jwe.Decrypt should succeed`) {
   639  				return
   640  			}
   641  
   642  			if !assert.Equal(t, plaintext, string(decrypted), `plaintext should match`) {
   643  				return
   644  			}
   645  		})
   646  	}
   647  }
   648  
   649  func TestGHIssue230(t *testing.T) {
   650  	t.Parallel()
   651  
   652  	const data = `{"ciphertext":"wko","encrypted_key":"","iv":"y-wj7nfa-T8XG58z","protected":"eyJhbGciOiJkaXIiLCJjbGV2aXMiOnsicGluIjoidHBtMiIsInRwbTIiOnsiaGFzaCI6InNoYTI1NiIsImp3a19wcml2IjoiQU80QUlCSTFRYjQ2SHZXUmNSRHVxRXdoN2ZWc3hSNE91MVhsOHBRX2hMMTlPeUc3QUJDVG80S2RqWEZYcEFUOWtLeWptVVJPOTVBaXc4U1o4MGZXRmtDMGdEazJLTXEtamJTZU1wcFZFaFJaWEpxQmhWNXVGZ1V0T0J4eUFjRzFZRjhFMW5Ob1dPWk9Eek5EUkRrOE1ZVWZrWVNpS0ZKb2pPZ0UxSjRIZkRoM0lBelY2MFR6V2NWcXJ0QnlwX2EyZ1V2a0JqcGpTeVF2Nmc2amJMSXpEaG10VnZLMmxDazhlMjUzdG1MSDNPQWk0Q0tZcWFZY0tjTTltSTdTRXBpVldlSjZZVFBEdmtORndpa0tNRjE3czVYQUlFUjZpczNNTVBpNkZTOWQ3ZmdMV25hUkpabDVNNUJDMldxN2NsVmYiLCJqd2tfcHViIjoiQUM0QUNBQUxBQUFFMGdBQUFCQUFJREpTSVhRSVVocjVPaDVkNXZWaWVGUDBmZG9pVFd3S1RicXJRRVRhVmx4QyIsImtleSI6ImVjYyJ9fSwiZW5jIjoiQTI1NkdDTSJ9","tag":"lir7v9YbCCZQKf5-yJ0BTQ"}`
   653  
   654  	msg, err := jwe.Parse([]byte(data))
   655  	if !assert.NoError(t, err, `jwe.Parse should succeed`) {
   656  		return
   657  	}
   658  
   659  	compact, err := jwe.Compact(msg)
   660  	if !assert.NoError(t, err, `jwe.Compact should succeed`) {
   661  		return
   662  	}
   663  
   664  	msg2, err := jwe.Parse(compact)
   665  	if !assert.NoError(t, err, `jwe.Parse should succeed`) {
   666  		return
   667  	}
   668  
   669  	if !assert.Equal(t, msg, msg2, `data -> msg -> compact -> msg2 produces msg == msg2`) {
   670  		t.Logf("msg -> %#v", msg)
   671  		t.Logf("msg2 -> %#v", msg2)
   672  		return
   673  	}
   674  }
   675  
   676  func TestReadFile(t *testing.T) {
   677  	const s = `eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg.48V1_ALb6US04U3b.5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ`
   678  
   679  	f, err := os.CreateTemp("", "test-read-file-*.jwe")
   680  	if !assert.NoError(t, err, `os.CreateTemp should succeed`) {
   681  		return
   682  	}
   683  	defer f.Close()
   684  
   685  	fmt.Fprintf(f, "%s", s)
   686  
   687  	if _, err := jwe.ReadFile(f.Name()); !assert.NoError(t, err, `jwe.ReadFile should succeed`) {
   688  		return
   689  	}
   690  }
   691  
   692  func TestCustomField(t *testing.T) {
   693  	// XXX has global effect!!!
   694  	jwe.RegisterCustomField(`x-birthday`, time.Time{})
   695  	defer jwe.RegisterCustomField(`x-birthday`, nil)
   696  
   697  	expected := time.Date(2015, 11, 4, 5, 12, 52, 0, time.UTC)
   698  	bdaybytes, _ := expected.MarshalText() // RFC3339
   699  
   700  	plaintext := []byte("Hello, World!")
   701  	rsakey, err := jwxtest.GenerateRsaJwk()
   702  	if !assert.NoError(t, err, `jwxtest.GenerateRsaJwk() should succeed`) {
   703  		return
   704  	}
   705  	pubkey, err := jwk.PublicKeyOf(rsakey)
   706  	if !assert.NoError(t, err, `jwk.PublicKeyOf() should succeed`) {
   707  		return
   708  	}
   709  
   710  	protected := jwe.NewHeaders()
   711  	protected.Set(`x-birthday`, string(bdaybytes))
   712  
   713  	encrypted, err := jwe.Encrypt(plaintext, jwe.WithKey(jwa.RSA_OAEP, pubkey), jwe.WithProtectedHeaders(protected))
   714  	if !assert.NoError(t, err, `jwe.Encrypt should succeed`) {
   715  		return
   716  	}
   717  
   718  	t.Run("jwe.Parse + json.Unmarshal", func(t *testing.T) {
   719  		msg, err := jwe.Parse(encrypted)
   720  		if !assert.NoError(t, err, `jwe.Parse should succeed`) {
   721  			return
   722  		}
   723  
   724  		v, ok := msg.ProtectedHeaders().Get(`x-birthday`)
   725  		if !assert.True(t, ok, `msg.ProtectedHeaders().Get("x-birthday") should succeed`) {
   726  			return
   727  		}
   728  
   729  		if !assert.Equal(t, expected, v, `values should match`) {
   730  			return
   731  		}
   732  
   733  		// Create JSON from jwe.Message
   734  		buf, err := json.Marshal(msg)
   735  		if !assert.NoError(t, err, `json.Marshal should succeed`) {
   736  			return
   737  		}
   738  
   739  		var msg2 jwe.Message
   740  		if !assert.NoError(t, json.Unmarshal(buf, &msg2), `json.Unmarshal should succeed`) {
   741  			return
   742  		}
   743  
   744  		v, ok = msg2.ProtectedHeaders().Get(`x-birthday`)
   745  		if !assert.True(t, ok, `msg2.ProtectedHeaders().Get("x-birthday") should succeed`) {
   746  			return
   747  		}
   748  
   749  		if !assert.Equal(t, expected, v, `values should match`) {
   750  			return
   751  		}
   752  	})
   753  }
   754  
   755  func TestGH554(t *testing.T) {
   756  	const keyID = `very-secret-key`
   757  	const plaintext = `hello world!`
   758  	privkey, err := jwxtest.GenerateEcdsaJwk()
   759  	if !assert.NoError(t, err, `jwxtest.GenerateEcdsaJwk() should succeed`) {
   760  		return
   761  	}
   762  
   763  	_ = privkey.Set(jwk.KeyIDKey, keyID)
   764  
   765  	pubkey, err := jwk.PublicKeyOf(privkey)
   766  	if !assert.NoError(t, err, `jwk.PublicKeyOf() should succeed`) {
   767  		return
   768  	}
   769  
   770  	if !assert.Equal(t, keyID, pubkey.KeyID(), `key ID should match`) {
   771  		return
   772  	}
   773  
   774  	encrypted, err := jwe.Encrypt([]byte(plaintext), jwe.WithKey(jwa.ECDH_ES, pubkey))
   775  	if !assert.NoError(t, err, `jwk.Encrypt() should succeed`) {
   776  		return
   777  	}
   778  
   779  	msg, err := jwe.Parse(encrypted)
   780  	if !assert.NoError(t, err, `jwe.Parse() should succeed`) {
   781  		return
   782  	}
   783  
   784  	recipients := msg.Recipients()
   785  
   786  	// The epk must have the same key ID as the original
   787  	kid := recipients[0].Headers().KeyID()
   788  	if !assert.Equal(t, keyID, kid, `key ID in epk should match`) {
   789  		return
   790  	}
   791  }
   792  
   793  func TestGH803(t *testing.T) {
   794  	privateKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
   795  	require.NoError(t, err, `ecdsa.GenerateKey should succeed`)
   796  
   797  	payload := []byte("Lorem Ipsum")
   798  	apu := []byte(`Alice`)
   799  	apv := []byte(`Bob`)
   800  	hdrs := jwe.NewHeaders()
   801  	hdrs.Set(jwe.AgreementPartyUInfoKey, apu)
   802  	hdrs.Set(jwe.AgreementPartyVInfoKey, apv)
   803  	encrypted, err := jwe.Encrypt(
   804  		payload,
   805  		jwe.WithJSON(),
   806  		jwe.WithKey(jwa.ECDH_ES, privateKey.PublicKey, jwe.WithPerRecipientHeaders(hdrs)),
   807  		jwe.WithContentEncryption(jwa.A128GCM),
   808  	)
   809  	require.NoError(t, err, `jwe.Encrypt should succeed`)
   810  
   811  	var msg jwe.Message
   812  	decrypted, err := jwe.Decrypt(
   813  		encrypted,
   814  		jwe.WithKey(jwa.ECDH_ES, privateKey),
   815  		jwe.WithMessage(&msg),
   816  	)
   817  	require.NoError(t, err, `jwe.Decrypt should succeed`)
   818  	require.Equal(t, payload, decrypted, `decrypt messages match`)
   819  	require.Equal(t, apu, msg.ProtectedHeaders().AgreementPartyUInfo())
   820  	require.Equal(t, apv, msg.ProtectedHeaders().AgreementPartyVInfo())
   821  }
   822  
   823  func TestGH840(t *testing.T) {
   824  	// Go 1.19+ panics if elliptic curve operations are called against
   825  	// a point that's _NOT_ on the curve
   826  	untrustedJWK := []byte(`{
   827  		"kty": "EC",
   828  		"crv": "P-256",
   829  		"x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqx7D4",
   830  		"y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
   831  		"d": "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE"
   832  	}`)
   833  
   834  	privkey, err := jwk.ParseKey(untrustedJWK)
   835  	require.NoError(t, err, `jwk.ParseKey should succeed`)
   836  
   837  	pubkey, err := privkey.PublicKey()
   838  	require.NoError(t, err, `privkey.PublicKey should succeed`)
   839  
   840  	const payload = `Lorem ipsum`
   841  	_, err = jwe.Encrypt([]byte(payload), jwe.WithKey(jwa.ECDH_ES_A128KW, pubkey))
   842  	require.Error(t, err, `jwe.Encrypt should fail (instead of panic)`)
   843  }
   844  
   845  type dummyKeyEncrypterDecrypter struct {
   846  	key []byte
   847  }
   848  
   849  func (kd *dummyKeyEncrypterDecrypter) DecryptKey(_ jwa.KeyEncryptionAlgorithm, cek []byte, _ jwe.Recipient, _ *jwe.Message) ([]byte, error) {
   850  	return bytes.TrimSuffix(cek, kd.key), nil
   851  }
   852  
   853  func (kd *dummyKeyEncrypterDecrypter) Algorithm() jwa.KeyEncryptionAlgorithm {
   854  	return jwa.A128GCMKW
   855  }
   856  
   857  func (kd *dummyKeyEncrypterDecrypter) EncryptKey(key []byte) ([]byte, error) {
   858  	return append(key, kd.key...), nil
   859  }
   860  
   861  var _ jwe.KeyEncrypter = (*dummyKeyEncrypterDecrypter)(nil)
   862  
   863  func TestGH924(t *testing.T) {
   864  	sharedKey := []byte("abra-kadabra")
   865  
   866  	ked := &dummyKeyEncrypterDecrypter{key: sharedKey}
   867  
   868  	payload := []byte("Lorem Ipsum")
   869  	encrypted, err := jwe.Encrypt(
   870  		payload,
   871  		jwe.WithJSON(),
   872  		jwe.WithKey(jwa.A128GCMKW, ked),
   873  		jwe.WithContentEncryption(jwa.A128GCM),
   874  	)
   875  	require.NoError(t, err, `jwe.Encrypt should succeed`)
   876  
   877  	var msg jwe.Message
   878  	decrypted, err := jwe.Decrypt(
   879  		encrypted,
   880  		jwe.WithKey(jwa.A128GCMKW, ked),
   881  		jwe.WithMessage(&msg),
   882  	)
   883  	require.NoError(t, err, `jwe.Decrypt should succeed`)
   884  	require.Equal(t, payload, decrypted, `decrypt messages match`)
   885  }
   886  
   887  func TestGH1001(t *testing.T) {
   888  	rawKey, err := jwxtest.GenerateRsaKey()
   889  	require.NoError(t, err, `jwxtest.GenerateRsaKey should succeed`)
   890  
   891  	encrypted, err := jwe.Encrypt([]byte("Lorem Ipsum"), jwe.WithKey(jwa.RSA_OAEP, rawKey.PublicKey))
   892  	require.NoError(t, err, `jwe.Encrypt should succeed`)
   893  	var cek []byte
   894  	decrypted, err := jwe.Decrypt(encrypted, jwe.WithKey(jwa.RSA_OAEP, rawKey), jwe.WithCEK(&cek))
   895  	require.NoError(t, err, `jwe.Decrypt should succeed`)
   896  
   897  	require.Equal(t, "Lorem Ipsum", string(decrypted), `decrypted message should match`)
   898  	require.NotNil(t, cek, `cek should not be nil`)
   899  
   900  	reEncrypted, err := jwe.EncryptStatic([]byte("Lorem Ipsum"), cek, jwe.WithKey(jwa.RSA_OAEP, rawKey.PublicKey))
   901  	require.NoError(t, err, `jwe.EncryptStatic should succeed`)
   902  
   903  	// sanity. empty CEKs should be rejected
   904  	_, err = jwe.EncryptStatic([]byte("Lorem Ipsum"), nil, jwe.WithKey(jwa.RSA_OAEP, rawKey.PublicKey))
   905  	require.Error(t, err, `jwe.Encryptstatic should fail with empty cek`)
   906  
   907  	cek = []byte(nil)
   908  	decrypted, err = jwe.Decrypt(reEncrypted, jwe.WithKey(jwa.RSA_OAEP, rawKey), jwe.WithCEK(&cek))
   909  	require.NoError(t, err, `jwe.Decrypt should succeed`)
   910  
   911  	require.Equal(t, "Lorem Ipsum", string(decrypted), `decrypted message should match`)
   912  	require.NotNil(t, cek, `cek should not be nil`)
   913  }
   914  
   915  func TestGHSA_7f9x_gw85_8grf(t *testing.T) {
   916  	token := []byte("eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMjU2R0NNIiwicDJjIjoyMDAwMDAwMDAwLCJwMnMiOiJNNzczSnlmV2xlX2FsSXNrc0NOTU9BIn0=.S8B1kXdIR7BM6i_TaGsgqEOxU-1Sgdakp4mHq7UVhn-_REzOiGz2gg.gU_LfzhBXtQdwYjh.9QUIS-RWkLc.m9TudmzUoCzDhHsGGfzmCA")
   917  	key, err := jwk.FromRaw([]byte(`abcdefg`))
   918  	require.NoError(t, err, `jwk.FromRaw should succeed`)
   919  
   920  	{
   921  		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   922  		defer cancel()
   923  
   924  		done := make(chan struct{})
   925  		go func(t *testing.T, done chan struct{}) {
   926  			_, err := jwe.Decrypt(token, jwe.WithKey(jwa.PBES2_HS256_A128KW, key))
   927  			require.Error(t, err, `jwe.Decrypt should fail`)
   928  			close(done)
   929  		}(t, done)
   930  
   931  		select {
   932  		case <-done:
   933  		case <-ctx.Done():
   934  			require.Fail(t, "jwe.Decrypt should not block")
   935  		}
   936  	}
   937  
   938  	// NOTE: HAS GLOBAL EFFECT
   939  	// Should allow for timeout to occur
   940  	jwe.Settings(jwe.WithMaxPBES2Count(100000000000000000))
   941  
   942  	// put it back to normal after the test
   943  	defer jwe.Settings(jwe.WithMaxPBES2Count(10000))
   944  	{
   945  		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   946  		defer cancel()
   947  
   948  		done := make(chan struct{})
   949  		go func(done chan struct{}) {
   950  			_, _ = jwe.Decrypt(token, jwe.WithKey(jwa.PBES2_HS256_A128KW, key))
   951  			close(done)
   952  		}(done)
   953  
   954  		select {
   955  		case <-done:
   956  			require.Fail(t, "jwe.Decrypt should block")
   957  		case <-ctx.Done():
   958  			// timeout occurred as it should
   959  		}
   960  	}
   961  }
   962  
   963  func TestMaxBufferSize(t *testing.T) {
   964  	// NOTE: This has GLOBAL EFFECT
   965  	jwe.Settings(jwe.WithMaxBufferSize(1))
   966  	defer jwe.Settings(jwe.WithMaxBufferSize(0))
   967  
   968  	key, err := jwxtest.GenerateRsaJwk()
   969  	require.NoError(t, err, `jwxtest.GenerateRsaJwk should succeed`)
   970  
   971  	_, err = jwe.Encrypt([]byte("Lorem Ipsum"), jwe.WithContentEncryption(jwa.A128CBC_HS256), jwe.WithKey(jwa.RSA_OAEP, key))
   972  	require.Error(t, err, `jwe.Encrypt should fail`)
   973  }
   974  
   975  func TestMaxDecompressBufferSize(t *testing.T) {
   976  	// This payload size is intentionally set to a small value to avoid
   977  	// causing problems for regular users and CI/CD systems. If you wish to
   978  	// verify that root issue is fixed, you may want to try increasing the
   979  	// payload size to a larger value.
   980  	const payloadSize = 1 << 16
   981  
   982  	privkey, err := rsa.GenerateKey(rand.Reader, 2048)
   983  	require.NoError(t, err, `rsa.GenerateKey should succeed`)
   984  
   985  	pubkey := &privkey.PublicKey
   986  
   987  	wrongPrivkey, err := rsa.GenerateKey(rand.Reader, 2048)
   988  	require.NoError(t, err, `rsa.GenerateKey should succeed`)
   989  	wrongPubkey := &wrongPrivkey.PublicKey
   990  
   991  	payload := strings.Repeat("x", payloadSize)
   992  
   993  	testcases := []struct {
   994  		Name                  string
   995  		GlobalMaxSize         int64
   996  		PublicKey             *rsa.PublicKey
   997  		Error                 bool
   998  		ProcessDecryptOptions func([]jwe.DecryptOption) []jwe.DecryptOption
   999  	}{
  1000  		// This should work, because we set the MaxSize to be large (==payload size)
  1001  		{
  1002  			Name:          "same as payload size",
  1003  			GlobalMaxSize: payloadSize,
  1004  			PublicKey:     pubkey,
  1005  		},
  1006  		// This should fail, because we set the GlobalMaxSize to be smaller than the payload size
  1007  		{
  1008  			Name:          "smaller than payload size",
  1009  			GlobalMaxSize: payloadSize - 1,
  1010  			PublicKey:     pubkey,
  1011  			Error:         true,
  1012  		},
  1013  		// This should fail, because the public key does not match the
  1014  		// private key used to decrypt the payload. In essence this way
  1015  		// we do NOT trigger the root cause of this issue, but we bail out early
  1016  		{
  1017  			Name:          "Wrong PublicKey",
  1018  			GlobalMaxSize: payloadSize,
  1019  			PublicKey:     wrongPubkey,
  1020  			Error:         true,
  1021  		},
  1022  		{
  1023  			Name:          "global=payloadSize-1, per-call=payloadSize",
  1024  			GlobalMaxSize: payloadSize - 1,
  1025  			PublicKey:     pubkey,
  1026  			ProcessDecryptOptions: func(options []jwe.DecryptOption) []jwe.DecryptOption {
  1027  				return append(options, jwe.WithMaxDecompressBufferSize(payloadSize))
  1028  			},
  1029  		},
  1030  		// This should be the last test case to put the value back to default :)
  1031  		{
  1032  			Name:          "Default 10MB globally",
  1033  			GlobalMaxSize: 10 * 1024 * 1024,
  1034  			PublicKey:     pubkey,
  1035  		},
  1036  	}
  1037  	for _, tc := range testcases {
  1038  		tc := tc
  1039  		t.Run(tc.Name, func(t *testing.T) {
  1040  			jwe.Settings(jwe.WithMaxDecompressBufferSize(tc.GlobalMaxSize))
  1041  
  1042  			encrypted, err := jwe.Encrypt([]byte(payload), jwe.WithKey(jwa.RSA_OAEP, tc.PublicKey), jwe.WithContentEncryption("A128CBC-HS256"), jwe.WithCompress(jwa.Deflate))
  1043  
  1044  			require.NoError(t, err, `jwe.Encrypt should succeed`)
  1045  
  1046  			decryptOptions := []jwe.DecryptOption{jwe.WithKey(jwa.RSA_OAEP, privkey)}
  1047  
  1048  			if fn := tc.ProcessDecryptOptions; fn != nil {
  1049  				decryptOptions = fn(decryptOptions)
  1050  			}
  1051  			_, err = jwe.Decrypt(encrypted, decryptOptions...)
  1052  			if tc.Error {
  1053  				require.Error(t, err, `jwe.Decrypt should fail`)
  1054  			} else {
  1055  				require.NoError(t, err, `jwe.Decrypt should succeed`)
  1056  			}
  1057  		})
  1058  	}
  1059  }