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 }