github.com/hyperledger/aries-framework-go@v0.3.2/pkg/didcomm/packer/anoncrypt/pack_test.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package anoncrypt 8 9 import ( 10 "bytes" 11 "crypto/ecdsa" 12 "crypto/ed25519" 13 "crypto/elliptic" 14 "encoding/json" 15 "errors" 16 "fmt" 17 "io" 18 "strings" 19 "testing" 20 21 "github.com/go-jose/go-jose/v3" 22 "github.com/golang/protobuf/proto" 23 hybrid "github.com/google/tink/go/hybrid/subtle" 24 "github.com/google/tink/go/keyset" 25 commonpb "github.com/google/tink/go/proto/common_go_proto" 26 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 27 "github.com/stretchr/testify/require" 28 29 ecdhpb "github.com/hyperledger/aries-framework-go/component/kmscrypto/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" 30 31 "github.com/hyperledger/aries-framework-go/pkg/common/log" 32 cryptoapi "github.com/hyperledger/aries-framework-go/pkg/crypto" 33 "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto" 34 "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/keyio" 35 "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" 36 afgjose "github.com/hyperledger/aries-framework-go/pkg/doc/jose" 37 "github.com/hyperledger/aries-framework-go/pkg/doc/util/kmsdidkey" 38 "github.com/hyperledger/aries-framework-go/pkg/kms" 39 "github.com/hyperledger/aries-framework-go/pkg/kms/localkms" 40 mockkms "github.com/hyperledger/aries-framework-go/pkg/mock/kms" 41 mockprovider "github.com/hyperledger/aries-framework-go/pkg/mock/provider" 42 mockstorage "github.com/hyperledger/aries-framework-go/pkg/mock/storage" 43 mockvdr "github.com/hyperledger/aries-framework-go/pkg/mock/vdr" 44 "github.com/hyperledger/aries-framework-go/pkg/secretlock/noop" 45 spilog "github.com/hyperledger/aries-framework-go/spi/log" 46 ) 47 48 func TestAnoncryptPackerSuccess(t *testing.T) { 49 k := createKMS(t) 50 51 tests := []struct { 52 name string 53 keyType kms.KeyType 54 encAlg afgjose.EncAlg 55 cty string 56 }{ 57 { 58 name: "anoncrypt using NISTP256ECDHKW and AES256-GCM", 59 keyType: kms.NISTP256ECDHKWType, 60 encAlg: afgjose.A256GCM, 61 cty: transport.MediaTypeV1PlaintextPayload, 62 }, 63 { 64 name: "anoncrypt using NISTP384ECDHKW and AES256-GCM", 65 keyType: kms.NISTP384ECDHKWType, 66 encAlg: afgjose.A256GCM, 67 cty: transport.MediaTypeV1PlaintextPayload, 68 }, 69 { 70 name: "anoncrypt using NISTP521ECDHKW and AES256-GCM", 71 keyType: kms.NISTP521ECDHKWType, 72 encAlg: afgjose.A256GCM, 73 cty: transport.MediaTypeV1PlaintextPayload, 74 }, 75 { 76 name: "anoncrypt using X25519ECDHKWType and AES256-GCM", 77 keyType: kms.X25519ECDHKWType, 78 encAlg: afgjose.A256GCM, 79 cty: transport.MediaTypeV1PlaintextPayload, 80 }, 81 { 82 name: "anoncrypt using NISTP256ECDHKW and XChacha20Poly1305", 83 keyType: kms.NISTP256ECDHKW, 84 encAlg: afgjose.XC20P, 85 cty: transport.MediaTypeV1PlaintextPayload, 86 }, 87 { 88 name: "anoncrypt using NISTP384ECDHKW and XChacha20Poly1305", 89 keyType: kms.NISTP384ECDHKW, 90 encAlg: afgjose.XC20P, 91 cty: transport.MediaTypeV1PlaintextPayload, 92 }, 93 { 94 name: "anoncrypt using NISTP521ECDHKW and XChacha20Poly1305", 95 keyType: kms.NISTP521ECDHKW, 96 encAlg: afgjose.XC20P, 97 cty: transport.MediaTypeV1PlaintextPayload, 98 }, 99 { 100 name: "anoncrypt using X25519ECDHKW and XChacha20Poly1305", 101 keyType: kms.X25519ECDHKWType, 102 encAlg: afgjose.XC20P, 103 cty: transport.MediaTypeV1PlaintextPayload, 104 }, 105 { 106 name: "anoncrypt using NISTP256ECDHKW and AES256-GCM without cty", 107 keyType: kms.NISTP256ECDHKWType, 108 encAlg: afgjose.A256GCM, 109 cty: transport.MediaTypeV1PlaintextPayload, 110 }, 111 { 112 name: "anoncrypt using X25519ECDHKW and XChacha20Poly1305 without cty", 113 keyType: kms.X25519ECDHKWType, 114 encAlg: afgjose.XC20P, 115 cty: transport.MediaTypeV1PlaintextPayload, 116 }, 117 { 118 name: "anoncrypt using NISTP256ECDHKW and XChacha20Poly1305 without cty", 119 keyType: kms.NISTP256ECDHKWType, 120 encAlg: afgjose.XC20P, 121 cty: transport.MediaTypeV1PlaintextPayload, 122 }, 123 { 124 name: "anoncrypt using X25519ECDHKW and AES256-GCM without cty", 125 keyType: kms.X25519ECDHKWType, 126 encAlg: afgjose.A256GCM, 127 cty: transport.MediaTypeV1PlaintextPayload, 128 }, 129 } 130 131 t.Parallel() 132 133 for _, tt := range tests { 134 tc := tt 135 t.Run(fmt.Sprintf("running %s", tc.name), func(t *testing.T) { 136 t.Logf("anoncrypt packing - creating recipient %s keys...", tc.keyType) 137 _, recDIDKeys, recipientsKeys, keyHandles := createRecipientsByKeyType(t, k, 3, tc.keyType) 138 139 log.SetLevel("aries-framework/pkg/didcomm/packer/anoncrypt", spilog.DEBUG) 140 141 cryptoSvc, err := tinkcrypto.New() 142 require.NoError(t, err) 143 144 anonPacker, err := New(newMockProvider(k, cryptoSvc), tc.encAlg) 145 require.NoError(t, err) 146 147 origMsg := []byte("secret message") 148 ct, err := anonPacker.Pack(tc.cty, origMsg, nil, recipientsKeys) 149 require.NoError(t, err) 150 151 jweStr, err := prettyPrint(ct) 152 require.NoError(t, err) 153 t.Logf("* anoncrypt JWE: %s", jweStr) 154 155 msg, err := anonPacker.Unpack(ct) 156 require.NoError(t, err) 157 158 recKey, err := exportPubKeyBytes(keyHandles[0], recDIDKeys[0]) 159 require.NoError(t, err) 160 161 require.EqualValues(t, &transport.Envelope{Message: origMsg, ToKey: recKey}, msg) 162 163 jweJSON, err := afgjose.Deserialize(string(ct)) 164 require.NoError(t, err) 165 166 verifyJWETypes(t, tc.cty, jweJSON.ProtectedHeaders) 167 168 // try with only 1 recipient 169 ct, err = anonPacker.Pack(tc.cty, origMsg, nil, [][]byte{recipientsKeys[0]}) 170 require.NoError(t, err) 171 172 t.Logf("* anoncrypt JWE Compact serialization (using first recipient only): %s", ct) 173 174 jweJSON, err = afgjose.Deserialize(string(ct)) 175 require.NoError(t, err) 176 177 jweStr, err = jweJSON.FullSerialize(json.Marshal) 178 require.NoError(t, err) 179 t.Logf("* anoncrypt Flattened JWE JSON serialization (using first recipient only): %s", jweStr) 180 181 msg, err = anonPacker.Unpack(ct) 182 require.NoError(t, err) 183 184 require.EqualValues(t, &transport.Envelope{Message: origMsg, ToKey: recKey}, msg) 185 186 verifyJWETypes(t, tc.cty, jweJSON.ProtectedHeaders) 187 }) 188 } 189 } 190 191 func verifyJWETypes(t *testing.T, cty string, jweHeader afgjose.Headers) { 192 encodingType, ok := jweHeader.Type() 193 require.True(t, ok) 194 195 require.Equal(t, transport.MediaTypeV2EncryptedEnvelope, encodingType) 196 197 contentType, ok := jweHeader.ContentType() 198 require.True(t, contentType == "" || contentType != "" && ok) 199 200 require.Equal(t, cty, contentType) 201 } 202 203 func TestAnoncryptPackerSuccessWithDifferentCurvesSuccess(t *testing.T) { 204 log.SetLevel("aries-framework/pkg/didcomm/packer/anoncrypt", spilog.DEBUG) 205 206 k := createKMS(t) 207 _, recDIDKeys, recipientsKey1, keyHandles1 := createRecipients(t, k, 1) 208 _, _, recipientsKey2, _ := createRecipientsByKeyType(t, k, 1, kms.NISTP384ECDHKW) //nolint:dogsled 209 _, _, recipientsKey3, _ := createRecipientsByKeyType(t, k, 1, kms.NISTP521ECDHKW) //nolint:dogsled 210 _, _, recipientsKey4, _ := createRecipientsByKeyType(t, k, 1, kms.X25519ECDHKW) //nolint:dogsled 211 212 recipientsKeys := make([][]byte, 4) 213 recipientsKeys[0] = make([]byte, len(recipientsKey1[0])) 214 recipientsKeys[1] = make([]byte, len(recipientsKey2[0])) 215 recipientsKeys[2] = make([]byte, len(recipientsKey3[0])) 216 recipientsKeys[3] = make([]byte, len(recipientsKey4[0])) 217 218 copy(recipientsKeys[0], recipientsKey1[0]) 219 copy(recipientsKeys[1], recipientsKey2[0]) 220 copy(recipientsKeys[2], recipientsKey3[0]) 221 copy(recipientsKeys[3], recipientsKey4[0]) 222 223 cty := transport.MediaTypeV1PlaintextPayload 224 225 cryptoSvc, err := tinkcrypto.New() 226 require.NoError(t, err) 227 228 anonPacker, err := New(newMockProvider(k, cryptoSvc), afgjose.A256GCM) 229 require.NoError(t, err) 230 231 origMsg := []byte("secret message") 232 ct, err := anonPacker.Pack(cty, origMsg, nil, recipientsKeys) 233 require.NoError(t, err) 234 235 ctStr, err := prettyPrint(ct) 236 require.NoError(t, err) 237 238 t.Logf("anoncrypt JWE: %s", ctStr) 239 240 msg, err := anonPacker.Unpack(ct) 241 require.NoError(t, err) 242 243 recKey, err := exportPubKeyBytes(keyHandles1[0], recDIDKeys[0]) 244 require.NoError(t, err) 245 246 require.EqualValues(t, &transport.Envelope{ 247 Message: origMsg, 248 ToKey: recKey, 249 }, msg) 250 251 // try with only 1 recipient 252 ct, err = anonPacker.Pack(cty, origMsg, nil, [][]byte{recipientsKeys[0]}) 253 require.NoError(t, err) 254 255 msg, err = anonPacker.Unpack(ct) 256 require.NoError(t, err) 257 258 require.EqualValues(t, &transport.Envelope{ 259 Message: origMsg, 260 ToKey: recKey, 261 }, msg) 262 } 263 264 func TestAnoncryptPackerFail(t *testing.T) { 265 cty := transport.MediaTypeV1PlaintextPayload 266 267 t.Run("new Pack fail with nil crypto service", func(t *testing.T) { 268 k := createKMS(t) 269 270 _, err := New(newMockProvider(k, nil), afgjose.A128CBCHS256) 271 require.EqualError(t, err, "anoncrypt: failed to create packer because crypto service is empty") 272 }) 273 274 cryptoSvc, err := tinkcrypto.New() 275 require.NoError(t, err) 276 277 t.Run("new Pack fail with nil kms", func(t *testing.T) { 278 _, err = New(newMockProvider(nil, cryptoSvc), afgjose.A256GCM) 279 require.EqualError(t, err, "anoncrypt: failed to create packer because KMS is empty") 280 }) 281 282 t.Run("new Pack fail with nil vdr", func(t *testing.T) { 283 k := createKMS(t) 284 c, e := tinkcrypto.New() 285 require.NoError(t, e) 286 287 p := newMockProvider(k, c) 288 p.VDRegistryValue = nil 289 290 _, err = New(p, afgjose.A192CBCHS384) 291 require.EqualError(t, err, "anoncrypt: failed to create packer because vdr registry is empty") 292 }) 293 294 k := createKMS(t) 295 _, _, recipientsKeys, _ := createRecipients(t, k, 10) //nolint:dogsled 296 origMsg := []byte("secret message") 297 anonPacker, err := New(newMockProvider(k, cryptoSvc), afgjose.A256GCM) 298 require.NoError(t, err) 299 300 t.Run("pack fail with empty recipients keys", func(t *testing.T) { 301 _, err = anonPacker.Pack(cty, origMsg, nil, nil) 302 require.EqualError(t, err, "anoncrypt Pack: empty recipientsPubKeys") 303 }) 304 305 t.Run("unpack fail with bad recipient key", func(t *testing.T) { 306 _, _, keys, _ := createRecipients(t, k, 1) 307 keys[0] = []byte(strings.Replace(string(keys[0]), "did:key:", "invalid", 1)) 308 var ct []byte 309 ct, err = anonPacker.Pack(cty, origMsg, nil, keys) 310 require.NoError(t, err) 311 _, err = anonPacker.Unpack(ct) 312 require.Contains(t, err.Error(), "invalid kid format, must be a did:key") 313 }) 314 315 t.Run("pack fail with invalid recipients keys", func(t *testing.T) { 316 _, err = anonPacker.Pack(cty, origMsg, nil, [][]byte{[]byte("invalid")}) 317 require.EqualError(t, err, "anoncrypt Pack: failed to convert recipient keys: invalid character 'i' "+ 318 "looking for beginning of value") 319 }) 320 321 t.Run("pack fail with invalid encAlg", func(t *testing.T) { 322 invalidAlg := "invalidAlg" 323 invalidAnonPacker, err := New(newMockProvider(k, cryptoSvc), afgjose.EncAlg(invalidAlg)) 324 require.NoError(t, err) 325 326 _, err = invalidAnonPacker.Pack(cty, origMsg, nil, recipientsKeys) 327 require.EqualError(t, err, fmt.Sprintf("anoncrypt Pack: failed to new JWEEncrypt instance: encryption"+ 328 " algorithm '%s' not supported", invalidAlg)) 329 }) 330 331 t.Run("pack success but unpack fails with invalid payload", func(t *testing.T) { 332 validAnonPacker, err := New(newMockProvider(k, cryptoSvc), afgjose.A256GCM) 333 require.NoError(t, err) 334 335 _, err = validAnonPacker.Pack(cty, origMsg, nil, recipientsKeys) 336 require.NoError(t, err) 337 338 _, err = validAnonPacker.Unpack([]byte("invalid jwe envelope")) 339 require.Error(t, err) 340 require.Contains(t, err.Error(), "anoncrypt Unpack: failed to deserialize JWE message: invalid compact "+ 341 "JWE: it must have five parts") 342 }) 343 344 t.Run("pack success but unpack fails with invalid payload auth (iv) data", func(t *testing.T) { 345 validAnonPacker, err := New(newMockProvider(k, cryptoSvc), afgjose.A192CBCHS384) 346 require.NoError(t, err) 347 348 var s []byte 349 350 s, err = validAnonPacker.Pack(cty, origMsg, nil, recipientsKeys) 351 require.NoError(t, err) 352 353 ivStartIndex := bytes.Index(s, []byte("\"iv\"")) 354 ivEndIndex := ivStartIndex + 6 + bytes.Index(s[ivStartIndex+6:], []byte("\"")) 355 sTrail := make([]byte, len(s[ivEndIndex:])) 356 copy(sTrail, s[ivEndIndex:]) 357 s = append(s[:ivStartIndex+6], []byte("K3ORqVx392nLcdJveUl_Jg")...) // invalid base64 iv causes decryption error 358 s = append(s, sTrail...) 359 360 _, err = validAnonPacker.Unpack(s) 361 require.Error(t, err) 362 require.Contains(t, err.Error(), "anoncrypt Unpack: failed to decrypt JWE envelope: ecdh_factory: "+ 363 "decryption failed") 364 }) 365 366 t.Run("pack success but unpack fails with missing keyID in protectedHeader", func(t *testing.T) { 367 validAnonPacker, err := New(newMockProvider(k, cryptoSvc), afgjose.A256GCM) 368 require.NoError(t, err) 369 370 ct, err := validAnonPacker.Pack(cty, origMsg, nil, [][]byte{recipientsKeys[0]}) 371 require.NoError(t, err) 372 373 jwe, err := afgjose.Deserialize(string(ct)) 374 require.NoError(t, err) 375 376 delete(jwe.ProtectedHeaders, afgjose.HeaderKeyID) 377 378 newCT, err := jwe.CompactSerialize(json.Marshal) 379 require.NoError(t, err) 380 381 _, err = validAnonPacker.Unpack([]byte(newCT)) 382 require.EqualError(t, err, "anoncrypt Unpack: single recipient missing 'KID' in jwe.ProtectHeaders") 383 }) 384 385 t.Run("pack success but unpack fails with missing kid in kms", func(t *testing.T) { 386 kids, _, newRecKeys, _ := createRecipients(t, k, 2) 387 validAnonPacker, err := New(newMockProvider(k, cryptoSvc), afgjose.A256GCM) 388 require.NoError(t, err) 389 390 ct, err := validAnonPacker.Pack(cty, origMsg, nil, newRecKeys) 391 require.NoError(t, err) 392 393 // rotate keys to update keyID and force a failure 394 _, _, err = k.Rotate(kms.NISTP256ECDHKWType, kids[0]) 395 require.NoError(t, err) 396 397 _, _, err = k.Rotate(kms.NISTP256ECDHKWType, kids[1]) 398 require.NoError(t, err) 399 400 _, err = validAnonPacker.Unpack(ct) 401 require.EqualError(t, err, "anoncrypt Unpack: no matching recipient in envelope") 402 }) 403 } 404 405 func exportPubKeyBytes(keyHandle *keyset.Handle, kid string) ([]byte, error) { 406 pubKH, err := keyHandle.Public() 407 if err != nil { 408 return nil, err 409 } 410 411 buf := new(bytes.Buffer) 412 pubKeyWriter := keyio.NewWriter(buf) 413 414 err = pubKH.WriteWithNoSecrets(pubKeyWriter) 415 if err != nil { 416 return nil, err 417 } 418 419 pubKey := &cryptoapi.PublicKey{} 420 421 err = json.Unmarshal(buf.Bytes(), pubKey) 422 if err != nil { 423 return nil, err 424 } 425 426 pubKey.KID = kid 427 428 return json.Marshal(pubKey) 429 } 430 431 // createRecipients and return their public key and keyset.Handle. 432 func createRecipients(t *testing.T, k *localkms.LocalKMS, 433 recipientsCount int) ([]string, []string, [][]byte, []*keyset.Handle) { 434 return createRecipientsByKeyType(t, k, recipientsCount, kms.NISTP256ECDHKW) 435 } 436 437 func createRecipientsByKeyType(t *testing.T, k *localkms.LocalKMS, recipientsCount int, 438 kt kms.KeyType) ([]string, []string, [][]byte, []*keyset.Handle) { 439 t.Helper() 440 441 var ( 442 r [][]byte 443 rKH []*keyset.Handle 444 kids []string 445 didKeys []string 446 ) 447 448 for i := 0; i < recipientsCount; i++ { 449 kid, didKey, marshalledPubKey, kh := createAndMarshalKeyByKeyType(t, k, kt) 450 451 r = append(r, marshalledPubKey) 452 rKH = append(rKH, kh) 453 kids = append(kids, kid) 454 didKeys = append(didKeys, didKey) 455 } 456 457 return kids, didKeys, r, rKH 458 } 459 460 // createAndMarshalKeyByKeyType creates a new recipient keyset.Handle, extracts public key, marshals it and returns 461 // both marshalled public key, jwk kid, didKey and original recipient keyset.Handle. 462 func createAndMarshalKeyByKeyType(t *testing.T, k *localkms.LocalKMS, 463 kt kms.KeyType) (string, string, []byte, *keyset.Handle) { 464 t.Helper() 465 466 kid, keyHandle, err := k.Create(kt) 467 require.NoError(t, err) 468 469 kh, ok := keyHandle.(*keyset.Handle) 470 require.True(t, ok) 471 472 pubKeyBytes, err := exportPubKeyBytes(kh, kid) 473 require.NoError(t, err) 474 475 key := &cryptoapi.PublicKey{} 476 err = json.Unmarshal(pubKeyBytes, key) 477 require.NoError(t, err) 478 479 didKey, err := kmsdidkey.BuildDIDKeyByKeyType(pubKeyBytes, kt) 480 require.NoError(t, err) 481 482 key.KID = didKey 483 mKey, err := json.Marshal(key) 484 require.NoError(t, err) 485 486 printKey(t, mKey, kh, kid, didKey) 487 488 return kid, didKey, mKey, kh 489 } 490 491 func printKey(t *testing.T, mPubKey []byte, kh *keyset.Handle, kid, didKey string) { 492 t.Helper() 493 494 extractKey, err := extractPrivKey(kh) 495 require.NoError(t, err) 496 497 switch keyType := extractKey.(type) { 498 case *hybrid.ECPrivateKey: 499 t.Logf("** EC key: %s, \n\t kms kid: %s, \n\t jwe kid (did:key):%s", getPrintedECPrivKey(t, keyType), kid, 500 didKey) 501 case []byte: 502 pubKey := new(cryptoapi.PublicKey) 503 err := json.Unmarshal(mPubKey, pubKey) 504 require.NoError(t, err) 505 506 fullKey := append(keyType, pubKey.X...) 507 t.Logf("** X25519 key: %s, \n\t kms kid: %s, \n\t jwe kid (did:key):%s", getPrintedX25519PrivKey(t, fullKey), kid, 508 didKey) 509 default: 510 t.Errorf("not supported key type: %s", keyType) 511 } 512 } 513 514 func prettyPrint(msg []byte) (string, error) { 515 var prettyJSON bytes.Buffer 516 517 err := json.Indent(&prettyJSON, msg, "", "\t") 518 if err != nil { 519 return "", err 520 } 521 522 return prettyJSON.String(), nil 523 } 524 525 func getPrintedECPrivKey(t *testing.T, privKeyType *hybrid.ECPrivateKey) string { 526 jwk := jose.JSONWebKey{ 527 Key: &ecdsa.PrivateKey{ 528 PublicKey: ecdsa.PublicKey{ 529 Curve: privKeyType.PublicKey.Curve, 530 X: privKeyType.PublicKey.Point.X, 531 Y: privKeyType.PublicKey.Point.Y, 532 }, 533 D: privKeyType.D, 534 }, 535 } 536 537 jwkByte, err := jwk.MarshalJSON() 538 require.NoError(t, err) 539 540 jwkStr, err := prettyPrint(jwkByte) 541 require.NoError(t, err) 542 543 return jwkStr 544 } 545 546 func getPrintedX25519PrivKey(t *testing.T, privKeyType ed25519.PrivateKey) string { 547 jwk := jose.JSONWebKey{ 548 Key: privKeyType, 549 } 550 551 jwkByte, err := jwk.MarshalJSON() 552 require.NoError(t, err) 553 554 jwkStr, err := prettyPrint(jwkByte) 555 require.NoError(t, err) 556 557 return strings.Replace(jwkStr, "Ed25519", "X25519", 1) 558 } 559 560 func extractPrivKey(kh *keyset.Handle) (interface{}, error) { 561 nistPECDHKWPrivateKeyTypeURL := "type.hyperledger.org/hyperledger.aries.crypto.tink.NistPEcdhKwPrivateKey" 562 x25519ECDHKWPrivateKeyTypeURL := "type.hyperledger.org/hyperledger.aries.crypto.tink.X25519EcdhKwPrivateKey" 563 buf := new(bytes.Buffer) 564 w := &privKeyWriter{w: buf} 565 nAEAD := &noopAEAD{} 566 567 if kh == nil { 568 return nil, fmt.Errorf("extractPrivKey: kh is nil") 569 } 570 571 err := kh.Write(w, nAEAD) 572 if err != nil { 573 return nil, fmt.Errorf("extractPrivKey: retrieving private key failed: %w", err) 574 } 575 576 ks := new(tinkpb.Keyset) 577 578 err = proto.Unmarshal(buf.Bytes(), ks) 579 if err != nil { 580 return nil, errors.New("extractPrivKey: invalid private key") 581 } 582 583 primaryKey := ks.Key[0] 584 585 switch primaryKey.KeyData.TypeUrl { 586 case nistPECDHKWPrivateKeyTypeURL: 587 pbKey := new(ecdhpb.EcdhAeadPrivateKey) 588 589 err = proto.Unmarshal(primaryKey.KeyData.Value, pbKey) 590 if err != nil { 591 return nil, errors.New("extractPrivKey: invalid key in keyset") 592 } 593 594 var c elliptic.Curve 595 596 c, err = hybrid.GetCurve(pbKey.PublicKey.Params.KwParams.CurveType.String()) 597 if err != nil { 598 return nil, fmt.Errorf("extractPrivKey: invalid key: %w", err) 599 } 600 601 return hybrid.GetECPrivateKey(c, pbKey.KeyValue), nil 602 case x25519ECDHKWPrivateKeyTypeURL: 603 pbKey := new(ecdhpb.EcdhAeadPrivateKey) 604 605 err = proto.Unmarshal(primaryKey.KeyData.Value, pbKey) 606 if err != nil { 607 return nil, errors.New("extractPrivKey: invalid key in keyset") 608 } 609 610 if pbKey.PublicKey.Params.KwParams.CurveType.String() != commonpb.EllipticCurveType_CURVE25519.String() { 611 return nil, errors.New("extractPrivKey: invalid key curve") 612 } 613 614 return pbKey.KeyValue, nil 615 } 616 617 return nil, fmt.Errorf("extractPrivKey: can't extract unsupported private key '%s'", primaryKey.KeyData.TypeUrl) 618 } 619 620 type noopAEAD struct{} 621 622 func (n noopAEAD) Encrypt(plaintext, _ []byte) ([]byte, error) { 623 return plaintext, nil 624 } 625 626 func (n noopAEAD) Decrypt(ciphertext, _ []byte) ([]byte, error) { 627 return ciphertext, nil 628 } 629 630 type privKeyWriter struct { 631 w io.Writer 632 } 633 634 // Write writes the public keyset to the underlying w.Writer. It's not used in this implementation. 635 func (p *privKeyWriter) Write(_ *tinkpb.Keyset) error { 636 return fmt.Errorf("privKeyWriter: write function not supported") 637 } 638 639 // WriteEncrypted writes the encrypted keyset to the underlying w.Writer. 640 func (p *privKeyWriter) WriteEncrypted(ks *tinkpb.EncryptedKeyset) error { 641 return write(p.w, ks) 642 } 643 644 func write(w io.Writer, ks *tinkpb.EncryptedKeyset) error { 645 // we write EncryptedKeyset directly without decryption since noopAEAD was used to write *keyset.Handle 646 _, e := w.Write(ks.EncryptedKeyset) 647 return e 648 } 649 650 func createKMS(t *testing.T) *localkms.LocalKMS { 651 t.Helper() 652 653 p, err := mockkms.NewProviderForKMS(mockstorage.NewMockStoreProvider(), &noop.NoLock{}) 654 require.NoError(t, err) 655 656 k, err := localkms.New("local-lock://test/key/uri", p) 657 require.NoError(t, err) 658 659 return k 660 } 661 662 func newMockProvider(customKMS kms.KeyManager, customCrypto cryptoapi.Crypto) *mockprovider.Provider { 663 return &mockprovider.Provider{ 664 KMSValue: customKMS, 665 CryptoValue: customCrypto, 666 VDRegistryValue: &mockvdr.MockVDRegistry{}, 667 } 668 }