github.com/trustbloc/kms-go@v1.1.2/doc/jose/encrypter_decrypter_test.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package jose_test
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/ecdsa"
    12  	"crypto/ed25519"
    13  	"crypto/rand"
    14  	"crypto/rsa"
    15  	_ "embed"
    16  	"encoding/base64"
    17  	"encoding/json"
    18  	"fmt"
    19  	"math/big"
    20  	"strings"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/go-jose/go-jose/v3"
    25  	hybrid "github.com/google/tink/go/hybrid/subtle"
    26  	"github.com/google/tink/go/keyset"
    27  	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
    28  	"github.com/google/tink/go/subtle"
    29  	"github.com/stretchr/testify/require"
    30  
    31  	mockstorage "github.com/trustbloc/kms-go/internal/mock/storage"
    32  
    33  	"github.com/trustbloc/kms-go/crypto/tinkcrypto"
    34  	"github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/composite/ecdh"
    35  	"github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/composite/keyio"
    36  	ecdhpb "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto"
    37  	ariesjose "github.com/trustbloc/kms-go/doc/jose"
    38  	"github.com/trustbloc/kms-go/doc/jose/jwk"
    39  	resolver "github.com/trustbloc/kms-go/doc/jose/kidresolver"
    40  	"github.com/trustbloc/kms-go/doc/util/jwkkid"
    41  	"github.com/trustbloc/kms-go/doc/util/kmsdidkey"
    42  	mockkms "github.com/trustbloc/kms-go/mock/kms"
    43  
    44  	cryptoapi "github.com/trustbloc/kms-go/spi/crypto"
    45  	"github.com/trustbloc/kms-go/spi/kms"
    46  )
    47  
    48  const (
    49  	// EnvelopeEncodingType representing the JWE 'Typ' protected type header for DIDComm V2 (example for tests).
    50  	EnvelopeEncodingType = "application/didcomm-encrypted+json"
    51  	// DIDCommContentEncodingType represent the JWE `Cty` protected type header for DIDComm V2 (example for tests).
    52  	DIDCommContentEncodingType = "application/didcomm-plain+json"
    53  
    54  	compactSerialization   = "Compact"
    55  	fullSerialization      = "Full"
    56  	flattenedSerialization = "Flattened"
    57  )
    58  
    59  //nolint:gocognit,gocyclo
    60  func TestJWEEncryptRoundTrip(t *testing.T) {
    61  	_, err := ariesjose.NewJWEEncrypt("", "", "", "", nil, nil, nil)
    62  	require.EqualError(t, err, "empty recipientsPubKeys list",
    63  		"NewJWEEncrypt should fail with empty recipientPubKeys")
    64  
    65  	singleRecipientNISTPKWError := "jwedecrypt: failed to unwrap cek: [unwrapKey: deriveKEKAndUnwrap:" +
    66  		" failed to AES unwrap key: go-jose/go-jose: key wrap input must be 8 byte blocks]"
    67  
    68  	singleRecipientX25519KWError := "jwedecrypt: failed to unwrap cek: [unwrapKey: deriveKEKAndUnwrap: failed to XC20P " +
    69  		"unwrap key: unwrap support: OKP unwrap invalid key]"
    70  
    71  	multiRecKWError := "jwedecrypt: failed to build recipients WK: unable to read " +
    72  		"JWK: invalid character 's' looking for beginning of value"
    73  
    74  	tests := []struct {
    75  		name             string
    76  		kt               *tinkpb.KeyTemplate
    77  		enc              ariesjose.EncAlg
    78  		keyType          kms.KeyType
    79  		recipientKWError string
    80  		nbRec            int
    81  		useCompact       bool
    82  	}{
    83  		{
    84  			name:             "P-256 ECDH KW and AES256GCM encryption with 2 recipients (Full serialization)",
    85  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
    86  			enc:              ariesjose.A256GCM,
    87  			keyType:          kms.NISTP256ECDHKWType,
    88  			nbRec:            2,
    89  			recipientKWError: multiRecKWError,
    90  		},
    91  		{
    92  			name:             "P-256 ECDH KW and AES256GCM encryption with 1 recipient (Flattened serialization)",
    93  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
    94  			enc:              ariesjose.A256GCM,
    95  			keyType:          kms.NISTP256ECDHKWType,
    96  			nbRec:            1,
    97  			recipientKWError: singleRecipientNISTPKWError,
    98  		},
    99  		{
   100  			name:             "P-256 ECDH KW and AES256GCM encryption with 1 recipient (Compact serialization)",
   101  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   102  			enc:              ariesjose.A256GCM,
   103  			keyType:          kms.NISTP256ECDHKWType,
   104  			nbRec:            1,
   105  			useCompact:       true,
   106  			recipientKWError: singleRecipientNISTPKWError,
   107  		},
   108  		{
   109  			name:             "P-384 ECDH KW and AES256GCM encryption with 2 recipients (Full serialization)",
   110  			kt:               ecdh.NISTP384ECDHKWKeyTemplate(),
   111  			enc:              ariesjose.A256GCM,
   112  			keyType:          kms.NISTP384ECDHKWType,
   113  			nbRec:            2,
   114  			recipientKWError: multiRecKWError,
   115  		},
   116  		{
   117  			name:             "P-384 ECDH KW and AES256GCM encryption with 1 recipient (Flattened serialization)",
   118  			kt:               ecdh.NISTP384ECDHKWKeyTemplate(),
   119  			enc:              ariesjose.A256GCM,
   120  			keyType:          kms.NISTP384ECDHKWType,
   121  			nbRec:            1,
   122  			recipientKWError: singleRecipientNISTPKWError,
   123  		},
   124  		{
   125  			name:             "P-384 ECDH KW and AES256GCM encryption with 1 recipient (Compact serialization)",
   126  			kt:               ecdh.NISTP384ECDHKWKeyTemplate(),
   127  			enc:              ariesjose.A256GCM,
   128  			keyType:          kms.NISTP384ECDHKWType,
   129  			nbRec:            1,
   130  			useCompact:       true,
   131  			recipientKWError: singleRecipientNISTPKWError,
   132  		},
   133  		{
   134  			name:             "P-521 ECDH KW and AES256GCM encryption with 2 recipients (Full serialization)",
   135  			kt:               ecdh.NISTP521ECDHKWKeyTemplate(),
   136  			enc:              ariesjose.A256GCM,
   137  			keyType:          kms.NISTP521ECDHKWType,
   138  			nbRec:            2,
   139  			recipientKWError: multiRecKWError,
   140  		},
   141  		{
   142  			name:             "P-521 ECDH KW and AES256GCM encryption with 1 recipient (Flattened serialization)",
   143  			kt:               ecdh.NISTP521ECDHKWKeyTemplate(),
   144  			enc:              ariesjose.A256GCM,
   145  			keyType:          kms.NISTP521ECDHKWType,
   146  			nbRec:            1,
   147  			recipientKWError: singleRecipientNISTPKWError,
   148  		},
   149  		{
   150  			name:             "P-521 ECDH KW and AES256GCM encryption with 1 recipient (Compact serialization)",
   151  			kt:               ecdh.NISTP521ECDHKWKeyTemplate(),
   152  			enc:              ariesjose.A256GCM,
   153  			keyType:          kms.NISTP521ECDHKWType,
   154  			nbRec:            1,
   155  			useCompact:       true,
   156  			recipientKWError: singleRecipientNISTPKWError,
   157  		},
   158  		{
   159  			name:             "X25519 ECDH KW and AES256GCM encryption with 2 recipients (Full serialization)",
   160  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   161  			enc:              ariesjose.A256GCM,
   162  			keyType:          kms.X25519ECDHKWType,
   163  			nbRec:            2,
   164  			recipientKWError: multiRecKWError,
   165  		},
   166  		{
   167  			name:             "X25519 ECDH KW and AES256GCM encryption with 1 recipient (Flattened serialization)",
   168  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   169  			enc:              ariesjose.A256GCM,
   170  			keyType:          kms.X25519ECDHKWType,
   171  			nbRec:            1,
   172  			recipientKWError: singleRecipientX25519KWError,
   173  		},
   174  		{
   175  			name:             "X25519 ECDH KW and AES256GCM encryption with 1 recipient (Compact serialization)",
   176  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   177  			enc:              ariesjose.A256GCM,
   178  			keyType:          kms.X25519ECDHKWType,
   179  			nbRec:            1,
   180  			useCompact:       true,
   181  			recipientKWError: singleRecipientX25519KWError,
   182  		},
   183  		{
   184  			name:             "P-256 ECDH KW and XChacha20Poly1305 encryption with 2 recipients (Full serialization)",
   185  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   186  			enc:              ariesjose.XC20P,
   187  			keyType:          kms.NISTP256ECDHKWType,
   188  			nbRec:            2,
   189  			recipientKWError: multiRecKWError,
   190  		},
   191  		{
   192  			name:             "P-256 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Flattened serialization)",
   193  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   194  			enc:              ariesjose.XC20P,
   195  			keyType:          kms.NISTP256ECDHKWType,
   196  			nbRec:            1,
   197  			recipientKWError: singleRecipientNISTPKWError,
   198  		},
   199  		{
   200  			name:             "P-256 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Compact serialization)",
   201  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   202  			enc:              ariesjose.XC20P,
   203  			keyType:          kms.NISTP256ECDHKWType,
   204  			nbRec:            1,
   205  			useCompact:       true,
   206  			recipientKWError: singleRecipientNISTPKWError,
   207  		},
   208  		{
   209  			name:             "P-384 ECDH KW and XChacha20Poly1305 encryption with 2 recipients (Full serialization)",
   210  			kt:               ecdh.NISTP384ECDHKWKeyTemplate(),
   211  			enc:              ariesjose.XC20P,
   212  			keyType:          kms.NISTP384ECDHKWType,
   213  			nbRec:            2,
   214  			recipientKWError: multiRecKWError,
   215  		},
   216  		{
   217  			name:             "P-384 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Flattened serialization)",
   218  			kt:               ecdh.NISTP384ECDHKWKeyTemplate(),
   219  			enc:              ariesjose.XC20P,
   220  			keyType:          kms.NISTP384ECDHKWType,
   221  			nbRec:            1,
   222  			recipientKWError: singleRecipientNISTPKWError,
   223  		},
   224  		{
   225  			name:             "P-384 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Compact serialization)",
   226  			kt:               ecdh.NISTP384ECDHKWKeyTemplate(),
   227  			enc:              ariesjose.XC20P,
   228  			keyType:          kms.NISTP384ECDHKWType,
   229  			nbRec:            1,
   230  			useCompact:       true,
   231  			recipientKWError: singleRecipientNISTPKWError,
   232  		},
   233  		{
   234  			name:             "P-521 ECDH KW and XChacha20Poly1305 encryption with 2 recipients (Full serialization)",
   235  			kt:               ecdh.NISTP521ECDHKWKeyTemplate(),
   236  			enc:              ariesjose.XC20P,
   237  			keyType:          kms.NISTP521ECDHKWType,
   238  			nbRec:            2,
   239  			recipientKWError: multiRecKWError,
   240  		},
   241  		{
   242  			name:             "P-521 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Flattened serialization)",
   243  			kt:               ecdh.NISTP521ECDHKWKeyTemplate(),
   244  			enc:              ariesjose.XC20P,
   245  			keyType:          kms.NISTP521ECDHKWType,
   246  			nbRec:            1,
   247  			recipientKWError: singleRecipientNISTPKWError,
   248  		},
   249  		{
   250  			name:             "P-521 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Compact serialization)",
   251  			kt:               ecdh.NISTP521ECDHKWKeyTemplate(),
   252  			enc:              ariesjose.XC20P,
   253  			keyType:          kms.NISTP521ECDHKWType,
   254  			nbRec:            1,
   255  			useCompact:       true,
   256  			recipientKWError: singleRecipientNISTPKWError,
   257  		},
   258  		{
   259  			name:             "X25519 ECDH KW and XChacha20Poly1305 encryption with 2 recipients (Full serialization)",
   260  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   261  			enc:              ariesjose.XC20P,
   262  			keyType:          kms.X25519ECDHKWType,
   263  			nbRec:            2,
   264  			recipientKWError: multiRecKWError,
   265  		},
   266  		{
   267  			name:             "X25519 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Flattened serialization)",
   268  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   269  			enc:              ariesjose.XC20P,
   270  			keyType:          kms.X25519ECDHKWType,
   271  			nbRec:            1,
   272  			recipientKWError: singleRecipientX25519KWError,
   273  		},
   274  		{
   275  			name:             "X25519 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Compact serialization)",
   276  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   277  			enc:              ariesjose.XC20P,
   278  			keyType:          kms.X25519ECDHKWType,
   279  			nbRec:            1,
   280  			useCompact:       true,
   281  			recipientKWError: singleRecipientX25519KWError,
   282  		},
   283  		{
   284  			name:             "P-256 ECDH KW and A128CBCHS256 encryption with 2 recipients (Full serialization)",
   285  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   286  			enc:              ariesjose.A128CBCHS256,
   287  			keyType:          kms.NISTP256ECDHKWType,
   288  			nbRec:            2,
   289  			recipientKWError: multiRecKWError,
   290  		},
   291  		{
   292  			name:             "P-256 ECDH KW and A128CBCHS256 encryption with 1 recipient (Flattened serialization)",
   293  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   294  			enc:              ariesjose.A128CBCHS256,
   295  			keyType:          kms.NISTP256ECDHKWType,
   296  			nbRec:            1,
   297  			recipientKWError: singleRecipientNISTPKWError,
   298  		},
   299  		{
   300  			name:             "P-256 ECDH KW and A128CBCHS256 encryption with 1 recipient (Compact serialization)",
   301  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   302  			enc:              ariesjose.A128CBCHS256,
   303  			keyType:          kms.NISTP256ECDHKWType,
   304  			nbRec:            1,
   305  			useCompact:       true,
   306  			recipientKWError: singleRecipientNISTPKWError,
   307  		},
   308  		{
   309  			name:             "X25519 ECDH KW and A128CBCHS256 encryption with 2 recipients (Full serialization)",
   310  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   311  			enc:              ariesjose.A128CBCHS256,
   312  			keyType:          kms.X25519ECDHKWType,
   313  			nbRec:            2,
   314  			recipientKWError: multiRecKWError,
   315  		},
   316  		{
   317  			name:             "X25519 ECDH KW and A128CBCHS256 encryption with 1 recipient (Flattened serialization)",
   318  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   319  			enc:              ariesjose.A128CBCHS256,
   320  			keyType:          kms.X25519ECDHKWType,
   321  			nbRec:            1,
   322  			recipientKWError: singleRecipientX25519KWError,
   323  		},
   324  		{
   325  			name:             "X25519 ECDH KW and A128CBCHS256 encryption with 1 recipient (Compact serialization)",
   326  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   327  			enc:              ariesjose.A128CBCHS256,
   328  			keyType:          kms.X25519ECDHKWType,
   329  			nbRec:            1,
   330  			useCompact:       true,
   331  			recipientKWError: singleRecipientX25519KWError,
   332  		},
   333  		{
   334  			name:             "P-256 ECDH KW and A192CBCHS384 encryption with 2 recipients (Full serialization)",
   335  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   336  			enc:              ariesjose.A192CBCHS384,
   337  			keyType:          kms.NISTP256ECDHKWType,
   338  			nbRec:            2,
   339  			recipientKWError: multiRecKWError,
   340  		},
   341  		{
   342  			name:             "P-256 ECDH KW and A192CBCHS384 encryption with 1 recipient (Flattened serialization)",
   343  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   344  			enc:              ariesjose.A192CBCHS384,
   345  			keyType:          kms.NISTP256ECDHKWType,
   346  			nbRec:            1,
   347  			recipientKWError: singleRecipientNISTPKWError,
   348  		},
   349  		{
   350  			name:             "P-256 ECDH KW and A192CBCHS384 encryption with 1 recipient (Compact serialization)",
   351  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   352  			enc:              ariesjose.A192CBCHS384,
   353  			keyType:          kms.NISTP256ECDHKWType,
   354  			nbRec:            1,
   355  			useCompact:       true,
   356  			recipientKWError: singleRecipientNISTPKWError,
   357  		},
   358  		{
   359  			name:             "X25519 ECDH KW and A192CBCHS384 encryption with 2 recipients (Full serialization)",
   360  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   361  			enc:              ariesjose.A192CBCHS384,
   362  			keyType:          kms.X25519ECDHKWType,
   363  			nbRec:            2,
   364  			recipientKWError: multiRecKWError,
   365  		},
   366  		{
   367  			name:             "X25519 ECDH KW and A192CBCHS384 encryption with 1 recipient (Flattened serialization)",
   368  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   369  			enc:              ariesjose.A192CBCHS384,
   370  			keyType:          kms.X25519ECDHKWType,
   371  			nbRec:            1,
   372  			recipientKWError: singleRecipientX25519KWError,
   373  		},
   374  		{
   375  			name:             "X25519 ECDH KW and A192CBCHS384 encryption with 1 recipient (Compact serialization)",
   376  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   377  			enc:              ariesjose.A192CBCHS384,
   378  			keyType:          kms.X25519ECDHKWType,
   379  			nbRec:            1,
   380  			useCompact:       true,
   381  			recipientKWError: singleRecipientX25519KWError,
   382  		},
   383  		{
   384  			name:             "P-256 ECDH KW and A256CBCHS384 encryption with 2 recipients (Full serialization)",
   385  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   386  			enc:              ariesjose.A256CBCHS384,
   387  			keyType:          kms.NISTP256ECDHKWType,
   388  			nbRec:            2,
   389  			recipientKWError: multiRecKWError,
   390  		},
   391  		{
   392  			name:             "P-256 ECDH KW and A256CBCHS384 encryption with 1 recipient (Flattened serialization)",
   393  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   394  			enc:              ariesjose.A256CBCHS384,
   395  			keyType:          kms.NISTP256ECDHKWType,
   396  			nbRec:            1,
   397  			recipientKWError: singleRecipientNISTPKWError,
   398  		},
   399  		{
   400  			name:             "P-256 ECDH KW and A256CBCHS384 encryption with 1 recipient (Compact serialization)",
   401  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   402  			enc:              ariesjose.A256CBCHS384,
   403  			keyType:          kms.NISTP256ECDHKWType,
   404  			nbRec:            1,
   405  			useCompact:       true,
   406  			recipientKWError: singleRecipientNISTPKWError,
   407  		},
   408  		{
   409  			name:             "X25519 ECDH KW and A256CBCHS384 encryption with 2 recipients (Full serialization)",
   410  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   411  			enc:              ariesjose.A256CBCHS384,
   412  			keyType:          kms.X25519ECDHKWType,
   413  			nbRec:            2,
   414  			recipientKWError: multiRecKWError,
   415  		},
   416  		{
   417  			name:             "X25519 ECDH KW and A256CBCHS384 encryption with 1 recipient (Flattened serialization)",
   418  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   419  			enc:              ariesjose.A256CBCHS384,
   420  			keyType:          kms.X25519ECDHKWType,
   421  			nbRec:            1,
   422  			recipientKWError: singleRecipientX25519KWError,
   423  		},
   424  		{
   425  			name:             "X25519 ECDH KW and A256CBCHS384 encryption with 1 recipient (Compact serialization)",
   426  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   427  			enc:              ariesjose.A256CBCHS384,
   428  			keyType:          kms.X25519ECDHKWType,
   429  			nbRec:            1,
   430  			useCompact:       true,
   431  			recipientKWError: singleRecipientX25519KWError,
   432  		},
   433  		{
   434  			name:             "P-256 ECDH KW and A256CBCHS512 encryption with 2 recipients (Full serialization)",
   435  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   436  			enc:              ariesjose.A256CBCHS512,
   437  			keyType:          kms.NISTP256ECDHKWType,
   438  			nbRec:            2,
   439  			recipientKWError: multiRecKWError,
   440  		},
   441  		{
   442  			name:             "P-256 ECDH KW and A256CBCHS512 encryption with 1 recipient (Flattened serialization)",
   443  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   444  			enc:              ariesjose.A256CBCHS512,
   445  			keyType:          kms.NISTP256ECDHKWType,
   446  			nbRec:            1,
   447  			recipientKWError: singleRecipientNISTPKWError,
   448  		},
   449  		{
   450  			name:             "P-256 ECDH KW and A256CBCHS512 encryption with 1 recipient (Compact serialization)",
   451  			kt:               ecdh.NISTP256ECDHKWKeyTemplate(),
   452  			enc:              ariesjose.A256CBCHS512,
   453  			keyType:          kms.NISTP256ECDHKWType,
   454  			nbRec:            1,
   455  			useCompact:       true,
   456  			recipientKWError: singleRecipientNISTPKWError,
   457  		},
   458  		{
   459  			name:             "X25519 ECDH KW and A256CBCHS512 encryption with 2 recipients (Full serialization)",
   460  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   461  			enc:              ariesjose.A256CBCHS512,
   462  			keyType:          kms.X25519ECDHKWType,
   463  			nbRec:            2,
   464  			recipientKWError: multiRecKWError,
   465  		},
   466  		{
   467  			name:             "X25519 ECDH KW and A256CBCHS512 encryption with 1 recipient (Flattened serialization)",
   468  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   469  			enc:              ariesjose.A256CBCHS512,
   470  			keyType:          kms.X25519ECDHKWType,
   471  			nbRec:            1,
   472  			recipientKWError: singleRecipientX25519KWError,
   473  		},
   474  		{
   475  			name:             "X25519 ECDH KW and A256CBCHS512 encryption with 1 recipient (Compact serialization)",
   476  			kt:               ecdh.X25519ECDHKWKeyTemplate(),
   477  			enc:              ariesjose.A256CBCHS512,
   478  			keyType:          kms.X25519ECDHKWType,
   479  			nbRec:            1,
   480  			useCompact:       true,
   481  			recipientKWError: singleRecipientX25519KWError,
   482  		},
   483  	}
   484  
   485  	for _, tt := range tests {
   486  		tc := tt
   487  		t.Run(tc.name, func(t *testing.T) {
   488  			t.Log("creating recipients keys..")
   489  			recECKeys, recKHs, _, recDIDKeys := createRecipientsByKeyTemplate(t, tc.nbRec, tc.kt, tc.keyType)
   490  
   491  			cryptoSvc, kmsSvc := createCryptoAndKMSServices(t, recKHs)
   492  
   493  			_, err = ariesjose.NewJWEEncrypt("", "", "", "", nil, recECKeys, cryptoSvc)
   494  			require.EqualError(t, err, "encryption algorithm '' not supported",
   495  				"NewJWEEncrypt should fail with empty encAlg")
   496  
   497  			jweEncrypter, err := ariesjose.NewJWEEncrypt(tc.enc, EnvelopeEncodingType,
   498  				DIDCommContentEncodingType, "", nil, recECKeys, cryptoSvc)
   499  			require.NoError(t, err, "NewJWEEncrypt should not fail with non empty recipientPubKeys")
   500  
   501  			pt := []byte("secret message")
   502  			aad := []byte("aad value")
   503  
   504  			if tc.useCompact { // compact serialization does not use AAD
   505  				aad = nil
   506  			}
   507  
   508  			testEncTime := time.Now()
   509  			jwe, err := jweEncrypter.EncryptWithAuthData(pt, aad)
   510  			t.Logf("ECDH-ES KW in EncryptWithAuthData took %v", time.Since(testEncTime))
   511  			require.NoError(t, err)
   512  			require.Equal(t, len(recECKeys), len(jwe.Recipients))
   513  
   514  			cty, ok := jwe.ProtectedHeaders.ContentType()
   515  			require.True(t, ok)
   516  			require.Equal(t, DIDCommContentEncodingType, cty)
   517  
   518  			typ, ok := jwe.ProtectedHeaders.Type()
   519  			require.True(t, ok)
   520  			require.Equal(t, EnvelopeEncodingType, typ)
   521  
   522  			alg, ok := jwe.ProtectedHeaders.Algorithm()
   523  			if alg != "" {
   524  				require.True(t, ok)
   525  				require.Contains(t, []string{"ECDH-ES+A256KW", "ECDH-ES+XC20PKW"}, alg)
   526  			} else {
   527  				require.False(t, ok)
   528  			}
   529  
   530  			kid, ok := jwe.ProtectedHeaders.KeyID()
   531  			if kid != "" {
   532  				require.True(t, ok)
   533  				require.NotEmpty(t, kid)
   534  			} else {
   535  				require.False(t, ok)
   536  			}
   537  
   538  			var serializedJWE, jweStr string
   539  			serialization := fullSerialization
   540  
   541  			if tc.useCompact {
   542  				testSerTime := time.Now()
   543  				serializedJWE, err = jwe.CompactSerialize(json.Marshal)
   544  				t.Logf("CompactSerilize took %v", time.Since(testSerTime))
   545  				require.NoError(t, err)
   546  				require.NotEmpty(t, serializedJWE)
   547  
   548  				jweStr = serializedJWE
   549  				serialization = compactSerialization
   550  			} else {
   551  				testSerTime := time.Now()
   552  				serializedJWE, err = jwe.FullSerialize(json.Marshal)
   553  				t.Logf("JSON Serialize took %v", time.Since(testSerTime))
   554  				require.NoError(t, err)
   555  				require.NotEmpty(t, serializedJWE)
   556  
   557  				jweStr, err = prettyPrint([]byte(serializedJWE))
   558  				require.NoError(t, err)
   559  				if tc.nbRec == 1 {
   560  					serialization = flattenedSerialization
   561  				}
   562  			}
   563  
   564  			t.Logf("* anoncrypt JWE (%s serialization): %s", serialization, jweStr)
   565  
   566  			mPh, err := json.Marshal(jwe.ProtectedHeaders)
   567  			require.NoError(t, err)
   568  
   569  			protectedHeadersStr, err := prettyPrint(mPh)
   570  			require.NoError(t, err)
   571  
   572  			t.Logf("* protected headers: %s", protectedHeadersStr)
   573  
   574  			// try to deserialize with go-jose (can't decrypt in go-jose since private key is protected by Tink)
   575  			joseJWE, err := jose.ParseEncrypted(serializedJWE)
   576  			require.NoError(t, err)
   577  			require.NotEmpty(t, joseJWE)
   578  
   579  			// try to deserialize with local package
   580  			testDeserTime := time.Now()
   581  			localJWE, err := ariesjose.Deserialize(serializedJWE)
   582  			t.Logf("JWE Deserialize took %v", time.Since(testDeserTime))
   583  			require.NoError(t, err)
   584  
   585  			t.Run("Decrypting JWE tests failures", func(t *testing.T) {
   586  				jweDecrypter := ariesjose.NewJWEDecrypt(nil, cryptoSvc, kmsSvc)
   587  
   588  				// decrypt empty JWE
   589  				_, err = jweDecrypter.Decrypt(nil)
   590  				require.EqualError(t, err, "jwedecrypt: jwe is nil")
   591  
   592  				var badJWE *ariesjose.JSONWebEncryption
   593  
   594  				badJWE, err = ariesjose.Deserialize(serializedJWE)
   595  				require.NoError(t, err)
   596  
   597  				ph := badJWE.ProtectedHeaders
   598  				badJWE.ProtectedHeaders = nil
   599  
   600  				// decrypt JWE with empty ProtectHeaders
   601  				_, err = jweDecrypter.Decrypt(badJWE)
   602  				require.EqualError(t, err, "jwedecrypt: jwe is missing protected headers")
   603  
   604  				badJWE.ProtectedHeaders = ariesjose.Headers{}
   605  				badJWE.ProtectedHeaders["somKey"] = "badKey"
   606  				_, err = jweDecrypter.Decrypt(badJWE)
   607  				require.EqualError(t, err, "jwedecrypt: jwe is missing encryption algorithm 'enc' header")
   608  
   609  				badJWE.ProtectedHeaders = map[string]interface{}{
   610  					ariesjose.HeaderEncryption: "badEncHeader",
   611  					ariesjose.HeaderType:       "test",
   612  				}
   613  
   614  				// decrypt JWE with bad Enc header value
   615  				_, err = jweDecrypter.Decrypt(badJWE)
   616  				require.EqualError(t, err, "jwedecrypt: encryption algorithm 'badEncHeader' not supported")
   617  
   618  				badJWE.ProtectedHeaders = ph
   619  
   620  				// decrypt JWE with invalid recipient key
   621  				badJWE.Recipients = []*ariesjose.Recipient{
   622  					{
   623  						EncryptedKey: "someKey",
   624  						Header: &ariesjose.RecipientHeaders{
   625  							EPK: []byte("somerawbytes"),
   626  						},
   627  					},
   628  				}
   629  
   630  				if tc.nbRec > 1 {
   631  					badJWE.Recipients = append(badJWE.Recipients, &ariesjose.Recipient{
   632  						EncryptedKey: "someOtherKey",
   633  						Header: &ariesjose.RecipientHeaders{
   634  							EPK: []byte("someotherrawbytes"),
   635  						},
   636  					})
   637  				}
   638  
   639  				_, err = jweDecrypter.Decrypt(badJWE)
   640  				require.EqualError(t, err, tc.recipientKWError)
   641  
   642  				// decrypt JWE with unsupported recipient key
   643  				var privKey *rsa.PrivateKey
   644  
   645  				privKey, err = rsa.GenerateKey(rand.Reader, 2048)
   646  
   647  				unsupportedJWK := jwk.JWK{
   648  					JSONWebKey: jose.JSONWebKey{
   649  						Key: &privKey.PublicKey,
   650  					},
   651  				}
   652  
   653  				var mk []byte
   654  
   655  				mk, err = unsupportedJWK.MarshalJSON()
   656  				require.NoError(t, err)
   657  
   658  				badJWE.Recipients = []*ariesjose.Recipient{
   659  					{
   660  						EncryptedKey: "someKey",
   661  						Header: &ariesjose.RecipientHeaders{
   662  							EPK: mk,
   663  						},
   664  					},
   665  				}
   666  
   667  				if tc.nbRec > 1 {
   668  					badJWE.Recipients = append(badJWE.Recipients, &ariesjose.Recipient{
   669  						EncryptedKey: "someOtherKey",
   670  						Header: &ariesjose.RecipientHeaders{
   671  							EPK: mk,
   672  						},
   673  					})
   674  				}
   675  
   676  				_, err = jweDecrypter.Decrypt(badJWE)
   677  				if tc.nbRec == 1 {
   678  					require.EqualError(t, err, tc.recipientKWError)
   679  				} else {
   680  					require.EqualError(t, err, "jwedecrypt: failed to build recipients WK: unsupported recipient key type")
   681  				}
   682  			})
   683  
   684  			t.Run("Decrypting JWE test success ", func(t *testing.T) {
   685  				jweDecrypter := ariesjose.NewJWEDecrypt(nil, cryptoSvc, kmsSvc)
   686  
   687  				var msg []byte
   688  
   689  				testDecTime := time.Now()
   690  				msg, err = jweDecrypter.Decrypt(localJWE)
   691  				t.Logf("JWE Decrypt took %v", time.Since(testDecTime))
   692  				require.NoError(t, err)
   693  				require.EqualValues(t, pt, msg)
   694  			})
   695  
   696  			t.Run("ECDH-ES Encrypt and Decrypt JWE test success with kid as did:key", func(t *testing.T) {
   697  				recKeys := make([]*cryptoapi.PublicKey, 0)
   698  				for i, k := range recECKeys {
   699  					k.KID = recDIDKeys[i]
   700  					recKeys = append(recKeys, k)
   701  				}
   702  
   703  				jweEncrypter, err = ariesjose.NewJWEEncrypt(tc.enc, EnvelopeEncodingType,
   704  					DIDCommContentEncodingType, "", nil, recKeys, cryptoSvc)
   705  				require.NoError(t, err)
   706  
   707  				testEncTime = time.Now()
   708  				jwe, err = jweEncrypter.EncryptWithAuthData(pt, aad)
   709  				t.Logf("ECDH-ES KW in EncryptWithAuthData with kid as did:key took %v", time.Since(testEncTime))
   710  				require.NoError(t, err)
   711  				require.Equal(t, len(recECKeys), len(jwe.Recipients))
   712  
   713  				if tc.useCompact {
   714  					testSerTime := time.Now()
   715  					serializedJWE, err = jwe.CompactSerialize(json.Marshal)
   716  					t.Logf("CompactSerilize JWE with as did:key took %v", time.Since(testSerTime))
   717  					require.NoError(t, err)
   718  					require.NotEmpty(t, serializedJWE)
   719  
   720  					jweStr = serializedJWE
   721  					serialization = compactSerialization
   722  				} else {
   723  					testSerTime := time.Now()
   724  					serializedJWE, err = jwe.FullSerialize(json.Marshal)
   725  					t.Logf("JSON Serialize with kid as did:key took %v", time.Since(testSerTime))
   726  					require.NoError(t, err)
   727  					require.NotEmpty(t, serializedJWE)
   728  
   729  					jweStr, err = prettyPrint([]byte(serializedJWE))
   730  					require.NoError(t, err)
   731  					if tc.nbRec == 1 {
   732  						serialization = flattenedSerialization
   733  					}
   734  				}
   735  
   736  				t.Logf("* anoncrypt JWE (%s serialization) with kid as did:key: %s", serialization, jweStr)
   737  
   738  				// try to deserialize with go-jose (can't decrypt in go-jose since private key is protected by Tink)
   739  				joseJWE, err := jose.ParseEncrypted(serializedJWE)
   740  				require.NoError(t, err)
   741  				require.NotEmpty(t, joseJWE)
   742  
   743  				// try to deserialize with local package
   744  				testDeserTime := time.Now()
   745  				localJWE, err = ariesjose.Deserialize(serializedJWE)
   746  				t.Logf("JWE with kid as did:key Deserialize took %v", time.Since(testDeserTime))
   747  				require.NoError(t, err)
   748  
   749  				jweDecrypter := ariesjose.NewJWEDecrypt([]resolver.KIDResolver{&resolver.DIDKeyResolver{}}, cryptoSvc, kmsSvc)
   750  
   751  				var msg []byte
   752  
   753  				testDecTime := time.Now()
   754  				msg, err = jweDecrypter.Decrypt(localJWE)
   755  				t.Logf("JWE with kid as did:key Decrypt took %v", time.Since(testDecTime))
   756  				require.NoError(t, err)
   757  				require.EqualValues(t, pt, msg)
   758  
   759  				if tc.nbRec > 1 {
   760  					t.Run("decrypt with failing kid resolver", func(t *testing.T) {
   761  						failingResolver := &mockResolver{resolveError: fmt.Errorf("resolve kid failure")}
   762  						jweDecrypter := ariesjose.NewJWEDecrypt([]resolver.KIDResolver{failingResolver}, cryptoSvc, kmsSvc)
   763  
   764  						_, err = jweDecrypter.Decrypt(localJWE)
   765  						require.EqualError(t, err, "jwedecrypt: failed to unwrap cek: [resolveKID: "+
   766  							"[resolve kid failure] resolveKID: [resolve kid failure]]")
   767  					})
   768  				}
   769  			})
   770  		})
   771  	}
   772  }
   773  
   774  type mockResolver struct {
   775  	resolveValue *cryptoapi.PublicKey
   776  	resolveError error
   777  }
   778  
   779  func (m *mockResolver) Resolve(kid string) (*cryptoapi.PublicKey, error) {
   780  	return m.resolveValue, m.resolveError
   781  }
   782  
   783  func TestInteropWithGoJoseEncryptAndLocalJoseDecryptUsingCompactSerialize(t *testing.T) {
   784  	recECKeys, recKHs, recKIDs, _ := createRecipients(t, 1)
   785  	gjRecipients := convertToGoJoseRecipients(t, recECKeys, recKIDs)
   786  
   787  	c, k := createCryptoAndKMSServices(t, recKHs)
   788  
   789  	eo := &jose.EncrypterOptions{}
   790  	gjEncrypter, err := jose.NewEncrypter(jose.A256GCM, gjRecipients[0],
   791  		eo.WithType(EnvelopeEncodingType))
   792  	require.NoError(t, err)
   793  
   794  	pt := []byte("Test secret message")
   795  
   796  	// encrypt pt using go-jose encryption
   797  	gjJWEEncrypter, err := gjEncrypter.Encrypt(pt)
   798  	require.NoError(t, err)
   799  
   800  	// get go-jose serialized JWE
   801  	gjSerializedJWE, err := gjJWEEncrypter.CompactSerialize()
   802  	require.NoError(t, err)
   803  
   804  	// deserialize using local jose package
   805  	localJWE, err := ariesjose.Deserialize(gjSerializedJWE)
   806  	require.NoError(t, err)
   807  
   808  	t.Run("Decrypting JWE message encrypted by go-jose test success", func(t *testing.T) {
   809  		jweDecrypter := ariesjose.NewJWEDecrypt(nil, c, k)
   810  
   811  		var msg []byte
   812  
   813  		msg, err = jweDecrypter.Decrypt(localJWE)
   814  		require.NoError(t, err)
   815  		require.EqualValues(t, pt, msg)
   816  	})
   817  }
   818  
   819  func TestInteropWithGoJoseEncryptAndLocalJoseDecrypt(t *testing.T) {
   820  	recECKeys, recKHs, recKIDs, _ := createRecipients(t, 3)
   821  	gjRecipients := convertToGoJoseRecipients(t, recECKeys, recKIDs)
   822  
   823  	c, k := createCryptoAndKMSServices(t, recKHs)
   824  
   825  	eo := &jose.EncrypterOptions{}
   826  	gjEncrypter, err := jose.NewMultiEncrypter(jose.A256GCM, gjRecipients,
   827  		eo.WithType(EnvelopeEncodingType))
   828  	require.NoError(t, err)
   829  
   830  	pt := []byte("Test secret message")
   831  	aad := []byte("Test some auth data")
   832  
   833  	// encrypt pt using go-jose encryption
   834  	gjJWEEncrypter, err := gjEncrypter.EncryptWithAuthData(pt, aad)
   835  	require.NoError(t, err)
   836  
   837  	// get go-jose serialized JWE
   838  	gjSerializedJWE := gjJWEEncrypter.FullSerialize()
   839  
   840  	// deserialize using local jose package
   841  	localJWE, err := ariesjose.Deserialize(gjSerializedJWE)
   842  	require.NoError(t, err)
   843  
   844  	t.Run("Decrypting JWE message encrypted by go-jose test success", func(t *testing.T) {
   845  		jweDecrypter := ariesjose.NewJWEDecrypt(nil, c, k)
   846  
   847  		var msg []byte
   848  
   849  		msg, err = jweDecrypter.Decrypt(localJWE)
   850  		require.NoError(t, err)
   851  		require.EqualValues(t, pt, msg)
   852  	})
   853  }
   854  
   855  func TestInteropWithLocalJoseEncryptAndGoJoseDecrypt(t *testing.T) {
   856  	c, err := tinkcrypto.New()
   857  	require.NoError(t, err)
   858  
   859  	// get two generated recipient Tink keys
   860  	recECKeys, _, _, _ := createRecipients(t, 2) //nolint:dogsled
   861  	// create a normal recipient key (not using Tink)
   862  	rec3PrivKey, err := ecdsa.GenerateKey(subtle.GetCurve(recECKeys[0].Curve), rand.Reader)
   863  	require.NoError(t, err)
   864  
   865  	// add third key to recECKeys
   866  	recECKeys = append(recECKeys, &cryptoapi.PublicKey{
   867  		X:     rec3PrivKey.PublicKey.X.Bytes(),
   868  		Y:     rec3PrivKey.PublicKey.Y.Bytes(),
   869  		Curve: rec3PrivKey.PublicKey.Curve.Params().Name,
   870  		Type:  "EC",
   871  	})
   872  
   873  	// encrypt using local jose package
   874  	jweEncrypter, err := ariesjose.NewJWEEncrypt(ariesjose.A256GCM, EnvelopeEncodingType, DIDCommContentEncodingType,
   875  		"", nil, recECKeys, c)
   876  	require.NoError(t, err, "NewJWEEncrypt should not fail with non empty recipientPubKeys")
   877  
   878  	pt := []byte("some msg")
   879  	jwe, err := jweEncrypter.EncryptWithAuthData(pt, []byte("aad value"))
   880  	require.NoError(t, err)
   881  	require.Equal(t, len(recECKeys), len(jwe.Recipients))
   882  
   883  	serializedJWE, err := jwe.FullSerialize(json.Marshal)
   884  	require.NoError(t, err)
   885  
   886  	// now parse serializedJWE using go-jose
   887  	gjParsedJWE, err := jose.ParseEncrypted(serializedJWE)
   888  	require.NoError(t, err)
   889  
   890  	// Decrypt with third recipient's private key (non Tink key)
   891  	i, _, msg, err := gjParsedJWE.DecryptMulti(rec3PrivKey)
   892  	require.NoError(t, err)
   893  	require.EqualValues(t, pt, msg)
   894  
   895  	// the third recipient's index is 2
   896  	require.Equal(t, 2, i)
   897  }
   898  
   899  func TestInteropWithLocalJoseEncryptAndGoJoseDecryptUsingCompactSerialization(t *testing.T) {
   900  	var recECKeys []*cryptoapi.PublicKey
   901  	// create a normal recipient key (not using Tink)
   902  	recPrivKey, err := ecdsa.GenerateKey(subtle.GetCurve("NIST_P256"), rand.Reader)
   903  	require.NoError(t, err)
   904  
   905  	c, err := tinkcrypto.New()
   906  	require.NoError(t, err)
   907  
   908  	recECKeys = append(recECKeys, &cryptoapi.PublicKey{
   909  		X:     recPrivKey.PublicKey.X.Bytes(),
   910  		Y:     recPrivKey.PublicKey.Y.Bytes(),
   911  		Curve: recPrivKey.PublicKey.Curve.Params().Name,
   912  		Type:  "EC",
   913  	})
   914  
   915  	// encrypt using local jose package
   916  	jweEncrypter, err := ariesjose.NewJWEEncrypt(ariesjose.A256GCM, EnvelopeEncodingType, DIDCommContentEncodingType,
   917  		"", nil, recECKeys, c)
   918  	require.NoError(t, err, "NewJWEEncrypt should not fail with non empty recipientPubKeys")
   919  
   920  	pt := []byte("some msg")
   921  	jwe, err := jweEncrypter.Encrypt(pt)
   922  	require.NoError(t, err)
   923  	require.Equal(t, len(recECKeys), len(jwe.Recipients))
   924  
   925  	serializedJWE, err := jwe.CompactSerialize(json.Marshal)
   926  	require.NoError(t, err)
   927  
   928  	// now parse serializedJWE using go-jose
   929  	gjParsedJWE, err := jose.ParseEncrypted(serializedJWE)
   930  	require.NoError(t, err)
   931  
   932  	// Decrypt with recipient's private key
   933  	msg, err := gjParsedJWE.Decrypt(recPrivKey)
   934  	require.NoError(t, err)
   935  	require.EqualValues(t, pt, msg)
   936  }
   937  
   938  func convertToGoJoseRecipients(t *testing.T, keys []*cryptoapi.PublicKey, kids []string) []jose.Recipient {
   939  	t.Helper()
   940  
   941  	var joseRecipients []jose.Recipient
   942  
   943  	for i, key := range keys {
   944  		c := subtle.GetCurve(key.Curve)
   945  		gjKey := jose.Recipient{
   946  			KeyID:     kids[i],
   947  			Algorithm: jose.ECDH_ES_A256KW,
   948  			Key: &ecdsa.PublicKey{
   949  				Curve: c,
   950  				X:     new(big.Int).SetBytes(key.X),
   951  				Y:     new(big.Int).SetBytes(key.Y),
   952  			},
   953  		}
   954  
   955  		joseRecipients = append(joseRecipients, gjKey)
   956  	}
   957  
   958  	return joseRecipients
   959  }
   960  
   961  func createRecipients(t *testing.T,
   962  	nbOfEntities int) ([]*cryptoapi.PublicKey, map[string]*keyset.Handle, []string, []string) {
   963  	return createRecipientsByKeyTemplate(t, nbOfEntities, ecdh.NISTP256ECDHKWKeyTemplate(), kms.NISTP256ECDHKWType)
   964  }
   965  
   966  // createRecipients and return their public key and keyset.Handle.
   967  func createRecipientsByKeyTemplate(t *testing.T, nbOfEntities int, kt *tinkpb.KeyTemplate,
   968  	keyType kms.KeyType) ([]*cryptoapi.PublicKey, map[string]*keyset.Handle, []string, []string) {
   969  	t.Helper()
   970  
   971  	r := make([]*cryptoapi.PublicKey, 0)
   972  	rKH := make(map[string]*keyset.Handle)
   973  	rKID := make([]string, 0)
   974  	rDIDKey := make([]string, 0)
   975  
   976  	for i := 0; i < nbOfEntities; i++ {
   977  		mrKey, kh, kid, didKey := createAndMarshalEntityKey(t, kt, keyType)
   978  
   979  		ecPubKey := new(cryptoapi.PublicKey)
   980  		err := json.Unmarshal(mrKey, ecPubKey)
   981  		require.NoError(t, err)
   982  
   983  		ecPubKey.KID = kid
   984  		rKH[kid] = kh
   985  
   986  		r = append(r, ecPubKey)
   987  		rKID = append(rKID, kid)
   988  		rDIDKey = append(rDIDKey, didKey)
   989  	}
   990  
   991  	return r, rKH, rKID, rDIDKey
   992  }
   993  
   994  // createAndMarshalEntityKey creates a new recipient keyset.Handle, extracts public key, marshals it and returns
   995  // both marshalled public key and original recipient keyset.Handle.
   996  func createAndMarshalEntityKey(t *testing.T, kt *tinkpb.KeyTemplate,
   997  	keyType kms.KeyType) ([]byte, *keyset.Handle, string, string) {
   998  	t.Helper()
   999  
  1000  	kh, err := keyset.NewHandle(kt)
  1001  	require.NoError(t, err)
  1002  
  1003  	pubKH, err := kh.Public()
  1004  	require.NoError(t, err)
  1005  
  1006  	buf := new(bytes.Buffer)
  1007  	pubKeyWriter := keyio.NewWriter(buf)
  1008  	require.NotEmpty(t, pubKeyWriter)
  1009  
  1010  	err = pubKH.WriteWithNoSecrets(pubKeyWriter)
  1011  	require.NoError(t, err)
  1012  
  1013  	mKeyBytes := buf.Bytes()
  1014  
  1015  	kid, err := jwkkid.CreateKID(mKeyBytes, keyType)
  1016  	require.NoError(t, err)
  1017  
  1018  	didKey, err := kmsdidkey.BuildDIDKeyByKeyType(mKeyBytes, keyType)
  1019  	require.NoError(t, err)
  1020  
  1021  	printKey(t, mKeyBytes, kid)
  1022  
  1023  	return mKeyBytes, kh, kid, didKey
  1024  }
  1025  
  1026  func printKey(t *testing.T, mPubKey []byte, kid string) {
  1027  	t.Helper()
  1028  
  1029  	pubKey := new(cryptoapi.PublicKey)
  1030  	err := json.Unmarshal(mPubKey, pubKey)
  1031  	require.NoError(t, err)
  1032  
  1033  	switch pubKey.Type {
  1034  	case ecdhpb.KeyType_EC.String():
  1035  		t.Logf("** EC key: %s, kid: %s", getPrintedECPubKey(t, pubKey), kid)
  1036  	case ecdhpb.KeyType_OKP.String():
  1037  		t.Logf("** X25519 key: %s, kid: %s", getPrintedX25519PubKey(t, pubKey), kid)
  1038  	default:
  1039  		t.Errorf("not supported key type: %s", pubKey.Type)
  1040  	}
  1041  }
  1042  
  1043  func prettyPrint(msg []byte) (string, error) {
  1044  	var prettyJSON bytes.Buffer
  1045  
  1046  	err := json.Indent(&prettyJSON, msg, "", "\t")
  1047  	if err != nil {
  1048  		return "", err
  1049  	}
  1050  
  1051  	return prettyJSON.String(), nil
  1052  }
  1053  
  1054  func getPrintedECPubKey(t *testing.T, pubKey *cryptoapi.PublicKey) string {
  1055  	crv, err := hybrid.GetCurve(pubKey.Curve)
  1056  	require.NoError(t, err)
  1057  
  1058  	j := jose.JSONWebKey{
  1059  		Key: &ecdsa.PublicKey{
  1060  			Curve: crv,
  1061  			X:     new(big.Int).SetBytes(pubKey.X),
  1062  			Y:     new(big.Int).SetBytes(pubKey.Y),
  1063  		},
  1064  	}
  1065  
  1066  	jwkByte, err := j.MarshalJSON()
  1067  	require.NoError(t, err)
  1068  	jwkStr, err := prettyPrint(jwkByte)
  1069  	require.NoError(t, err)
  1070  
  1071  	return jwkStr
  1072  }
  1073  
  1074  func getPrintedX25519PubKey(t *testing.T, pubKeyType *cryptoapi.PublicKey) string {
  1075  	j := jose.JSONWebKey{
  1076  		Key: ed25519.PublicKey(pubKeyType.X),
  1077  	}
  1078  
  1079  	jwkByte, err := j.MarshalJSON()
  1080  	require.NoError(t, err)
  1081  
  1082  	jwkStr, err := prettyPrint(jwkByte)
  1083  	require.NoError(t, err)
  1084  
  1085  	return strings.Replace(jwkStr, "Ed25519", "X25519", 1)
  1086  }
  1087  
  1088  func TestFailNewJWEEncrypt(t *testing.T) {
  1089  	c, err := tinkcrypto.New()
  1090  	require.NoError(t, err)
  1091  
  1092  	recipients, recsKH, kids, _ := createRecipients(t, 2)
  1093  
  1094  	t.Run("test with missing skid", func(t *testing.T) {
  1095  		_, err = ariesjose.NewJWEEncrypt(ariesjose.A256GCM, EnvelopeEncodingType, DIDCommContentEncodingType,
  1096  			"", recsKH[kids[0]], recipients, c)
  1097  		require.EqualError(t, err, "senderKID is required with senderKH")
  1098  	})
  1099  
  1100  	t.Run("test with missing crypto", func(t *testing.T) {
  1101  		_, err = ariesjose.NewJWEEncrypt(ariesjose.A256GCM, EnvelopeEncodingType, DIDCommContentEncodingType,
  1102  			kids[0], recsKH[kids[0]], recipients, nil)
  1103  		require.EqualError(t, err, "crypto service is required to create a JWEEncrypt instance")
  1104  	})
  1105  }
  1106  
  1107  //nolint:gocognit
  1108  func TestECDH1PU(t *testing.T) {
  1109  	tests := []struct {
  1110  		name       string
  1111  		kt         *tinkpb.KeyTemplate
  1112  		enc        ariesjose.EncAlg
  1113  		keyType    kms.KeyType
  1114  		nbRec      int
  1115  		useCompact bool
  1116  	}{
  1117  		{
  1118  			name:    "P-256 ECDH KW and XChacha20Poly1305 encryption with 2 recipients (Full serialization)",
  1119  			kt:      ecdh.NISTP256ECDHKWKeyTemplate(),
  1120  			enc:     ariesjose.XC20P,
  1121  			keyType: kms.NISTP256ECDHKWType,
  1122  			nbRec:   2,
  1123  		},
  1124  		{
  1125  			name:    "P-256 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Flattened serialization)",
  1126  			kt:      ecdh.NISTP256ECDHKWKeyTemplate(),
  1127  			enc:     ariesjose.XC20P,
  1128  			keyType: kms.NISTP256ECDHKWType,
  1129  			nbRec:   1,
  1130  		},
  1131  		{
  1132  			name:       "P-256 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Compact serialization)",
  1133  			kt:         ecdh.NISTP256ECDHKWKeyTemplate(),
  1134  			enc:        ariesjose.XC20P,
  1135  			keyType:    kms.NISTP256ECDHKWType,
  1136  			nbRec:      1,
  1137  			useCompact: true,
  1138  		},
  1139  		{
  1140  			name:    "P-384 ECDH KW and XChacha20Poly1305 encryption with 2 recipients (Full serialization)",
  1141  			kt:      ecdh.NISTP384ECDHKWKeyTemplate(),
  1142  			enc:     ariesjose.XC20P,
  1143  			keyType: kms.NISTP384ECDHKWType,
  1144  			nbRec:   2,
  1145  		},
  1146  		{
  1147  			name:    "P-384 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Flattened serialization)",
  1148  			kt:      ecdh.NISTP384ECDHKWKeyTemplate(),
  1149  			enc:     ariesjose.XC20P,
  1150  			keyType: kms.NISTP384ECDHKWType,
  1151  			nbRec:   1,
  1152  		},
  1153  		{
  1154  			name:       "P-384 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Compact serialization)",
  1155  			kt:         ecdh.NISTP384ECDHKWKeyTemplate(),
  1156  			enc:        ariesjose.XC20P,
  1157  			keyType:    kms.NISTP384ECDHKWType,
  1158  			nbRec:      1,
  1159  			useCompact: true,
  1160  		},
  1161  		{
  1162  			name:    "P-521 ECDH KW and XChacha20Poly1305 encryption with 2 recipients (Full serialization)",
  1163  			kt:      ecdh.NISTP521ECDHKWKeyTemplate(),
  1164  			enc:     ariesjose.XC20P,
  1165  			keyType: kms.NISTP521ECDHKWType,
  1166  			nbRec:   2,
  1167  		},
  1168  		{
  1169  			name:    "P-521 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Flattened serialization)",
  1170  			kt:      ecdh.NISTP521ECDHKWKeyTemplate(),
  1171  			enc:     ariesjose.XC20P,
  1172  			keyType: kms.NISTP521ECDHKWType,
  1173  			nbRec:   1,
  1174  		},
  1175  		{
  1176  			name:       "P-521 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Compact serialization)",
  1177  			kt:         ecdh.NISTP521ECDHKWKeyTemplate(),
  1178  			enc:        ariesjose.XC20P,
  1179  			keyType:    kms.NISTP521ECDHKWType,
  1180  			nbRec:      1,
  1181  			useCompact: true,
  1182  		},
  1183  		{
  1184  			name:    "X25519 ECDH KW and XChacha20Poly1305 encryption with 2 recipients (Full serialization)",
  1185  			kt:      ecdh.X25519ECDHKWKeyTemplate(),
  1186  			enc:     ariesjose.XC20P,
  1187  			keyType: kms.X25519ECDHKWType,
  1188  			nbRec:   2,
  1189  		},
  1190  		{
  1191  			name:    "X25519 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Flattened serialization)",
  1192  			kt:      ecdh.X25519ECDHKWKeyTemplate(),
  1193  			enc:     ariesjose.XC20P,
  1194  			keyType: kms.X25519ECDHKWType,
  1195  			nbRec:   1,
  1196  		},
  1197  		{
  1198  			name:       "X25519 ECDH KW and XChacha20Poly1305 encryption with 1 recipient (Compact serialization)",
  1199  			kt:         ecdh.X25519ECDHKWKeyTemplate(),
  1200  			enc:        ariesjose.XC20P,
  1201  			keyType:    kms.X25519ECDHKWType,
  1202  			nbRec:      1,
  1203  			useCompact: true,
  1204  		},
  1205  		{
  1206  			name:    "P-256 ECDH KW and A128CBCHS256 encryption with 2 recipients (Full serialization)",
  1207  			kt:      ecdh.NISTP256ECDHKWKeyTemplate(),
  1208  			enc:     ariesjose.A128CBCHS256,
  1209  			keyType: kms.NISTP256ECDHKWType,
  1210  			nbRec:   2,
  1211  		},
  1212  		{
  1213  			name:    "P-256 ECDH KW and A128CBCHS256 encryption with 1 recipient (Flattened serialization)",
  1214  			kt:      ecdh.NISTP256ECDHKWKeyTemplate(),
  1215  			enc:     ariesjose.A128CBCHS256,
  1216  			keyType: kms.NISTP256ECDHKWType,
  1217  			nbRec:   1,
  1218  		},
  1219  		{
  1220  			name:       "P-256 ECDH KW and A128CBCHS256 encryption with 1 recipient (Compact serialization)",
  1221  			kt:         ecdh.NISTP256ECDHKWKeyTemplate(),
  1222  			enc:        ariesjose.A128CBCHS256,
  1223  			keyType:    kms.NISTP256ECDHKWType,
  1224  			nbRec:      1,
  1225  			useCompact: true,
  1226  		},
  1227  		{
  1228  			name:    "X25519 ECDH KW and A128CBCHS256 encryption with 2 recipients (Full serialization)",
  1229  			kt:      ecdh.X25519ECDHKWKeyTemplate(),
  1230  			enc:     ariesjose.A128CBCHS256,
  1231  			keyType: kms.X25519ECDHKWType,
  1232  			nbRec:   2,
  1233  		},
  1234  		{
  1235  			name:    "X25519 ECDH KW and A128CBCHS256 encryption with 1 recipient (Flattened serialization)",
  1236  			kt:      ecdh.X25519ECDHKWKeyTemplate(),
  1237  			enc:     ariesjose.A128CBCHS256,
  1238  			keyType: kms.X25519ECDHKWType,
  1239  			nbRec:   1,
  1240  		},
  1241  		{
  1242  			name:       "X25519 ECDH KW and A128CBCHS256 encryption with 1 recipient (Compact serialization)",
  1243  			kt:         ecdh.X25519ECDHKWKeyTemplate(),
  1244  			enc:        ariesjose.A128CBCHS256,
  1245  			keyType:    kms.X25519ECDHKWType,
  1246  			nbRec:      1,
  1247  			useCompact: true,
  1248  		},
  1249  		{
  1250  			name:    "P-256 ECDH KW and A192CBCHS384 encryption with 2 recipients (Full serialization)",
  1251  			kt:      ecdh.NISTP256ECDHKWKeyTemplate(),
  1252  			enc:     ariesjose.A192CBCHS384,
  1253  			keyType: kms.NISTP256ECDHKWType,
  1254  			nbRec:   2,
  1255  		},
  1256  		{
  1257  			name:    "P-256 ECDH KW and A192CBCHS384 encryption with 1 recipient (Flattened serialization)",
  1258  			kt:      ecdh.NISTP256ECDHKWKeyTemplate(),
  1259  			enc:     ariesjose.A192CBCHS384,
  1260  			keyType: kms.NISTP256ECDHKWType,
  1261  			nbRec:   1,
  1262  		},
  1263  		{
  1264  			name:       "P-256 ECDH KW and A192CBCHS384 encryption with 1 recipient (Compact serialization)",
  1265  			kt:         ecdh.NISTP256ECDHKWKeyTemplate(),
  1266  			enc:        ariesjose.A192CBCHS384,
  1267  			keyType:    kms.NISTP256ECDHKWType,
  1268  			nbRec:      1,
  1269  			useCompact: true,
  1270  		},
  1271  		{
  1272  			name:    "P-384 ECDH KW and A192CBCHS384 encryption with 2 recipients (Full serialization)",
  1273  			kt:      ecdh.NISTP384ECDHKWKeyTemplate(),
  1274  			enc:     ariesjose.A192CBCHS384,
  1275  			keyType: kms.NISTP384ECDHKWType,
  1276  			nbRec:   2,
  1277  		},
  1278  		{
  1279  			name:    "P-384 ECDH KW and A192CBCHS384 encryption with 1 recipient (Flattened serialization)",
  1280  			kt:      ecdh.NISTP384ECDHKWKeyTemplate(),
  1281  			enc:     ariesjose.A192CBCHS384,
  1282  			keyType: kms.NISTP384ECDHKWType,
  1283  			nbRec:   1,
  1284  		},
  1285  		{
  1286  			name:       "P-384 ECDH KW and A192CBCHS384 encryption with 1 recipient (Compact serialization)",
  1287  			kt:         ecdh.NISTP384ECDHKWKeyTemplate(),
  1288  			enc:        ariesjose.A192CBCHS384,
  1289  			keyType:    kms.NISTP384ECDHKWType,
  1290  			nbRec:      1,
  1291  			useCompact: true,
  1292  		},
  1293  		{
  1294  			name:    "X25519 ECDH KW and A192CBCHS384 encryption with 2 recipients (Full serialization)",
  1295  			kt:      ecdh.X25519ECDHKWKeyTemplate(),
  1296  			enc:     ariesjose.A192CBCHS384,
  1297  			keyType: kms.X25519ECDHKWType,
  1298  			nbRec:   2,
  1299  		},
  1300  		{
  1301  			name:    "X25519 ECDH KW and A192CBCHS384 encryption with 1 recipient (Flattened serialization)",
  1302  			kt:      ecdh.X25519ECDHKWKeyTemplate(),
  1303  			enc:     ariesjose.A192CBCHS384,
  1304  			keyType: kms.X25519ECDHKWType,
  1305  			nbRec:   1,
  1306  		},
  1307  		{
  1308  			name:       "X25519 ECDH KW and A192CBCHS384 encryption with 1 recipient (Compact serialization)",
  1309  			kt:         ecdh.X25519ECDHKWKeyTemplate(),
  1310  			enc:        ariesjose.A192CBCHS384,
  1311  			keyType:    kms.X25519ECDHKWType,
  1312  			nbRec:      1,
  1313  			useCompact: true,
  1314  		},
  1315  		{
  1316  			name:    "X25519 ECDH KW and A256CBCHS384 encryption with 2 recipients (Full serialization)",
  1317  			kt:      ecdh.X25519ECDHKWKeyTemplate(),
  1318  			enc:     ariesjose.A256CBCHS384,
  1319  			keyType: kms.X25519ECDHKWType,
  1320  			nbRec:   2,
  1321  		},
  1322  		{
  1323  			name:    "X25519 ECDH KW and A256CBCHS384 encryption with 1 recipient (Flattened serialization)",
  1324  			kt:      ecdh.X25519ECDHKWKeyTemplate(),
  1325  			enc:     ariesjose.A256CBCHS384,
  1326  			keyType: kms.X25519ECDHKWType,
  1327  			nbRec:   1,
  1328  		},
  1329  		{
  1330  			name:       "X25519 ECDH KW and A256CBCHS384 encryption with 1 recipient (Compact serialization)",
  1331  			kt:         ecdh.X25519ECDHKWKeyTemplate(),
  1332  			enc:        ariesjose.A256CBCHS384,
  1333  			keyType:    kms.X25519ECDHKWType,
  1334  			nbRec:      1,
  1335  			useCompact: true,
  1336  		},
  1337  		{
  1338  			name:    "P-521 ECDH KW and A256CBCHS512 encryption with 2 recipients (Full serialization)",
  1339  			kt:      ecdh.NISTP521ECDHKWKeyTemplate(),
  1340  			enc:     ariesjose.A256CBCHS512,
  1341  			keyType: kms.NISTP521ECDHKWType,
  1342  			nbRec:   2,
  1343  		},
  1344  		{
  1345  			name:    "P-521 ECDH KW and A256CBCHS512 encryption with 1 recipient (Flattened serialization)",
  1346  			kt:      ecdh.NISTP521ECDHKWKeyTemplate(),
  1347  			enc:     ariesjose.A256CBCHS512,
  1348  			keyType: kms.NISTP521ECDHKWType,
  1349  			nbRec:   1,
  1350  		},
  1351  		{
  1352  			name:       "P-521 ECDH KW and A256CBCHS512 encryption with 1 recipient (Compact serialization)",
  1353  			kt:         ecdh.NISTP521ECDHKWKeyTemplate(),
  1354  			enc:        ariesjose.A256CBCHS512,
  1355  			keyType:    kms.NISTP521ECDHKWType,
  1356  			nbRec:      1,
  1357  			useCompact: true,
  1358  		},
  1359  		{
  1360  			name:    "X25519 ECDH KW and A256CBCHS512 encryption with 2 recipients (Full serialization)",
  1361  			kt:      ecdh.X25519ECDHKWKeyTemplate(),
  1362  			enc:     ariesjose.A256CBCHS512,
  1363  			keyType: kms.X25519ECDHKWType,
  1364  			nbRec:   2,
  1365  		},
  1366  		{
  1367  			name:    "X25519 ECDH KW and A256CBCHS512 encryption with 1 recipient (Flattened serialization)",
  1368  			kt:      ecdh.X25519ECDHKWKeyTemplate(),
  1369  			enc:     ariesjose.A256CBCHS512,
  1370  			keyType: kms.X25519ECDHKWType,
  1371  			nbRec:   1,
  1372  		},
  1373  		{
  1374  			name:       "X25519 ECDH KW and A256CBCHS512 encryption with 1 recipient (Compact serialization)",
  1375  			kt:         ecdh.X25519ECDHKWKeyTemplate(),
  1376  			enc:        ariesjose.A256CBCHS512,
  1377  			keyType:    kms.X25519ECDHKWType,
  1378  			nbRec:      1,
  1379  			useCompact: true,
  1380  		},
  1381  	}
  1382  
  1383  	for _, tt := range tests {
  1384  		tc := tt
  1385  		t.Run(tc.name, func(t *testing.T) {
  1386  			t.Log("creating Sender key..")
  1387  			senders, senderKHs, senderKIDs, senderDIDKeys := createRecipientsByKeyTemplate(t, 1, tc.kt, tc.keyType)
  1388  			t.Log("creating recipients keys..")
  1389  			recipientsKeys, recKHs, _, recDIDKeys := createRecipientsByKeyTemplate(t, tc.nbRec, tc.kt, tc.keyType)
  1390  
  1391  			cryptoSvc, kmsSvc := createCryptoAndKMSServices(t, recKHs)
  1392  
  1393  			senderPubKey, err := json.Marshal(senders[0])
  1394  			require.NoError(t, err)
  1395  
  1396  			jweEncrypter, err := ariesjose.NewJWEEncrypt(tc.enc, EnvelopeEncodingType, DIDCommContentEncodingType,
  1397  				senderKIDs[0], senderKHs[senderKIDs[0]], recipientsKeys, cryptoSvc)
  1398  			require.NoError(t, err)
  1399  			require.NotEmpty(t, jweEncrypter)
  1400  
  1401  			mockStoreMap := make(map[string]mockstorage.DBEntry)
  1402  			mockStore := &mockstorage.MockStore{
  1403  				Store: mockStoreMap,
  1404  			}
  1405  
  1406  			storeResolver := []resolver.KIDResolver{&resolver.StoreResolver{Store: mockStore}}
  1407  
  1408  			pt := []byte("secret message")
  1409  			aad := []byte("aad value")
  1410  
  1411  			if tc.useCompact { // Compact serialization does not use aad
  1412  				aad = nil
  1413  			}
  1414  
  1415  			// test JWEEncrypt for ECDH1PU
  1416  			testEncTime := time.Now()
  1417  			jwe, err := jweEncrypter.EncryptWithAuthData(pt, aad)
  1418  			t.Logf("ECDH-1PU KW in EncryptWithAuthData took %v", time.Since(testEncTime))
  1419  			require.NoError(t, err)
  1420  
  1421  			cty, ok := jwe.ProtectedHeaders.ContentType()
  1422  			require.True(t, ok)
  1423  			require.Equal(t, DIDCommContentEncodingType, cty)
  1424  
  1425  			typ, ok := jwe.ProtectedHeaders.Type()
  1426  			require.True(t, ok)
  1427  			require.Equal(t, EnvelopeEncodingType, typ)
  1428  
  1429  			alg, ok := jwe.ProtectedHeaders.Algorithm()
  1430  			if alg != "" {
  1431  				cbcHMACAlgs := []string{
  1432  					tinkcrypto.ECDH1PUA128KWAlg, tinkcrypto.ECDH1PUA192KWAlg,
  1433  					tinkcrypto.ECDH1PUA256KWAlg, tinkcrypto.ECDH1PUXC20PKWAlg,
  1434  				}
  1435  
  1436  				require.True(t, ok)
  1437  				require.Contains(t, cbcHMACAlgs, alg)
  1438  			} else {
  1439  				require.False(t, ok)
  1440  			}
  1441  
  1442  			kid, ok := jwe.ProtectedHeaders.KeyID()
  1443  			if kid != "" {
  1444  				require.True(t, ok)
  1445  				require.NotEmpty(t, kid)
  1446  			} else {
  1447  				require.False(t, ok)
  1448  			}
  1449  
  1450  			var serializedJWE, jweStr string
  1451  			serialization := fullSerialization
  1452  
  1453  			if tc.useCompact {
  1454  				testSerTime := time.Now()
  1455  				serializedJWE, err = jwe.CompactSerialize(json.Marshal)
  1456  				t.Logf("Compact serialize took %v", time.Since(testSerTime))
  1457  				require.NoError(t, err)
  1458  				require.NotEmpty(t, serializedJWE)
  1459  
  1460  				jweStr = serializedJWE
  1461  				serialization = compactSerialization
  1462  			} else {
  1463  				testSerTime := time.Now()
  1464  				serializedJWE, err = jwe.FullSerialize(json.Marshal)
  1465  				t.Logf("JSON serialize took %v", time.Since(testSerTime))
  1466  				require.NoError(t, err)
  1467  				require.NotEmpty(t, serializedJWE)
  1468  
  1469  				jweStr, err = prettyPrint([]byte(serializedJWE))
  1470  				require.NoError(t, err)
  1471  				if tc.nbRec == 1 {
  1472  					serialization = flattenedSerialization
  1473  				}
  1474  			}
  1475  
  1476  			t.Logf("* authcrypt JWE (%s serialization): %s", serialization, jweStr)
  1477  
  1478  			mPh, err := json.Marshal(jwe.ProtectedHeaders)
  1479  			require.NoError(t, err)
  1480  
  1481  			protectedHeadersStr, err := prettyPrint(mPh)
  1482  			require.NoError(t, err)
  1483  
  1484  			t.Logf("* protected headers: %s", protectedHeadersStr)
  1485  
  1486  			testDeserTime := time.Now()
  1487  			localJWE, err := ariesjose.Deserialize(serializedJWE)
  1488  			t.Logf("JWE deserialize took %v", time.Since(testDeserTime))
  1489  			require.NoError(t, err)
  1490  
  1491  			t.Run("ECDH-1PU JWE message without kid key in the KID storeResolver's store should fail", func(t *testing.T) {
  1492  				jd := ariesjose.NewJWEDecrypt(storeResolver, cryptoSvc, kmsSvc)
  1493  				require.NotEmpty(t, jd)
  1494  
  1495  				_, err = jd.Decrypt(localJWE)
  1496  				require.EqualError(t, err, "jwedecrypt: failed to add sender public key for skid: fetchSenderPubKey: "+
  1497  					"resolveKID: [storeResolver: failed to resolve kid from store: data not found]")
  1498  			})
  1499  
  1500  			// add sender pubkey into the recipient's mock store to prepare for a successful JWEDecrypt() for each recipient
  1501  			mockStoreMap[senderKIDs[0]] = mockstorage.DBEntry{Value: senderPubKey}
  1502  
  1503  			t.Run("Decrypting JWE message test success", func(t *testing.T) {
  1504  				jd := ariesjose.NewJWEDecrypt(storeResolver, cryptoSvc, kmsSvc)
  1505  				require.NotEmpty(t, jd)
  1506  
  1507  				var msg []byte
  1508  
  1509  				testDecTime := time.Now()
  1510  				msg, err = jd.Decrypt(localJWE)
  1511  				t.Logf("JWE deserialize took %v", time.Since(testDecTime))
  1512  				require.NoError(t, err)
  1513  				require.EqualValues(t, pt, msg)
  1514  			})
  1515  
  1516  			t.Run("ECDH-1PU Encrypt and Decrypt JWE test success with skid/kid as did:key", func(t *testing.T) {
  1517  				recKeys := make([]*cryptoapi.PublicKey, 0)
  1518  				for i, k := range recipientsKeys {
  1519  					k.KID = recDIDKeys[i]
  1520  					recKeys = append(recKeys, k)
  1521  				}
  1522  
  1523  				jweEncrypter, err = ariesjose.NewJWEEncrypt(tc.enc, EnvelopeEncodingType,
  1524  					DIDCommContentEncodingType, senderDIDKeys[0], senderKHs[senderKIDs[0]], recKeys, cryptoSvc)
  1525  				require.NoError(t, err)
  1526  
  1527  				testEncTime = time.Now()
  1528  				jwe, err = jweEncrypter.EncryptWithAuthData(pt, aad)
  1529  				t.Logf("ECDH-1PU KW in EncryptWithAuthData with kid as did:key took %v", time.Since(testEncTime))
  1530  				require.NoError(t, err)
  1531  				require.Equal(t, len(recipientsKeys), len(jwe.Recipients))
  1532  
  1533  				if tc.useCompact {
  1534  					testSerTime := time.Now()
  1535  					serializedJWE, err = jwe.CompactSerialize(json.Marshal)
  1536  					t.Logf("CompactSerilize JWE with as did:key took %v", time.Since(testSerTime))
  1537  					require.NoError(t, err)
  1538  					require.NotEmpty(t, serializedJWE)
  1539  
  1540  					jweStr = serializedJWE
  1541  					serialization = compactSerialization
  1542  				} else {
  1543  					testSerTime := time.Now()
  1544  					serializedJWE, err = jwe.FullSerialize(json.Marshal)
  1545  					t.Logf("JSON Serialize with kid as did:key took %v", time.Since(testSerTime))
  1546  					require.NoError(t, err)
  1547  					require.NotEmpty(t, serializedJWE)
  1548  
  1549  					jweStr, err = prettyPrint([]byte(serializedJWE))
  1550  					require.NoError(t, err)
  1551  					if tc.nbRec == 1 {
  1552  						serialization = flattenedSerialization
  1553  					}
  1554  				}
  1555  
  1556  				t.Logf("* authcrypt JWE (%s serialization) with kid as did:key: %s", serialization, jweStr)
  1557  
  1558  				// try to deserialize with go-jose (can't decrypt in go-jose since private key is protected by Tink)
  1559  				joseJWE, err := jose.ParseEncrypted(serializedJWE)
  1560  				require.NoError(t, err)
  1561  				require.NotEmpty(t, joseJWE)
  1562  
  1563  				// try to deserialize with local package
  1564  				testDeserTime := time.Now()
  1565  				localJWE, err = ariesjose.Deserialize(serializedJWE)
  1566  				t.Logf("JWE with kid as did:key Deserialize took %v", time.Since(testDeserTime))
  1567  				require.NoError(t, err)
  1568  
  1569  				jweDecrypter := ariesjose.NewJWEDecrypt([]resolver.KIDResolver{&resolver.DIDKeyResolver{}}, cryptoSvc, kmsSvc)
  1570  
  1571  				var msg []byte
  1572  
  1573  				testDecTime := time.Now()
  1574  				msg, err = jweDecrypter.Decrypt(localJWE)
  1575  				t.Logf("JWE with kid as did:key Decrypt took %v", time.Since(testDecTime))
  1576  				require.NoError(t, err)
  1577  				require.EqualValues(t, pt, msg)
  1578  			})
  1579  		})
  1580  	}
  1581  }
  1582  
  1583  func createCryptoAndKMSServices(t *testing.T, keys map[string]*keyset.Handle) (cryptoapi.Crypto, kms.KeyManager) {
  1584  	c, err := tinkcrypto.New()
  1585  	require.NoError(t, err)
  1586  
  1587  	k := &mockKMSGetter{
  1588  		keys: keys,
  1589  	}
  1590  
  1591  	require.NoError(t, err)
  1592  
  1593  	return c, k
  1594  }
  1595  
  1596  type mockKMSGetter struct {
  1597  	mockkms.KeyManager
  1598  	keys map[string]*keyset.Handle
  1599  }
  1600  
  1601  func (k *mockKMSGetter) Get(kid string) (interface{}, error) {
  1602  	return k.keys[kid], nil
  1603  }
  1604  
  1605  // nolint:gochecknoglobals // embedded test data
  1606  var (
  1607  	// test vector retrieved from:
  1608  	//nolint:lll
  1609  	// (github: https://github.com/NeilMadden/jose-ecdh-1pu/blob/master/draft-madden-jose-ecdh-1pu-04/draft-madden-jose-ecdh-1pu-04.txt#L740)
  1610  	// (ietf draft: https://datatracker.ietf.org/doc/html/draft-madden-jose-ecdh-1pu-04#appendix-B)
  1611  	//go:embed testdata/alice_key_ref.json
  1612  	aliceKeyRef string
  1613  	//go:embed testdata/bob_key_ref.json
  1614  	bobKeyRef string
  1615  	//go:embed testdata/charlie_key_ref.json
  1616  	charlieKeyRef string
  1617  	//go:embed testdata/jwe_ref.json
  1618  	jweRef string
  1619  )
  1620  
  1621  func Test1PUDraft4ExampleBDecrypt(t *testing.T) {
  1622  	testJWE := trimSpace(jweRef)
  1623  	aliceKey := trimSpace(aliceKeyRef)
  1624  	bobKey := trimSpace(bobKeyRef)
  1625  	charlieKey := trimSpace(charlieKeyRef)
  1626  
  1627  	skid := "Alice"
  1628  	keys := convertX25519ToKH(t, []string{aliceKey, bobKey, charlieKey}, []string{skid, "bob-key-2", "2021-05-06"})
  1629  
  1630  	c, k := createCryptoAndKMSServices(t, keys)
  1631  
  1632  	mockStoreMap := make(map[string]mockstorage.DBEntry)
  1633  
  1634  	pubKH, err := keys[skid].Public()
  1635  	require.NoError(t, err)
  1636  
  1637  	senderPubKey, err := keyio.ExtractPrimaryPublicKey(pubKH)
  1638  	require.NoError(t, err)
  1639  
  1640  	mSenderPubKey, err := json.Marshal(senderPubKey)
  1641  	require.NoError(t, err)
  1642  
  1643  	mockStoreMap[skid] = mockstorage.DBEntry{Value: mSenderPubKey}
  1644  
  1645  	mockStore := &mockstorage.MockStore{
  1646  		Store: mockStoreMap,
  1647  	}
  1648  
  1649  	localJWE, err := ariesjose.Deserialize(testJWE)
  1650  	require.NoError(t, err)
  1651  	require.NotEmpty(t, localJWE)
  1652  
  1653  	dec := ariesjose.NewJWEDecrypt([]resolver.KIDResolver{&resolver.StoreResolver{Store: mockStore}}, c, k)
  1654  	require.NotEmpty(t, dec)
  1655  
  1656  	pt, err := dec.Decrypt(localJWE)
  1657  	require.NoError(t, err)
  1658  	require.EqualValues(t, []byte("Three is a magic number."), pt)
  1659  }
  1660  
  1661  func trimSpace(s string) string {
  1662  	s = strings.ReplaceAll(s, " ", "")
  1663  	s = strings.ReplaceAll(s, "\n", "")
  1664  
  1665  	return s
  1666  }
  1667  
  1668  func convertX25519ToKH(t *testing.T, keys, kids []string) map[string]*keyset.Handle {
  1669  	t.Helper()
  1670  
  1671  	var err error
  1672  
  1673  	khs := make(map[string]*keyset.Handle)
  1674  
  1675  	for i, k := range keys {
  1676  		delim := ",\"d\""
  1677  		idx := strings.Index(k, delim)
  1678  		mPubKey := k[:idx] + "}"
  1679  		pubKey := &jwk.JWK{}
  1680  		err = json.Unmarshal([]byte(mPubKey), pubKey)
  1681  		require.NoError(t, err)
  1682  
  1683  		var d []byte
  1684  
  1685  		dVal := k[idx+len(delim)+2 : len(k)-2]
  1686  		d, err = base64.RawURLEncoding.DecodeString(dVal)
  1687  		require.NoError(t, err)
  1688  
  1689  		privKey := &cryptoapi.PrivateKey{
  1690  			PublicKey: cryptoapi.PublicKey{
  1691  				X:     pubKey.Key.([]byte),
  1692  				Curve: pubKey.Crv,
  1693  				Type:  pubKey.Kty,
  1694  			},
  1695  			D: d,
  1696  		}
  1697  
  1698  		var kh *keyset.Handle
  1699  
  1700  		kh, err = keyio.PrivateKeyToKeysetHandle(privKey, ecdh.XC20P)
  1701  		require.NoError(t, err)
  1702  
  1703  		khs[kids[i]] = kh
  1704  	}
  1705  
  1706  	return khs
  1707  }