public static void main()

in src/main/java/com/example/AwsKmsPqTlsExample.java [60:212]


    public static void main(String[] args) throws Exception {
        /*
         * Check preconditions before continuing. The AWS CRT supports hybrid post-quantum TLS on Linux systems only.
         */
        if (TlsCipherPreference.TLS_CIPHER_PREF_KMS_PQ_TLSv1_0_2020_07.isSupported()) {
            LOG.info(() -> "Hybrid post-quantum ciphers are supported and will be used");
        } else {
            throw new UnsupportedOperationException("Hybrid post-quantum cipher suites are supported only on Linux systems");
        }

        /*
         * Set up a PQ TLS HTTP client that will be used in the rest of the example.
         */
        SdkAsyncHttpClient awsCrtHttpClient = AwsCrtAsyncHttpClient.builder()
                .tlsCipherPreference(TlsCipherPreference.TLS_CIPHER_PREF_KMS_PQ_TLSv1_0_2020_07)
                .build();
        /*
         * Set up a Java SDK 2.0 KMS Client which will use hybrid post-quantum TLS for all connections to KMS.
         */
        KmsAsyncClient asyncKMSClient = KmsAsyncClient.builder()
                .httpClient(awsCrtHttpClient)
                .build();


        /*
         * Import key material workflow with hybrid post-quantum TLS
         *
         * Step 1: Create an external CMK with no key material
         */
        CreateKeyRequest createRequest = CreateKeyRequest.builder()
                .origin(OriginType.EXTERNAL)
                .description("Test key for aws-kms-pq-tls-example. Feel free to delete this.")
                .build();
        CreateKeyResponse createResponse = asyncKMSClient.createKey(createRequest).get();
        String keyId = createResponse.keyMetadata().keyId();
        LOG.info(() -> "Created CMK " + keyId);

        /*
         * Step 2: Get the wrapping key and token required to import the local key material. The AlgorithmSpec determines
         * how we must wrap the local key material using the public key from KMS.
         */
        GetParametersForImportRequest getParametersRequest = GetParametersForImportRequest.builder()
                .keyId(keyId)
                .wrappingAlgorithm(AlgorithmSpec.RSAES_OAEP_SHA_1)
                .wrappingKeySpec(WrappingKeySpec.RSA_2048)
                .build();
        GetParametersForImportResponse getParametersResponse =
                asyncKMSClient.getParametersForImport(getParametersRequest).get();

        /*
         * Step 3: Prepare the parameters for the ImportKeyMaterial call.
         */
        SdkBytes importToken = getParametersResponse.importToken();
        byte[] publicKeyBytes = getParametersResponse.publicKey().asByteArray();

        /*
         * Create an ephemeral AES key. You should never do this in production. With KMS ImportKeyMaterial, you are
         * responsible for keeping a durable copy of the key.
         * https://docs.aws.amazon.com/kms/latest/developerguide/importing-keys.html
         *
         * The plaintextAesKey exists only for the lifetime of this function. This example key material will expire from
         * KMS in 10 minutes. This is the 'validTo(Instant.now().plusSeconds(600))' in the ImportKeyMaterial call below.
         */
        byte[] plaintextAesKey = new byte[AES_KEY_SIZE_BYTES];
        SECURE_RANDOM.nextBytes(plaintextAesKey);

        /*
         * Use the wrapping key to encrypt the local key material. Then use the token to import the wrapped key
         * material into KMS.
         *
         * This RSA wrapped key material is protected in transit with PQ TLS. If you use classic TLS, a large-scale
         * quantum computer would be able to decrypt the TLS session data and recover the RSA-wrapped key material. Then
         * it could decrypt the RSA-wrapped key to recover your plaintext AES key.
         */
        RSAPublicKey rsaPublicKey = RSAUtils.decodeX509PublicKey(publicKeyBytes);
        byte[] encryptedAesKey = RSAUtils.encryptRSA(rsaPublicKey, plaintextAesKey);

        /*
         * Step 4: Import the key material using the CMK ID, wrapped key material, and import token. This is the
         * important call to protect. Your AES key is leaving your computer and traveling over the network wrapped by an
         * RSA public key and encrypted with PQ TLS.
         *
         * This AES key will be used for all KMS cryptographic operations when you use this CMK. If this key is
         * compromised, all ciphertexts that use this CMK are also compromised.
         */
        ImportKeyMaterialRequest importRequest = ImportKeyMaterialRequest.builder()
                .keyId(keyId)
                .encryptedKeyMaterial(SdkBytes.fromByteArray(encryptedAesKey))
                .importToken(importToken)
                .expirationModel(ExpirationModelType.KEY_MATERIAL_EXPIRES)
                .validTo(Instant.now().plusSeconds(600))
                .build();
        LOG.info(() -> String.format("Importing key material into CMK %s. Using PQ TLS to protect RSA-wrapped AES key " +
                "in transit", keyId));
        asyncKMSClient.importKeyMaterial(importRequest).get();

        /*
         * Sensitive cryptographic operations workflow. Use a KMS CMK to encrypt and decrypt data. The CMK can have any
         * origin (AWS_KMS, EXTERNAL, or AWS_CLOUDHSM). This example reuses the CMK with imported key material that we
         * created in the previous step.
         *
         * Step 1: Generate a data key. KMS GenerateDataKey returns the plaintext data key and a copy of that data key
         * encrypted under the CMK using AES-GCM with 256-bit keys. It is your responsibility to keep the ciphertext so
         * the plaintext data key can be decrypted in the future.
         */
        GenerateDataKeyRequest generateDataKeyRequest = GenerateDataKeyRequest.builder()
                .keyId(keyId)
                .keySpec(DataKeySpec.AES_256)
                .build();
        LOG.info(() -> String.format("Generating a data key. Using PQ TLS to protect the plaintext data key in transit. " +
                "The encrypted data key is encrypted under the CMK %s", keyId));
        GenerateDataKeyResponse generateDataKeyResponse = asyncKMSClient.generateDataKey(generateDataKeyRequest).get();

        /*
         * Step 2: Use the plaintext data key for client-side encryption. You can get the plaintext data key by calling
         * generateDataKeyResponse.plaintext(). This step is omitted and will depend on your use case.
         */

        /*
         * Step 3: Decrypt the encrypted data key.
         */
        SdkBytes encryptedDataKey = generateDataKeyResponse.ciphertextBlob();
        DecryptRequest decryptRequest = DecryptRequest.builder()
                .ciphertextBlob(encryptedDataKey)
                .build();
        LOG.info(() -> "Decrypting a KMS ciphertext. Using PQ TLS to protect the plaintext data in transit");
        DecryptResponse decryptResponse = asyncKMSClient.decrypt(decryptRequest).get();

        /*
         * Step 4: Use the plaintext data key to decrypt your client-side data. You can get the plaintext data key by
         * calling decryptResponse.plaintext(). This step is omitted and will depend on your use case.
         */

        /*
         * Clean up resources from this demo.
         *
         * Schedule deletion of the CMK that contains imported key material. Because this CMK was created only for this
         * test, we will delete it as part of cleanup. After the CMK is deleted, any ciphertexts encrypted under
         * this CMK are permanently unrecoverable.
         */
        ScheduleKeyDeletionRequest deletionRequest = ScheduleKeyDeletionRequest.builder()
                .keyId(keyId)
                .pendingWindowInDays(7)
                .build();
        ScheduleKeyDeletionResponse deletionResult = asyncKMSClient.scheduleKeyDeletion(deletionRequest).get();
        LOG.info(() -> String.format("CMK %s is schedule to be deleted at %s", keyId, deletionResult.deletionDate()));

        /*
         * Shut down the SDK and HTTP client. This will free any Java and native resources created for the demo.
         */
        asyncKMSClient.close();
        awsCrtHttpClient.close();
    }