Utilisation de la mise en cache des clés de données - AWS Encryption SDK

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Utilisation de la mise en cache des clés de données

Cette rubrique vous montre comment utiliser la mise en cache des clés de données dans votre application. Elle vous guide à travers le processus étape par étape. Elle associe ensuite les étapes dans un exemple simple qui utilise la mise en cache des clés de données dans une opération visant à chiffrer une chaîne.

Les exemples de cette section montrent comment utiliser la version 2.0. x et versions ultérieures duAWS Encryption SDK. Pour les exemples utilisant des versions antérieures, recherchez votre version dans la liste des versions du GitHub référentiel de votre langage de programmation.

Pour obtenir des exemples complets et testés d'utilisation de la mise en cache de clés de données dans le AWS Encryption SDK, veuillez consulter :

AWS Encryption SDKfor .NET ne prend pas en charge la mise en cache des clés de données.

Utilisation de la mise en cache des clés de données : S tep-by-step

Ces step-by-step instructions vous montrent comment créer les composants dont vous avez besoin pour implémenter la mise en cache des clés de données.

  • Création d'un cache de clé de données Dans ces exemples, nous utilisons le cache local AWS Encryption SDK fourni par le. Nous limitons le cache à 10 clés de données.

     

    C
    // Cache capacity (maximum number of entries) is required size_t cache_capacity = 10; struct aws_allocator *allocator = aws_default_allocator(); struct aws_cryptosdk_materials_cache *cache = aws_cryptosdk_materials_cache_local_new(allocator, cache_capacity);
    Java

    L'exemple suivant utilise la version 2. x duKit SDK de chiffrement AWS pour Java. Version 3. x du rend Kit SDK de chiffrement AWS pour Java obsolète le CMM de mise en cache des clés de données. Avec la version 3. x, vous pouvez également utiliser le trousseau de clés AWS KMS hiérarchique, une solution alternative de mise en cache des matériaux cryptographiques.

    // Cache capacity (maximum number of entries) is required int MAX_CACHE_SIZE = 10; CryptoMaterialsCache cache = new LocalCryptoMaterialsCache(MAX_CACHE_SIZE);
    JavaScript Browser
    const capacity = 10 const cache = getLocalCryptographicMaterialsCache(capacity)
    JavaScript Node.js
    const capacity = 10 const cache = getLocalCryptographicMaterialsCache(capacity)
    Python
    # Cache capacity (maximum number of entries) is required MAX_CACHE_SIZE = 10 cache = aws_encryption_sdk.LocalCryptoMaterialsCache(MAX_CACHE_SIZE)

     

  • Créez un fournisseur de clés principales (Java et Python) ou un trousseau de clés (C et JavaScript). Ces exemples utilisent un fournisseur de clés principales AWS Key Management Service (AWS KMS) ou un trousseau de AWS KMSclés compatible.

     

    C
    // Create an AWS KMS keyring // The input is the Amazon Resource Name (ARN) // of an AWS KMS key struct aws_cryptosdk_keyring *kms_keyring = Aws::Cryptosdk::KmsKeyring::Builder().Build(kms_key_arn);
    Java

    L'exemple suivant utilise la version 2. x duKit SDK de chiffrement AWS pour Java. Version 3. x du rend Kit SDK de chiffrement AWS pour Java obsolète le CMM de mise en cache des clés de données. Avec la version 3. x, vous pouvez également utiliser le trousseau de clés AWS KMS hiérarchique, une solution alternative de mise en cache des matériaux cryptographiques.

    // Create an AWS KMS master key provider // The input is the Amazon Resource Name (ARN) // of an AWS KMS key MasterKeyProvider<KmsMasterKey> keyProvider = KmsMasterKeyProvider.builder().buildStrict(kmsKeyArn);
    JavaScript Browser

    Dans le navigateur, vous devez injecter vos informations d'identification en toute sécurité. Cet exemple définit les informations d'identification dans un webpack (kms.webpack.config) qui résout les informations d'identification lors de l'exécution. Il crée une instance de fournisseur client AWS KMS à partir d'un client AWS KMS et les informations d'identification. Ensuite, lorsqu'il crée le trousseau de clés, il transmet le fournisseur client au constructeur avec le AWS KMS key (. generatorKeyId)

    const { accessKeyId, secretAccessKey, sessionToken } = credentials const clientProvider = getClient(KMS, { credentials: { accessKeyId, secretAccessKey, sessionToken } }) /* Create an AWS KMS keyring * You must configure the AWS KMS keyring with at least one AWS KMS key * The input is the Amazon Resource Name (ARN) */ of an AWS KMS key const keyring = new KmsKeyringBrowser({ clientProvider, generatorKeyId, keyIds, })
    JavaScript Node.js
    /* Create an AWS KMS keyring * The input is the Amazon Resource Name (ARN) */ of an AWS KMS key const keyring = new KmsKeyringNode({ generatorKeyId })
    Python
    # Create an AWS KMS master key provider # The input is the Amazon Resource Name (ARN) # of an AWS KMS key key_provider = aws_encryption_sdk.StrictAwsKmsMasterKeyProvider(key_ids=[kms_key_arn])

     

  • Créez un gestionnaire de matériel cryptographique de mise en cache (CMM de mise en cache).

     

    Associez votre CMM de mise en cache à votre cache et à votre fournisseur de clé principale ou à votre trousseau de clés. Définissez ensuite les seuils de sécurité du cache sur le CMM de mise en cache.

     

    C

    Dans leKit SDK de chiffrement AWS pour C, vous pouvez créer un CMM de mise en cache à partir d'un CMM sous-jacent, tel que le CMM par défaut, ou à partir d'un trousseau de clés. Cet exemple crée le CMM de mise en cache à partir d'un porte-clés.

    Après avoir créé le CMM de mise en cache, vous pouvez libérer vos références au trousseau de clés et au cache. Pour plus de détails, consultez Comptage des références.

    // Create the caching CMM // Set the partition ID to NULL. // Set the required maximum age value to 60 seconds. struct aws_cryptosdk_cmm *caching_cmm = aws_cryptosdk_caching_cmm_new_from_keyring(allocator, cache, kms_keyring, NULL, 60, AWS_TIMESTAMP_SECS); // Add an optional message threshold // The cached data key will not be used for more than 10 messages. aws_status = aws_cryptosdk_caching_cmm_set_limit_messages(caching_cmm, 10); // Release your references to the cache and the keyring. aws_cryptosdk_materials_cache_release(cache); aws_cryptosdk_keyring_release(kms_keyring);
    Java

    L'exemple suivant utilise la version 2. x duKit SDK de chiffrement AWS pour Java. Version 3. x of the Kit SDK de chiffrement AWS pour Java ne prend pas en charge la mise en cache des clés de données, mais prend en charge le keyring AWS KMS hiérarchique, une solution alternative de mise en cache des matériaux cryptographiques.

    /* * Security thresholds * Max entry age is required. * Max messages (and max bytes) per entry are optional */ int MAX_ENTRY_AGE_SECONDS = 60; int MAX_ENTRY_MSGS = 10; //Create a caching CMM CryptoMaterialsManager cachingCmm = CachingCryptoMaterialsManager.newBuilder().withMasterKeyProvider(keyProvider) .withCache(cache) .withMaxAge(MAX_ENTRY_AGE_SECONDS, TimeUnit.SECONDS) .withMessageUseLimit(MAX_ENTRY_MSGS) .build();
    JavaScript Browser
    /* * Security thresholds * Max age (in milliseconds) is required. * Max messages (and max bytes) per entry are optional. */ const maxAge = 1000 * 60 const maxMessagesEncrypted = 10 /* Create a caching CMM from a keyring */ const cachingCmm = new WebCryptoCachingMaterialsManager({ backingMaterials: keyring, cache, maxAge, maxMessagesEncrypted })
    JavaScript Node.js
    /* * Security thresholds * Max age (in milliseconds) is required. * Max messages (and max bytes) per entry are optional. */ const maxAge = 1000 * 60 const maxMessagesEncrypted = 10 /* Create a caching CMM from a keyring */ const cachingCmm = new NodeCachingMaterialsManager({ backingMaterials: keyring, cache, maxAge, maxMessagesEncrypted })
    Python
    # Security thresholds # Max entry age is required. # Max messages (and max bytes) per entry are optional # MAX_ENTRY_AGE_SECONDS = 60.0 MAX_ENTRY_MESSAGES = 10 # Create a caching CMM caching_cmm = CachingCryptoMaterialsManager( master_key_provider=key_provider, cache=cache, max_age=MAX_ENTRY_AGE_SECONDS, max_messages_encrypted=MAX_ENTRY_MESSAGES )

C'est tout ce que vous avez besoin de faire. Ensuite, laissez le kit AWS Encryption SDK gérer le cache pour vous, ou ajoutez votre propre logique de gestion de cache.

Lorsque vous souhaitez utiliser la mise en cache des clés de données dans un appel pour chiffrer ou déchiffrer des données, spécifiez votre CMM de mise en cache plutôt qu'un fournisseur de clé principale ou un autre CMM.

Note

Si vous chiffrez des flux de données, ou des données de taille inconnue, assurez-vous de spécifier la taille des données dans la demande. Le kit AWS Encryption SDK n'utilise pas la mise en cache des clés de données lors du chiffrement des données de taille inconnue.

C

Dans le kit Kit SDK de chiffrement AWS pour C, vous créez une session avec le CMM de mise en cache, puis vous traitez la session.

Par défaut, lorsque la taille du message est inconnue et sans limite, le kit AWS Encryption SDK ne met pas en cache les clés de données. Pour autoriser la mise en cache lorsque vous ne connaissez pas la taille exacte des données, utilisez la méthode aws_cryptosdk_session_set_message_bound pour définir une taille maximale pour le message. Définissez une limite supérieure à la taille estimée du message. Si la taille réelle du message dépasse la limite, l'opération échoue.

/* Create a session with the caching CMM. Set the session mode to encrypt. */ struct aws_cryptosdk_session *session = aws_cryptosdk_session_new_from_cmm_2(allocator, AWS_CRYPTOSDK_ENCRYPT, caching_cmm); /* Set a message bound of 1000 bytes */ aws_status = aws_cryptosdk_session_set_message_bound(session, 1000); /* Encrypt the message using the session with the caching CMM */ aws_status = aws_cryptosdk_session_process( session, output_buffer, output_capacity, &output_produced, input_buffer, input_len, &input_consumed); /* Release your references to the caching CMM and the session. */ aws_cryptosdk_cmm_release(caching_cmm); aws_cryptosdk_session_destroy(session);
Java

L'exemple suivant utilise la version 2. x duKit SDK de chiffrement AWS pour Java. Version 3. x du rend Kit SDK de chiffrement AWS pour Java obsolète le CMM de mise en cache des clés de données. Avec la version 3. x, vous pouvez également utiliser le trousseau de clés AWS KMS hiérarchique, une solution alternative de mise en cache des matériaux cryptographiques.

// When the call to encryptData specifies a caching CMM, // the encryption operation uses the data key cache final AwsCrypto encryptionSdk = AwsCrypto.standard(); return encryptionSdk.encryptData(cachingCmm, plaintext_source).getResult();
JavaScript Browser
const { result } = await encrypt(cachingCmm, plaintext)
JavaScript Node.js

Lorsque vous utilisez le CMM de mise en cache dans Kit SDK de chiffrement AWS pour JavaScript for Node.js, la encrypt méthode nécessite la longueur du texte en clair. Si vous ne le fournissez pas, la clé de données n'est pas mise en cache. Si vous fournissez une longueur, mais que les données en texte brut que vous fournissez dépassent cette longueur, l'opération de chiffrement échoue. Si vous ne connaissez pas la longueur exacte du texte brut, par exemple lorsque vous diffusez des données, indiquez la plus grande valeur attendue.

const { result } = await encrypt(cachingCmm, plaintext, { plaintextLength: plaintext.length })
Python
# Set up an encryption client client = aws_encryption_sdk.EncryptionSDKClient() # When the call to encrypt specifies a caching CMM, # the encryption operation uses the data key cache # encrypted_message, header = client.encrypt( source=plaintext_source, materials_manager=caching_cmm )

Exemple de mise en cache des clés de données : chiffrement d'une chaîne

Cet exemple de code simple utilise la mise en cache des clés de données lors du chiffrement d'une chaîne. Il combine le code de la step-by-step procédure dans un code de test que vous pouvez exécuter.

L'exemple crée un cache local et un fournisseur de clés principales ou un trousseau de clés pour unAWS KMS key. Il utilise ensuite le cache local et le fournisseur de clés principales ou le trousseau de clés pour créer un CMM de mise en cache avec des seuils de sécurité appropriés. En Java et Python, la demande de chiffrement spécifie le CMM de mise en cache, les données en texte brut à chiffrer et un contexte de chiffrement. En C, le CMM de mise en cache est spécifié dans la session et la session est fournie à la demande de chiffrement.

Pour exécuter ces exemples, vous devez fournir le nom de ressource Amazon (ARN) d'un AWS KMS key. Assurez-vous que vous êtes autorisé à utiliser la AWS KMS key pour générer une clé de données.

Pour des exemples concrets plus détaillés de création et d'utilisation d'un cache de clé de données, voirExemple de code de mise en cache des clés de données.

C
/* * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). You may not use * this file except in compliance with the License. A copy of the License is * located at * * http://aws.amazon.com/apache2.0/ * * or in the "license" file accompanying this file. This file is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing permissions and * limitations under the License. */ #include <aws/cryptosdk/cache.h> #include <aws/cryptosdk/cpp/kms_keyring.h> #include <aws/cryptosdk/session.h> void encrypt_with_caching( uint8_t *ciphertext, // output will go here (assumes ciphertext_capacity bytes already allocated) size_t *ciphertext_len, // length of output will go here size_t ciphertext_capacity, const char *kms_key_arn, int max_entry_age, int cache_capacity) { const uint64_t MAX_ENTRY_MSGS = 100; struct aws_allocator *allocator = aws_default_allocator(); // Load error strings for debugging aws_cryptosdk_load_error_strings(); // Create a keyring struct aws_cryptosdk_keyring *kms_keyring = Aws::Cryptosdk::KmsKeyring::Builder().Build(kms_key_arn); // Create a cache struct aws_cryptosdk_materials_cache *cache = aws_cryptosdk_materials_cache_local_new(allocator, cache_capacity); // Create a caching CMM struct aws_cryptosdk_cmm *caching_cmm = aws_cryptosdk_caching_cmm_new_from_keyring( allocator, cache, kms_keyring, NULL, max_entry_age, AWS_TIMESTAMP_SECS); if (!caching_cmm) abort(); if (aws_cryptosdk_caching_cmm_set_limit_messages(caching_cmm, MAX_ENTRY_MSGS)) abort(); // Create a session struct aws_cryptosdk_session *session = aws_cryptosdk_session_new_from_cmm_2(allocator, AWS_CRYPTOSDK_ENCRYPT, caching_cmm); if (!session) abort(); // Encryption context struct aws_hash_table *enc_ctx = aws_cryptosdk_session_get_enc_ctx_ptr_mut(session); if (!enc_ctx) abort(); AWS_STATIC_STRING_FROM_LITERAL(enc_ctx_key, "purpose"); AWS_STATIC_STRING_FROM_LITERAL(enc_ctx_value, "test"); if (aws_hash_table_put(enc_ctx, enc_ctx_key, (void *)enc_ctx_value, NULL)) abort(); // Plaintext data to be encrypted const char *my_data = "My plaintext data"; size_t my_data_len = strlen(my_data); if (aws_cryptosdk_session_set_message_size(session, my_data_len)) abort(); // When the session uses a caching CMM, the encryption operation uses the data key cache // specified in the caching CMM. size_t bytes_read; if (aws_cryptosdk_session_process( session, ciphertext, ciphertext_capacity, ciphertext_len, (const uint8_t *)my_data, my_data_len, &bytes_read)) abort(); if (!aws_cryptosdk_session_is_done(session) || bytes_read != my_data_len) abort(); aws_cryptosdk_session_destroy(session); aws_cryptosdk_cmm_release(caching_cmm); aws_cryptosdk_materials_cache_release(cache); aws_cryptosdk_keyring_release(kms_keyring); }
Java

L'exemple suivant utilise la version 2. x duKit SDK de chiffrement AWS pour Java. Version 3. x du rend Kit SDK de chiffrement AWS pour Java obsolète le CMM de mise en cache des clés de données. Avec la version 3. x, vous pouvez également utiliser le trousseau de clés AWS KMS hiérarchique, une solution alternative de mise en cache des matériaux cryptographiques.

// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package com.amazonaws.crypto.examples; import com.amazonaws.encryptionsdk.AwsCrypto; import com.amazonaws.encryptionsdk.CryptoMaterialsManager; import com.amazonaws.encryptionsdk.MasterKeyProvider; import com.amazonaws.encryptionsdk.caching.CachingCryptoMaterialsManager; import com.amazonaws.encryptionsdk.caching.CryptoMaterialsCache; import com.amazonaws.encryptionsdk.caching.LocalCryptoMaterialsCache; import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKey; import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.Map; import java.util.concurrent.TimeUnit; /** * <p> * Encrypts a string using an &KMS; key and data key caching * * <p> * Arguments: * <ol> * <li>KMS Key ARN: To find the Amazon Resource Name of your &KMS; key, * see 'Find the key ID and ARN' at https://docs.aws.amazon.com/kms/latest/developerguide/find-cmk-id-arn.html * <li>Max entry age: Maximum time (in seconds) that a cached entry can be used * <li>Cache capacity: Maximum number of entries in the cache * </ol> */ public class SimpleDataKeyCachingExample { /* * Security thresholds * Max entry age is required. * Max messages (and max bytes) per data key are optional */ private static final int MAX_ENTRY_MSGS = 100; public static byte[] encryptWithCaching(String kmsKeyArn, int maxEntryAge, int cacheCapacity) { // Plaintext data to be encrypted byte[] myData = "My plaintext data".getBytes(StandardCharsets.UTF_8); // Encryption context // Most encrypted data should have an associated encryption context // to protect integrity. This sample uses placeholder values. // For more information see: // blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management final Map<String, String> encryptionContext = Collections.singletonMap("purpose", "test"); // Create a master key provider MasterKeyProvider<KmsMasterKey> keyProvider = KmsMasterKeyProvider.builder() .buildStrict(kmsKeyArn); // Create a cache CryptoMaterialsCache cache = new LocalCryptoMaterialsCache(cacheCapacity); // Create a caching CMM CryptoMaterialsManager cachingCmm = CachingCryptoMaterialsManager.newBuilder().withMasterKeyProvider(keyProvider) .withCache(cache) .withMaxAge(maxEntryAge, TimeUnit.SECONDS) .withMessageUseLimit(MAX_ENTRY_MSGS) .build(); // When the call to encryptData specifies a caching CMM, // the encryption operation uses the data key cache final AwsCrypto encryptionSdk = AwsCrypto.standard(); return encryptionSdk.encryptData(cachingCmm, myData, encryptionContext).getResult(); } }
JavaScript Browser
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 /* This is a simple example of using a caching CMM with a KMS keyring * to encrypt and decrypt using the AWS Encryption SDK for Javascript in a browser. */ import { KmsKeyringBrowser, KMS, getClient, buildClient, CommitmentPolicy, WebCryptoCachingMaterialsManager, getLocalCryptographicMaterialsCache, } from '@aws-crypto/client-browser' import { toBase64 } from '@aws-sdk/util-base64-browser' /* This builds the client with the REQUIRE_ENCRYPT_REQUIRE_DECRYPT commitment policy, * which enforces that this client only encrypts using committing algorithm suites * and enforces that this client * will only decrypt encrypted messages * that were created with a committing algorithm suite. * This is the default commitment policy * if you build the client with `buildClient()`. */ const { encrypt, decrypt } = buildClient( CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT ) /* This is injected by webpack. * The webpack.DefinePlugin or @aws-sdk/karma-credential-loader will replace the values when bundling. * The credential values are pulled from @aws-sdk/credential-provider-node * Use any method you like to get credentials into the browser. * See kms.webpack.config */ declare const credentials: { accessKeyId: string secretAccessKey: string sessionToken: string } /* This is done to facilitate testing. */ export async function testCachingCMMExample() { /* This example uses an &KMS; keyring. The generator key in a &KMS; keyring generates and encrypts the data key. * The caller needs kms:GenerateDataKey permission on the &KMS; key in generatorKeyId. */ const generatorKeyId = 'arn:aws:kms:us-west-2:658956600833:alias/EncryptDecrypt' /* Adding additional KMS keys that can decrypt. * The caller must have kms:Encrypt permission for every &KMS; key in keyIds. * You might list several keys in different AWS Regions. * This allows you to decrypt the data in any of the represented Regions. * In this example, the generator key * and the additional key are actually the same &KMS; key. * In `generatorId`, this &KMS; key is identified by its alias ARN. * In `keyIds`, this &KMS; key is identified by its key ARN. * In practice, you would specify different &KMS; keys, * or omit the `keyIds` parameter. * This is *only* to demonstrate how the &KMS; key ARNs are configured. */ const keyIds = [ 'arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f', ] /* Need a client provider that will inject correct credentials. * The credentials here are injected by webpack from your environment bundle is created * The credential values are pulled using @aws-sdk/credential-provider-node. * See kms.webpack.config * You should inject your credential into the browser in a secure manner * that works with your application. */ const { accessKeyId, secretAccessKey, sessionToken } = credentials /* getClient takes a KMS client constructor * and optional configuration values. * The credentials can be injected here, * because browsers do not have a standard credential discovery process the way Node.js does. */ const clientProvider = getClient(KMS, { credentials: { accessKeyId, secretAccessKey, sessionToken, }, }) /* You must configure the KMS keyring with your &KMS; keys */ const keyring = new KmsKeyringBrowser({ clientProvider, generatorKeyId, keyIds, }) /* Create a cache to hold the data keys (and related cryptographic material). * This example uses the local cache provided by the Encryption SDK. * The `capacity` value represents the maximum number of entries * that the cache can hold. * To make room for an additional entry, * the cache evicts the oldest cached entry. * Both encrypt and decrypt requests count independently towards this threshold. * Entries that exceed any cache threshold are actively removed from the cache. * By default, the SDK checks one item in the cache every 60 seconds (60,000 milliseconds). * To change this frequency, pass in a `proactiveFrequency` value * as the second parameter. This value is in milliseconds. */ const capacity = 100 const cache = getLocalCryptographicMaterialsCache(capacity) /* The partition name lets multiple caching CMMs share the same local cryptographic cache. * By default, the entries for each CMM are cached separately. However, if you want these CMMs to share the cache, * use the same partition name for both caching CMMs. * If you don't supply a partition name, the Encryption SDK generates a random name for each caching CMM. * As a result, sharing elements in the cache MUST be an intentional operation. */ const partition = 'local partition name' /* maxAge is the time in milliseconds that an entry will be cached. * Elements are actively removed from the cache. */ const maxAge = 1000 * 60 /* The maximum number of bytes that will be encrypted under a single data key. * This value is optional, * but you should configure the lowest practical value. */ const maxBytesEncrypted = 100 /* The maximum number of messages that will be encrypted under a single data key. * This value is optional, * but you should configure the lowest practical value. */ const maxMessagesEncrypted = 10 const cachingCMM = new WebCryptoCachingMaterialsManager({ backingMaterials: keyring, cache, partition, maxAge, maxBytesEncrypted, maxMessagesEncrypted, }) /* Encryption context is a *very* powerful tool for controlling * and managing access. * When you pass an encryption context to the encrypt function, * the encryption context is cryptographically bound to the ciphertext. * If you don't pass in the same encryption context when decrypting, * the decrypt function fails. * The encryption context is ***not*** secret! * Encrypted data is opaque. * You can use an encryption context to assert things about the encrypted data. * The encryption context helps you to determine * whether the ciphertext you retrieved is the ciphertext you expect to decrypt. * For example, if you are are only expecting data from 'us-west-2', * the appearance of a different AWS Region in the encryption context can indicate malicious interference. * See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context * * Also, cached data keys are reused ***only*** when the encryption contexts passed into the functions are an exact case-sensitive match. * See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/data-caching-details.html#caching-encryption-context */ const encryptionContext = { stage: 'demo', purpose: 'simple demonstration app', origin: 'us-west-2', } /* Find data to encrypt. */ const plainText = new Uint8Array([1, 2, 3, 4, 5]) /* Encrypt the data. * The caching CMM only reuses data keys * when it know the length (or an estimate) of the plaintext. * However, in the browser, * you must provide all of the plaintext to the encrypt function. * Therefore, the encrypt function in the browser knows the length of the plaintext * and does not accept a plaintextLength option. */ const { result } = await encrypt(cachingCMM, plainText, { encryptionContext }) /* Log the plain text * only for testing and to show that it works. */ console.log('plainText:', plainText) document.write('</br>plainText:' + plainText + '</br>') /* Log the base64-encoded result * so that you can try decrypting it with another AWS Encryption SDK implementation. */ const resultBase64 = toBase64(result) console.log(resultBase64) document.write(resultBase64) /* Decrypt the data. * NOTE: This decrypt request will not use the data key * that was cached during the encrypt operation. * Data keys for encrypt and decrypt operations are cached separately. */ const { plaintext, messageHeader } = await decrypt(cachingCMM, result) /* Grab the encryption context so you can verify it. */ const { encryptionContext: decryptedContext } = messageHeader /* Verify the encryption context. * If you use an algorithm suite with signing, * the Encryption SDK adds a name-value pair to the encryption context that contains the public key. * Because the encryption context might contain additional key-value pairs, * do not include a test that requires that all key-value pairs match. * Instead, verify that the key-value pairs that you supplied to the `encrypt` function are included in the encryption context that the `decrypt` function returns. */ Object.entries(encryptionContext).forEach(([key, value]) => { if (decryptedContext[key] !== value) throw new Error('Encryption Context does not match expected values') }) /* Log the clear message * only for testing and to show that it works. */ document.write('</br>Decrypted:' + plaintext) console.log(plaintext) /* Return the values to make testing easy. */ return { plainText, plaintext } }
JavaScript Node.js
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { KmsKeyringNode, buildClient, CommitmentPolicy, NodeCachingMaterialsManager, getLocalCryptographicMaterialsCache, } from '@aws-crypto/client-node' /* This builds the client with the REQUIRE_ENCRYPT_REQUIRE_DECRYPT commitment policy, * which enforces that this client only encrypts using committing algorithm suites * and enforces that this client * will only decrypt encrypted messages * that were created with a committing algorithm suite. * This is the default commitment policy * if you build the client with `buildClient()`. */ const { encrypt, decrypt } = buildClient( CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT ) export async function cachingCMMNodeSimpleTest() { /* An &KMS; key is required to generate the data key. * You need kms:GenerateDataKey permission on the &KMS; key in generatorKeyId. */ const generatorKeyId = 'arn:aws:kms:us-west-2:658956600833:alias/EncryptDecrypt' /* Adding alternate &KMS; keys that can decrypt. * Access to kms:Encrypt is required for every &KMS; key in keyIds. * You might list several keys in different AWS Regions. * This allows you to decrypt the data in any of the represented Regions. * In this example, the generator key * and the additional key are actually the same &KMS; key. * In `generatorId`, this &KMS; key is identified by its alias ARN. * In `keyIds`, this &KMS; key is identified by its key ARN. * In practice, you would specify different &KMS; keys, * or omit the `keyIds` parameter. * This is *only* to demonstrate how the &KMS; key ARNs are configured. */ const keyIds = [ 'arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f', ] /* The &KMS; keyring must be configured with the desired &KMS; keys * This example passes the keyring to the caching CMM * instead of using it directly. */ const keyring = new KmsKeyringNode({ generatorKeyId, keyIds }) /* Create a cache to hold the data keys (and related cryptographic material). * This example uses the local cache provided by the Encryption SDK. * The `capacity` value represents the maximum number of entries * that the cache can hold. * To make room for an additional entry, * the cache evicts the oldest cached entry. * Both encrypt and decrypt requests count independently towards this threshold. * Entries that exceed any cache threshold are actively removed from the cache. * By default, the SDK checks one item in the cache every 60 seconds (60,000 milliseconds). * To change this frequency, pass in a `proactiveFrequency` value * as the second parameter. This value is in milliseconds. */ const capacity = 100 const cache = getLocalCryptographicMaterialsCache(capacity) /* The partition name lets multiple caching CMMs share the same local cryptographic cache. * By default, the entries for each CMM are cached separately. However, if you want these CMMs to share the cache, * use the same partition name for both caching CMMs. * If you don't supply a partition name, the Encryption SDK generates a random name for each caching CMM. * As a result, sharing elements in the cache MUST be an intentional operation. */ const partition = 'local partition name' /* maxAge is the time in milliseconds that an entry will be cached. * Elements are actively removed from the cache. */ const maxAge = 1000 * 60 /* The maximum amount of bytes that will be encrypted under a single data key. * This value is optional, * but you should configure the lowest value possible. */ const maxBytesEncrypted = 100 /* The maximum number of messages that will be encrypted under a single data key. * This value is optional, * but you should configure the lowest value possible. */ const maxMessagesEncrypted = 10 const cachingCMM = new NodeCachingMaterialsManager({ backingMaterials: keyring, cache, partition, maxAge, maxBytesEncrypted, maxMessagesEncrypted, }) /* Encryption context is a *very* powerful tool for controlling * and managing access. * When you pass an encryption context to the encrypt function, * the encryption context is cryptographically bound to the ciphertext. * If you don't pass in the same encryption context when decrypting, * the decrypt function fails. * The encryption context is ***not*** secret! * Encrypted data is opaque. * You can use an encryption context to assert things about the encrypted data. * The encryption context helps you to determine * whether the ciphertext you retrieved is the ciphertext you expect to decrypt. * For example, if you are are only expecting data from 'us-west-2', * the appearance of a different AWS Region in the encryption context can indicate malicious interference. * See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context * * Also, cached data keys are reused ***only*** when the encryption contexts passed into the functions are an exact case-sensitive match. * See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/data-caching-details.html#caching-encryption-context */ const encryptionContext = { stage: 'demo', purpose: 'simple demonstration app', origin: 'us-west-2', } /* Find data to encrypt. A simple string. */ const cleartext = 'asdf' /* Encrypt the data. * The caching CMM only reuses data keys * when it know the length (or an estimate) of the plaintext. * If you do not know the length, * because the data is a stream * provide an estimate of the largest expected value. * * If your estimate is smaller than the actual plaintext length * the AWS Encryption SDK will throw an exception. * * If the plaintext is not a stream, * the AWS Encryption SDK uses the actual plaintext length * instead of any length you provide. */ const { result } = await encrypt(cachingCMM, cleartext, { encryptionContext, plaintextLength: 4, }) /* Decrypt the data. * NOTE: This decrypt request will not use the data key * that was cached during the encrypt operation. * Data keys for encrypt and decrypt operations are cached separately. */ const { plaintext, messageHeader } = await decrypt(cachingCMM, result) /* Grab the encryption context so you can verify it. */ const { encryptionContext: decryptedContext } = messageHeader /* Verify the encryption context. * If you use an algorithm suite with signing, * the Encryption SDK adds a name-value pair to the encryption context that contains the public key. * Because the encryption context might contain additional key-value pairs, * do not include a test that requires that all key-value pairs match. * Instead, verify that the key-value pairs that you supplied to the `encrypt` function are included in the encryption context that the `decrypt` function returns. */ Object.entries(encryptionContext).forEach(([key, value]) => { if (decryptedContext[key] !== value) throw new Error('Encryption Context does not match expected values') }) /* Return the values so the code can be tested. */ return { plaintext, result, cleartext, messageHeader } }
Python
# Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You # may not use this file except in compliance with the License. A copy of # the License is located at # # http://aws.amazon.com/apache2.0/ # # or in the "license" file accompanying this file. This file is # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. """Example of encryption with data key caching.""" import aws_encryption_sdk from aws_encryption_sdk import CommitmentPolicy def encrypt_with_caching(kms_key_arn, max_age_in_cache, cache_capacity): """Encrypts a string using an &KMS; key and data key caching. :param str kms_key_arn: Amazon Resource Name (ARN) of the &KMS; key :param float max_age_in_cache: Maximum time in seconds that a cached entry can be used :param int cache_capacity: Maximum number of entries to retain in cache at once """ # Data to be encrypted my_data = "My plaintext data" # Security thresholds # Max messages (or max bytes per) data key are optional MAX_ENTRY_MESSAGES = 100 # Create an encryption context encryption_context = {"purpose": "test"} # Set up an encryption client with an explicit commitment policy. Note that if you do not explicitly choose a # commitment policy, REQUIRE_ENCRYPT_REQUIRE_DECRYPT is used by default. client = aws_encryption_sdk.EncryptionSDKClient(commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT) # Create a master key provider for the &KMS; key key_provider = aws_encryption_sdk.StrictAwsKmsMasterKeyProvider(key_ids=[kms_key_arn]) # Create a local cache cache = aws_encryption_sdk.LocalCryptoMaterialsCache(cache_capacity) # Create a caching CMM caching_cmm = aws_encryption_sdk.CachingCryptoMaterialsManager( master_key_provider=key_provider, cache=cache, max_age=max_age_in_cache, max_messages_encrypted=MAX_ENTRY_MESSAGES, ) # When the call to encrypt data specifies a caching CMM, # the encryption operation uses the data key cache specified # in the caching CMM encrypted_message, _header = client.encrypt( source=my_data, materials_manager=caching_cmm, encryption_context=encryption_context ) return encrypted_message