

# Perform offline operations with public keys
<a name="offline-public-key"></a>

In an asymmetric KMS key, the private key is created in AWS KMS and never leaves AWS KMS unencrypted. To use the private key, you must call AWS KMS. You can use the public key within AWS KMS by calling the AWS KMS API operations. Or, you can [download the public key](download-public-key.md) and share for use outside of AWS KMS.

You might share a public key to let others encrypt data outside of AWS KMS that you can decrypt only with your private key. Or, to allow others to verify a digital signature outside of AWS KMS that you have generated with your private key. Or, to share your public key with a peer to derive a shared secret.

When you use the public key in your asymmetric KMS key within AWS KMS, you benefit from the authentication, authorization, and logging that are part of every AWS KMS operation. You also reduce of risk of encrypting data that cannot be decrypted. These features are not effective outside of AWS KMS. For details, see [Special considerations for downloading public keys](#download-public-key-considerations).

**Tip**  
Looking for data keys or SSH keys? This topic explains how to manage asymmetric keys in AWS Key Management Service, where the private key is not exportable. For exportable data key pairs where the private key is protected by a symmetric encryption KMS key, see [GenerateDataKeyPair](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKeyPair.html). For help with downloading the public key associated with an Amazon EC2 instance, see *Retrieving the public key* in the [Amazon EC2 User Guide](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/describe-keys.html#retrieving-the-public-key) and [Amazon EC2 User Guide](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/describe-keys.html#retrieving-the-public-key).

**Topics**
+ [Special considerations for downloading public keys](#download-public-key-considerations)
+ [Download public key](download-public-key.md)
+ [Example offline operations](offline-operations.md)

## Special considerations for downloading public keys
<a name="download-public-key-considerations"></a>

To protect your KMS keys, AWS KMS provides access controls, authenticated encryption, and detailed logs of every operation. AWS KMS also allows you to prevent the use of KMS keys, temporarily or permanently. Finally, AWS KMS operations are designed to minimize of risk of encrypting data that cannot be decrypted. These features are not available when you use downloaded public keys outside of AWS KMS. 

**Authorization**  
[Key policies](key-policies.md) and [IAM policies](iam-policies.md) that control access to the KMS key within AWS KMS have no effect on operations performed outside of AWS. Any user who can get the public key can use it outside of AWS KMS even if they don't have permission to encrypt data or verify signatures with the KMS key.

**Key usage restrictions**  
Key usage restrictions are not effective outside of AWS KMS. If you call the [Encrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Encrypt.html) operation with a KMS key that has a `KeyUsage` of `SIGN_VERIFY`, the AWS KMS operation fails. But if you encrypt data outside of AWS KMS with a public key from a KMS key with a `KeyUsage` of `SIGN_VERIFY` or `KEY_AGREEMENT`, the data cannot be decrypted.

**Algorithm restrictions**  
Restrictions on the encryption and signing algorithms that AWS KMS supports are not effective outside of AWS KMS. If you encrypt data with the public key from a KMS key outside of AWS KMS, and use an encryption algorithm that AWS KMS does not support, the data cannot be decrypted. 

**Disabling and deleting KMS keys**  
Actions that you can take to prevent the use of KMS key in a cryptographic operation within AWS KMS do not prevent anyone from using the public key outside of AWS KMS. For example, disabling a KMS key, scheduling deletion of a KMS key, deleting a KMS key, or deleting the key material from a KMS key have no effect on a public key outside of AWS KMS. If you delete an asymmetric KMS key or delete or lose its key material, data that you encrypt with a public key outside of AWS KMS is unrecoverable.

**Logging**  
AWS CloudTrail logs that record every AWS KMS operation, including the request, response, date, time, and authorized user, do not record the use of the public key outside of AWS KMS.

**Offline verification with SM2 key pairs (China Regions only)**  
To verify a signature outside of AWS KMS with an SM2 public key, you must specify the distinguishing ID. By default, AWS KMS uses `1234567812345678` as the distinguishing ID. For more information, see [Offline verification with SM2 key pairs (China Regions only).](offline-operations.md#key-spec-sm-offline-verification)

# Download public key
<a name="download-public-key"></a>

You can download the public key from an asymmetric KMS key pair in the AWS KMS console or by using the [GetPublicKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GetPublicKey.html) operation. To download the public key, you must have `kms:GetPublicKey` permission on the asymmetric KMS key.

The public key that AWS KMS returns is a DER-encoded X.509 public key, also known as `SubjectPublicKeyInfo` (SPKI), as defined in [RFC 5280](https://datatracker.ietf.org/doc/html/rfc5280). When you use the HTTP API or the AWS CLI, the value is Base64-encoded. Otherwise, it is not Base64-encoded.

To download the public key from an asymmetric KMS key pair, you need `kms:GetPublicKey` permissions. For more information about AWS KMS permissions, see the [Permissions reference](kms-api-permissions-reference.md).

## Using the AWS KMS console
<a name="download-public-key-console"></a>

You can use the AWS Management Console to view, copy, and download the public key from an asymmetric KMS key in your AWS account. To download the public key from an asymmetric KMS key in different AWS account, use the AWS KMS API.

1. Sign in to the AWS Management Console and open the AWS Key Management Service (AWS KMS) console at [https://console.aws.amazon.com/kms](https://console.aws.amazon.com/kms).

1. To change the AWS Region, use the Region selector in the upper-right corner of the page.

1. In the navigation pane, choose **Customer managed keys**.

1. Choose the alias or key ID of an asymmetric KMS key.

1. Choose the **Cryptographic configuration** tab. Record the values of the **Key spec**, **Key usage**, and **Encryption algorithms** or **Signing Algorithms** fields. You'll need to use these values to use the public key outside of AWS KMS. Be sure to share this information when you share the public key.

1. Choose the **Public key** tab.

1. To copy the public key to your clipboard, choose **Copy**. To download the public key to a file, choose **Download**.

## Using the AWS KMS API
<a name="download-public-key-api"></a>

The [GetPublicKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GetPublicKey.html) operation returns the public key in an asymmetric KMS key. It also returns critical information that you need to use the public key correctly outside of AWS KMS, including the key usage and encryption algorithms. Be sure to save these values and share them whenever you share the public key.

The examples in this section use the [AWS Command Line Interface (AWS CLI)](https://aws.amazon.com/cli/), but you can use any supported programming language. 

To specify a KMS key, use its [key ID](concepts.md#key-id-key-id), [key ARN](concepts.md#key-id-key-ARN), [alias name](concepts.md#key-id-alias-name), or [alias ARN](concepts.md#key-id-alias-ARN). When using an alias name, prefix it with **alias/**. To specify a KMS key in a different AWS account, you must use its key ARN or alias ARN.

Before running this command, replace the example alias name with a valid identifier for the KMS key. To run this command, you must have `kms:GetPublicKey` permissions on the KMS key.

```
$ aws kms get-public-key --key-id alias/example_RSA_3072

{
    "KeySpec": "RSA_3072",
    "KeyId": "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab",
    "KeyUsage": "ENCRYPT_DECRYPT",
    "EncryptionAlgorithms": [
        "RSAES_OAEP_SHA_1",
        "RSAES_OAEP_SHA_256"
    ],
    "PublicKey": "MIIBojANBgkqhkiG..."
}
```

# Example offline operations
<a name="offline-operations"></a>

After [downloading the public key](download-public-key.md) of your asymmetric KMS key pair, you can share it with others and use it to perform offline operations.

AWS CloudTrail logs that record every AWS KMS operation, including the request, response, date, time, and authorized user, do not record the use of the public key outside of AWS KMS.

This topic provides example offline operations and details the tools AWS KMS provides to make offline operations easier.

**Topics**
+ [Deriving shared secrets offline](#key-spec-ecc-offline)
+ [Offline verification with ML-DSA key pairs](#mldsa-offline-verification)
+ [Offline verification with SM2 key pairs (China Regions only)](#key-spec-sm-offline-verification)

## Deriving shared secrets offline
<a name="key-spec-ecc-offline"></a>

You can [download the public key](download-public-key.md) of your ECC key pair for use in offline operations, that is, operations outside of AWS KMS.

The following [OpenSSL](https://openssl.org/) walkthrough demonstrates one method of deriving a shared secret outside of AWS KMS using the public key of an ECC KMS key pair and a private key created with OpenSSL.

1. Create an ECC key pair in OpenSSL and prepare it for use with AWS KMS.

   ```
   // Create an ECC key pair in OpenSSL and save the private key in openssl_ecc_key_priv.pem
   export OPENSSL_CURVE_NAME="P-256"
   export KMS_CURVE_NAME="ECC_NIST_P256"
   
   export OPENSSL_KEY1_PRIV_PEM="openssl_ecc_key1_priv.pem"
   openssl ecparam -name ${OPENSSL_CURVE_NAME} -genkey -out ${OPENSSL_KEY1_PRIV_PEM}                    
                       
   // Derive the public key from the private key                    
   export OPENSSL_KEY1_PUB_PEM="openssl_ecc_key1_pub.pem"
   openssl ec -in ${OPENSSL_KEY1_PRIV_PEM} -pubout -outform pem \
       -out ${OPENSSL_KEY1_PUB_PEM}                    
                       
   // View the PEM file containing the public key and extract the public key as a 
   // Base64 encoded string into OPENSSL_KEY1_PUB_BASE64 for use with AWS KMS
   export OPENSSL_KEY1_PUB_BASE64=`cat ${OPENSSL_KEY1_PUB_PEM} | \
       tee /dev/stderr | grep -v "PUBLIC KEY" | tr -d "\n"`
   ```

1. Create an ECC key agreement key pair in AWS KMS and prepare it for use with OpenSSL.

   ```
   // Create a KMS key on the same curve as the key pair from step 1 
   // with a key usage of KEY_AGREEMENT
   // Save its ARN in KMS_KEY1_ARN.
   export KMS_KEY1_ARN=`aws kms create-key --key-spec ${KMS_CURVE_NAME} \
       --key-usage KEY_AGREEMENT | tee /dev/stderr | jq -r .KeyMetadata.Arn`
   
   // Download the public key and save the Base64-encoded version in KMS_KEY1_PUB_BASE64        
   export KMS_KEY1_PUB_BASE64=`aws kms get-public-key --key-id ${KMS_KEY1_ARN} | \
       tee /dev/stderr | jq -r .PublicKey`                    
                       
   // Create a PEM file for the public KMS key for use with OpenSSL   
   export KMS_KEY1_PUB_PEM="aws_kms_ecdh_key1_pub.pem"
   echo "-----BEGIN PUBLIC KEY-----" > ${KMS_KEY1_PUB_PEM}
   echo ${KMS_KEY1_PUB_BASE64} | fold -w 64 >> ${KMS_KEY1_PUB_PEM}
   echo "-----END PUBLIC KEY-----" >> ${KMS_KEY1_PUB_PEM}
   ```

1. Derive shared secret in OpenSSL using the private key in OpenSSL and the public KMS key.

   ```
   export OPENSSL_SHARED_SECRET1_BIN="openssl_shared_secret1.bin"
   openssl pkeyutl -derive -inkey ${OPENSSL_KEY1_PRIV_PEM} \
       -peerkey ${KMS_KEY1_PUB_PEM} -out ${OPENSSL_SHARED_SECRET1_BIN}
   ```

## Offline verification with ML-DSA key pairs
<a name="mldsa-offline-verification"></a>

AWS KMS supports a hedged variant of ML-DSA signing, as described in [Federal Information Processing Standards (FIPS) 204 standard](https://csrc.nist.gov/pubs/fips/204/final) section 3.4 for messages up to 4 KB bytes.

To sign messages larger than 4 KB, you perform the message pre-processing step outside of AWS KMS. This hashing step creates a 64-byte message representative μ, as defined in NIST FIPS 204, section 6.2.

AWS KMS has a message type called `EXTERNAL_MU` for messages larger than 4 KB. When you use this instead of the `RAW` message type, AWS KMS:
+ Assumes you've already performed the hashing step
+ Skips its internal hashing process
+ Works with messages of any size

When you verify a message, the method that you use depends on the size restriction of the external system or library and whether it supports the 64-byte message representative μ:
+ If the message is smaller than the size restriction, use the `RAW` message type.
+ If the message is larger than the size restriction, use the representative μ in the external system.

The following sections demonstrate how to sign messages using AWS KMS and verify messages using OpenSSL. We provide examples for both messages under and over the 4 KB message size limit imposed by AWS KMS. OpenSSL doesn't impose a limit on message size for verification.

For both examples, first get the public key from AWS KMS. Use the following AWS CLI command:

```
aws kms get-public-key \
    --key-id _<1234abcd-12ab-34cd-56ef-1234567890ab>_ \
    --output text \
    --query PublicKey | base64 --decode > public_key.der
```

### Message size less than 4KB
<a name="mldsa-offline-verification-less-than-4KB"></a>

For messages under 4 KB, use the `RAW` message type with AWS KMS. While you can use `EXTERNAL_MU`, it isn't necessary for messages within the size limit.

Use the following AWS CLI command to sign the message:

```
aws kms sign \
    --key-id _<1234abcd-12ab-34cd-56ef-1234567890ab>_ \
    --message 'your message' \
    --message-type RAW \
    --signing-algorithm ML_DSA_SHAKE_256 \
    --output text \
    --query Signature | base64 --decode > ExampleSignature.bin
```

To verify this message using OpenSSL use the following command:

```
echo -n 'your message' | ./openssl dgst -verify public_key.der -signature ExampleSignature.bin
```

### Message size more than 4KB
<a name="mldsa-offline-verification-more-than-4KB"></a>

To sign messages larger than 4KB, use the `EXTERNAL_MU` message type. When you use `EXTERNAL_MU`, you pre-hash the message externally to a 64-byte representative μ as defined in NIST FIPS 204 section 6.2 and pass it to the signing or verifying operations. Note that this is different from the "Pre-hash MLDSA" or HashML-DSA defined in NIST FIPS 204 section 5.4. 

1. First, construct a message prefix. The prefix contains a domain separator, the length of any context, and the context. The default for the domain separator and context length is zero.

1. Prepend the message prefix to the message.

1. Use SHAKE256 to hash the public key and prepend it to the result of step 2.

1. Finally, hash the result of step 3 to produce a 64-byte `EXTERNAL_MU`.

The following example uses OpenSSL 3.5 to construct the `EXTERNAL_MU`:

```
{
    openssl asn1parse -inform DER -in public_key.der -strparse 17 -noout -out - 2>/dev/null |
    openssl dgst -provider default -shake256 -xoflen 64 -binary;
    printf '\x00\x00';
    echo -n "your message"
} | openssl dgst -provider default -shake256 -xoflen 64 -binary > mu.bin
```

After you create the `mu.bin` file, call the AWS KMS API with the following command to sign the message:

```
aws kms sign \
    --key-id _<1234abcd-12ab-34cd-56ef-1234567890ab>_ \
    --message fileb://mu.bin \
    --message-type EXTERNAL_MU \
    --signing-algorithm ML_DSA_SHAKE_256 \
    --output text \
    --query Signature | base64 --decode > ExampleSignature.bin
```

The resulting signature is the same as a `RAW` signature on the original message. You can use the same OpenSSL 3.5 command to verify the message:

```
echo -n 'your message' | ./openssl dgst -verify public_key.der -signature ExampleSignature.bin
```

## Offline verification with SM2 key pairs (China Regions only)
<a name="key-spec-sm-offline-verification"></a>

To verify a signature outside of AWS KMS with an SM2 public key, you must specify the distinguishing ID. When you pass a raw message, [https://docs.aws.amazon.com/kms/latest/APIReference/API_Sign.html#KMS-Sign-request-MessageType](https://docs.aws.amazon.com/kms/latest/APIReference/API_Sign.html#KMS-Sign-request-MessageType), to the [Sign](https://docs.aws.amazon.com/kms/latest/APIReference/API_Sign.html) API, AWS KMS uses the default distinguishing ID, `1234567812345678`, defined by OSCCA in GM/T 0009-2012. You cannot specify your own distinguishing ID within AWS KMS.

However, if you are generating a message digest outside of AWS, you can specify your own distinguishing ID, then pass the message digest, [https://docs.aws.amazon.com/kms/latest/APIReference/API_Sign.html#API_Sign_RequestSyntax](https://docs.aws.amazon.com/kms/latest/APIReference/API_Sign.html#API_Sign_RequestSyntax), to AWS KMS to sign. To do this, change the `DEFAULT_DISTINGUISHING_ID` value in the `SM2OfflineOperationHelper` class. The distinguishing ID you specify can be any string up to 8,192 characters long. After AWS KMS signs the message digest, you need either the message digest or the message and the distinguishing ID used to compute the digest to verify it offline.

**Important**  
The `SM2OfflineOperationHelper` reference code is designed to be compatible with [Bouncy Castle](https://www.bouncycastle.org/documentation/documentation-java/) version 1.68. For help with other versions, contact [bouncycastle.org](https://www.bouncycastle.org).

### `SM2OfflineOperationHelper` class
<a name="key-spec-sm-offline-helper"></a>

To help you with offline operations with SM2 keys, the `SM2OfflineOperationHelper` class for Java has methods that perform the tasks for you. You can use this helper class as a model for other cryptographic providers.

Within AWS KMS, the raw ciphertext conversions and SM2DSA message digest calculations occur automatically. Not all cryptographic providers implement SM2 in the same way. Some libraries, like [OpenSSL](https://openssl.org/) versions 1.1.1 and later, perform these actions automatically. AWS KMS confirmed this behavior in testing with OpenSSL version 3.0. Use the following `SM2OfflineOperationHelper` class with libraries, like [Bouncy Castle](https://www.bouncycastle.org/java.html), that require you to perform these conversions and calculations manually.

The `SM2OfflineOperationHelper` class provides methods for the following offline operations:
+   
**Message digest calculation**  
To generate a message digest offline that you can use for offline verification, or that you can pass to AWS KMS to sign, use the `calculateSM2Digest` method. The `calculateSM2Digest` method generates a message digest with the SM3 hashing algorithm. The [GetPublicKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GetPublicKey.html) API returns your public key in binary format. You must parse the binary key into a Java PublicKey. Provide the parsed public key with the message. The method automatically combines your message with the default distinguishing ID, `1234567812345678`, but you can set your own distinguishing ID by changing the `DEFAULT_DISTINGUISHING_ID` value.
+   
**Verify**  
To verify a signature offline, use the `offlineSM2DSAVerify` method. The `offlineSM2DSAVerify` method uses the message digest calculated from the specified distinguishing ID, and original message you provide to verify the digital signature. The [GetPublicKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GetPublicKey.html) API returns your public key in binary format. You must parse the binary key into a Java PublicKey. Provide the parsed public key with the original message and the signature you want to verify. For more details, see [ Offline verification with SM2 key pairs](#key-spec-sm-offline-verification).
+   
**Encrypt**  
To encrypt plaintext offline, use the `offlineSM2PKEEncrypt` method. This method ensures the ciphertext is in a format AWS KMS can decrypt. The `offlineSM2PKEEncrypt` method encrypts the plaintext, and then converts the raw ciphertext produced by SM2PKE to the ASN.1 format. The [GetPublicKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GetPublicKey.html) API returns your public key in binary format. You must parse the binary key into a Java PublicKey. Provide the parsed public key with the plaintext that you want to encrypt.  
If you're unsure whether you need to perform the conversion, use the following OpenSSL operation to test the format of your ciphertext. If the operation fails, you need to convert the ciphertext to the ASN.1 format.  

  ```
  openssl asn1parse -inform DER -in ciphertext.der
  ```

By default, the `SM2OfflineOperationHelper` class uses the default distinguishing ID, `1234567812345678`, when generating message digests for SM2DSA operations.

```
package com.amazon.kms.utils;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;

import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.jce.interfaces.ECPublicKey;

import java.util.Arrays;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.params.ParametersWithID;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;

public class SM2OfflineOperationHelper {
    // You can change the DEFAULT_DISTINGUISHING_ID value to set your own distinguishing ID,
    // the DEFAULT_DISTINGUISHING_ID can be any string up to 8,192 characters long.
    private static final byte[] DEFAULT_DISTINGUISHING_ID = "1234567812345678".getBytes(StandardCharsets.UTF_8);
    private static final X9ECParameters SM2_X9EC_PARAMETERS = GMNamedCurves.getByName("sm2p256v1");

    // ***calculateSM2Digest***
    // Calculate message digest
    public static byte[] calculateSM2Digest(final PublicKey publicKey, final byte[] message) throws
            NoSuchProviderException, NoSuchAlgorithmException {
        final ECPublicKey ecPublicKey = (ECPublicKey) publicKey;

        // Generate SM3 hash of default distinguishing ID, 1234567812345678
        final int entlenA = DEFAULT_DISTINGUISHING_ID.length * 8;
        final byte [] entla = new byte[] { (byte) (entlenA & 0xFF00), (byte) (entlenA & 0x00FF) };
        final byte [] a = SM2_X9EC_PARAMETERS.getCurve().getA().getEncoded();
        final byte [] b = SM2_X9EC_PARAMETERS.getCurve().getB().getEncoded();
        final byte [] xg = SM2_X9EC_PARAMETERS.getG().getXCoord().getEncoded();
        final byte [] yg = SM2_X9EC_PARAMETERS.getG().getYCoord().getEncoded();
        final byte[] xa = ecPublicKey.getQ().getXCoord().getEncoded();
        final byte[] ya = ecPublicKey.getQ().getYCoord().getEncoded();
        final byte[] za = MessageDigest.getInstance("SM3", "BC")
                .digest(ByteBuffer.allocate(entla.length + DEFAULT_DISTINGUISHING_ID.length + a.length + b.length + xg.length + yg.length +
                        xa.length + ya.length).put(entla).put(DEFAULT_DISTINGUISHING_ID).put(a).put(b).put(xg).put(yg).put(xa).put(ya)
                        .array());

        // Combine hashed distinguishing ID with original message to generate final digest
        return MessageDigest.getInstance("SM3", "BC")
                .digest(ByteBuffer.allocate(za.length + message.length).put(za).put(message)
                        .array());
    }

    // ***offlineSM2DSAVerify***
    // Verify digital signature with SM2 public key
    public static boolean offlineSM2DSAVerify(final PublicKey publicKey, final byte [] message,
            final byte [] signature) throws InvalidKeyException {
        final SM2Signer signer = new SM2Signer();
        CipherParameters cipherParameters = ECUtil.generatePublicKeyParameter(publicKey);
        cipherParameters = new ParametersWithID(cipherParameters, DEFAULT_DISTINGUISHING_ID);
        signer.init(false, cipherParameters);
        signer.update(message, 0, message.length);
        return signer.verifySignature(signature);
    }

    // ***offlineSM2PKEEncrypt***
    // Encrypt data with SM2 public key
    public static byte[] offlineSM2PKEEncrypt(final PublicKey publicKey, final byte [] plaintext) throws
            NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException,
            BadPaddingException, IllegalBlockSizeException, IOException {
        final Cipher sm2Cipher = Cipher.getInstance("SM2", "BC");
        sm2Cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        // By default, Bouncy Castle returns raw ciphertext in the c1c2c3 format
        final byte [] cipherText = sm2Cipher.doFinal(plaintext);

        // Convert the raw ciphertext to the ASN.1 format before passing it to AWS KMS
        final ASN1EncodableVector asn1EncodableVector = new ASN1EncodableVector();
        final int coordinateLength = (SM2_X9EC_PARAMETERS.getCurve().getFieldSize() + 7) / 8 * 2 + 1;
        final int sm3HashLength = 32;
        final int xCoordinateInCipherText = 33;
        final int yCoordinateInCipherText = 65;
        byte[] coords = new byte[coordinateLength];
        byte[] sm3Hash = new byte[sm3HashLength];
        byte[] remainingCipherText = new byte[cipherText.length - coordinateLength - sm3HashLength];

        // Split components out of the ciphertext
        System.arraycopy(cipherText, 0, coords, 0, coordinateLength);
        System.arraycopy(cipherText, cipherText.length - sm3HashLength, sm3Hash, 0, sm3HashLength);
        System.arraycopy(cipherText, coordinateLength, remainingCipherText, 0,cipherText.length - coordinateLength - sm3HashLength);

        // Build standard SM2PKE ASN.1 ciphertext vector
        asn1EncodableVector.add(new ASN1Integer(new BigInteger(1, Arrays.copyOfRange(coords, 1, xCoordinateInCipherText))));
        asn1EncodableVector.add(new ASN1Integer(new BigInteger(1, Arrays.copyOfRange(coords, xCoordinateInCipherText, yCoordinateInCipherText))));
        asn1EncodableVector.add(new DEROctetString(sm3Hash));
        asn1EncodableVector.add(new DEROctetString(remainingCipherText));

        return new DERSequence(asn1EncodableVector).getEncoded("DER");
    }
}
```