Skip to content

This library is an extension of the node-jose library, and uses monkey-patching to extend the capabilities of node-jose. It provides JWE-based encrypters/decrypters and JWS-based signers/verifiers for cryptographic operations with keys stored in AWS Key Management Service (KMS).

License

amzn/node-jose_aws-kms-extension

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

node-jose_aws-kms-extension

This library is an extension of the node-jose library, and uses monkey-patching to extend the capabilities of node-jose. It provides JWE-based encrypters/decrypters and JWS-based signers/verifiers for cryptographic operations with keys stored in AWS Key Management Service (KMS).

Installation

You can install the library from npm using the following command. This library requires Node.js 18 or above.

npm install @aws-crypto/node-jose_aws-kms-extension

Usage

Import the necessary classes from @aws-crypto/node-jose_aws-kms-extension module:

import {
  KMSAsymmetricSigningKey,
  KMSSymmetricCEK,
  KMSSymmetricKey,
} from '@aws-crypto/node-jose_aws-kms-extension';

Import the main jose object.

import { jose } from '@aws-crypto/node-jose_aws-kms-extension';

Now, you can use all existing node-jose features as you would in the absence of this library. This library adds AWS KMS support transparently. You can use your AWS KMS keys for various encryption and signing operations using the regular node-jose functions. AWS KMS-specific algorithm names are supported.

Supported node-jose functions include:

  1. jose.JWE.createEncrypt()
  2. jose.JWE.createDecrypt()
  3. jose.JWS.createSign()
  4. jose.JWS.createVerify()

This library uses @aws-sdk/client-kms for all its communication with AWS KMS.

Supported KMS Signing Algorithms

Supported KMS Encryption Algorithms

Supported Data Key Spec

Examples

Importing variables from modules @aws-crypto/node-jose_aws-kms-extension and @aws-sdk/client-kms

import {
  jose,
  KMSAsymmetricSigningKey,
  KMSSymmetricCEK,
  KMSSymmetricKey,
} from '@aws-crypto/node-jose_aws-kms-extension';
import { KMSClient } from "@aws-sdk/client-kms";

Creating AWS KMS Client

const kmsClient: KMSClient = new KMSClient({ region: 'REGION' });

Signing

  1. Prepare signing options with format as compact, and header fields.
  2. Prepare signatory with key as KMSAsymmetricSigningKey object.
  3. Use jose.JWS.createSign method to sign the payload.
const signingOpts = {
  format: 'compact',
  fields: {
    alg: 'SIGNING_ALGORITHM',
    kid: 'KMS_SIGNING_KEY_ID',
    JWS_CRIT_HEADER1: 'JWS_CRIT_HEADER1_VALUE',
    JWS_CRIT_HEADER2: 'JWS_CRIT_HEADER2_VALUE',
    crit: ['JWS_CRIT_HEADER1', 'JWS_CRIT_HEADER2'],
  },
};

const signatory = {
  key: new KMSAsymmetricSigningKey('KMS_SIGNING_KEY_ID', kmsClient),
};

const dataToSign = 'This is the data to sign';
const signer = jose.JWS.createSign(signingOpts, signatory);
const jws: Promise<string> = signer
  .update(dataToSign)
  .final()
  .then(function (result: string) {
    console.log('JWS: ', result);
    return result;
  });

Encryption

  1. Prepare encryption options with format as compact, header fields and cek as KMSSymmetricCEK object.
  2. Prepare encryption recipient with reference as false, and key as KMSSymmetricKey object. Use same KMS key to create KMSSymmetricCEK and KMSSymmetricKey.
  3. Use jose.JWE.createEncrypt method to encrypt jws payload.
const encryptionOpts = {
  format: 'compact',
  fields: {
    kid: 'ENCRYPTION_KMS_KEY_ID',
    alg: 'KEY_ENCRYPTION_ALGORITHM',
    enc: 'CONTENT_ENCRYPTION_ALGORITHM',
    JWE_CRIT_HEADER1: 'JWE_CRIT_HEADER1_VALUE',
    JWE_CRIT_HEADER2: 'JWE_CRIT_HEADER2_VALUE',
    crit: ['JWE_CRIT_HEADER1', 'JWE_CRIT_HEADER2'],
  },
  cek: new KMSSymmetricCEK('KMS_ENCRYPTION_KEY_ID', kmsClient, 'KEY_SPEC'),
};

const encryptionRecipient = {
  reference: false,
  key: new KMSSymmetricKey('KMS_ENCRYPTION_KEY_ID', kmsClient),
};

const encrypter = jose.JWE.createEncrypt(
  encryptionOpts,
  encryptionRecipient,
);
const jwe: Promise<string> = jws.then(function (jws: string) {
  return encrypter
    .update(jws)
    .final()
    .then(function (result: string) {
      console.log('JWE: ', result);
      return result;
    });
});

Decryption

  1. Prepare decryption options with handlers to process jwe critical headers.
  2. Preare decryption assumed key as KMSSymmetricKey object
  3. Use jose.JWE.createDecrypt method to decrypt jwe payload.
const decryption_opts = {
  handlers: {
    JWE_CRIT_HEADER1: function(jwe: any) {
      console.log(jwe.header.JWE_CRIT_HEADER1)
      // process JWE_CRIT_HEADER1
    },
    JWE_CRIT_HEADER2: function(jwe: any) {
      console.log(jwe.header.JWE_CRIT_HEADER2)
      // process JWE_CRIT_HEADER2
    }
  },
};

const decryption_assumedKey = new KMSSymmetricKey(
  'KMS_ENCRYPTION_KEY_ID',
  kmsClient,
);

const decrypter = jose.JWE.createDecrypt(
  decryption_assumedKey,
  decryption_opts,
);

const decyptedContent: Promise<any> = jwe.then(function (jwe: string) {
  return decrypter.decrypt(jwe).then(function (result: any) {
    console.log('JWE decryption result: ', result);
    return result;
  });
});

Verification

  1. Prepare verification options with handlers to process jws critical headers.
  2. Prepare verification assumed key as KMSAsymmetricSigningKey object
  3. Use jose.JWS.createVerify method to verify jws payload.
const verification_opts = {
  handlers: {
    JWS_CRIT_HEADER1: function(jws: any) {
      console.log(jws.header.JWS_CRIT_HEADER1)
      // process JWS_CRIT_HEADER1
    },
    JWS_CRIT_HEADER2: function(jws: any) {
      console.log(jws.header.JWS_CRIT_HEADER2)
      // process JWS_CRIT_HEADER2
    }
  },
};

const verificationAssumedKey = new KMSAsymmetricSigningKey(
  'KMS_SIGNING_KEY_ID',
  kmsClient,
);

const verifier = jose.JWS.createVerify(
  verificationAssumedKey,
  verification_opts,
);
const verificationResult: Promise<any> = decyptedContent.then(function (
  decryptedContent: any,
) {
  const payloadToVerify = jose.util.utf8.encode(decryptedContent.payload);
  return verifier.verify(payloadToVerify).then(function (result: any) {
    console.log('JWS verification result: ', result);
    console.log('Verified payload: ', jose.util.utf8.encode(result.payload));
    return result;
  });
});

Note: KMS_SIGNING_KEY_ID and KMS_ENCRYPTION_KEY_ID can be KMS key ID, key ARN, alias name, or alias ARN. When using an alias name, it will have prefix alias/. It should be key ARN or alias ARN to specify in different Amazon Web Services account.

Security

See CONTRIBUTING for more information.

License

This library is distributed under the Apache License, Version 2.0, see LICENSE and NOTICE for more information.

About

This library is an extension of the node-jose library, and uses monkey-patching to extend the capabilities of node-jose. It provides JWE-based encrypters/decrypters and JWS-based signers/verifiers for cryptographic operations with keys stored in AWS Key Management Service (KMS).

Topics

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

No packages published