elastic / request-crypto

Encrypt/Decrypt request payload
Other
6 stars 6 forks source link

add `createRequestDecryptor.getJWKMetadata` method #9

Closed Bamieh closed 3 years ago

Bamieh commented 3 years ago

This PR adds a new method to the request decryptor API. The method getJWKMetadata returns the metadata of the JWK used to encrypt the request body.

The metadata is an object including the following:

Usage:

import { createRequestDecryptor } from '@elastic/request-crypto';
import privateJWKS from './privateJWKS';

async function handler (event, context, callback) {
  const requestDecryptor = await createRequestDecryptor(privateJWKS);
  const jwkMetadata = await requestDecryptor.getJWKMetadata(event.body);

  // ... use metadata
}

If the key is not in the provided JWKS the function will throw an error Error: no key found.

cc @JoshMock Related: https://github.com/elastic/infra/issues/26063

Bamieh commented 3 years ago

@afharo Thanks for the review!

For that use case, though, I feel like we are decrypting twice: once to get the metadata and a 2nd time to decrypt the payload. Would it make sense to have a way to avoid the double decryption of the key? What do you think?

The library uses 2 encryptions to encrypt a payload:

  1. Actual payload uses AES encryption: a. Sender encrypts data with a randomly generated 32-bytes AES passphrase. b. Sender encrypts payload with a strong AES 256 bit key that is derived from the passphrase.

  2. Encrypting the AES passphrase uses RSA a. Use Public RSA key that is shipped with Kibana to encrypt the AES key.

To get the AES passphrase we need to decrypt the key using the private JWKS. Then we use that to passphrase decrypt the actual payload.

So we always need the double decryption since they serve different use cases.

The JWK decryption is super fast and lightweight. Decrypting the actual payload (AES) is more costly. Thus it makes sense to provice the getJWKMetadata method for usecases the require checking the key metadata without decrypting the actual payload.

If you have more questions happy to discuss it! I find this topic super fascinating. I have everything documented in the README too :) . #why answers why we have this double encryption strategy to begin with.

afharo commented 3 years ago

@Bamieh I understand the reasoning behind the double encryption: encrypting the content with a passphrase, and the passphrase with JWK.

What I meant with double-decryption was about getting the passphrase twice. In case we need to run getJWKMetadata to identify something from the data provided in the JWK, and then decrypt the payload, we'd be decrypting the JWK Metadata twice. I don't know how much worth it is to consider a method decryptWithKnownJWKMetadata(payloadToDecrypt, knownDecryptedJWKMetadata). But again, this is just a Super-NIT, and I think this is very simple to implement and can be done in future if needed. No need to block this PR for that :)