Simple Key Import
When working with HSMs, you may need to import existing keying material. You can either:
- Import a key pair. For example, because you have a long-term CA private key that you want to migrate from one HSM vendor to another. This allows you to later use the key pair as if it had been generated within the HSM.
- Import a public key. For example, because you want to import a public key to export a key from the HSM using wrapping (for example, for BYOK use cases).
In this tutorial you will learn how to:
- Generate an RSA key pairs locally.
- Format the key pair to prepare it for import.
- Import keys (both public-only and key pairs) into the HSM using the REST API.
For security reasons, generating a fresh private key within the HSM is preferred over importing an existing key. This is because with a fresh key, there is full provenance over where the key has been. When importing an existing key, the HSM cannot guarantee that there are no external copies of the key.
Generate a Key Pair Locally
To create a new RSA key pair locally, use the following command.
This will generate a private key (private_key.pem) with a length of 4096 bits.
openssl genrsa -out private_key.pem 4096
Get the Private Key
To be able to pass the private key to the REST API, it needs to be Base64-encoded (PEM-encoded), with the header/footer and all newline characters removed.
- Linux (Bash)
- Windows (PowerShell)
sed '/-----BEGIN PRIVATE KEY-----/d; /-----END PRIVATE KEY-----/d' private_key.pem | tr -d '\n'
(Get-Content private_key.pem | Where-Object {$_ -notmatch "-----BEGIN PRIVATE KEY-----|-----END PRIVATE KEY-----"} | Out-String).Replace("`n", "").Replace("`r", "")
The output will be a single-line, base64-encoded private key string.
MIIJQQIBADANBgkqhkiG9w0BAQEFAASC...
Get the Public Key
Derive the public key from the private key and save it to a file:
openssl rsa -in private_key.pem -pubout -out public_key.pem
Next, extract and clean the public key, as done for the private key.
- Linux (Bash)
- Windows (PowerShell)
sed '/-----BEGIN PUBLIC KEY-----/d; /-----END PUBLIC KEY-----/d' public_key.pem | tr -d '\n'
(Get-Content public_key.pem | Where-Object {$_ -notmatch "-----BEGIN PUBLIC KEY-----|-----END PUBLIC KEY-----"} | Out-String).Replace("`n", "").Replace("`r", "")
The output will be a single-line, base64-encoded public key string.
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A...
Import the Private & Public Key into the HSM
Use the following API endpoint to import the private and public keys into the HSM.
Replace the the values of privateKey and publicKey with the strings you have created above.
Replace the other values (such as label and the attributes) according to your preferences.
POST: /v1/importedKey
- Import Key Pair
- Import Public Key Only
{
"label": "import_keypair",
"algorithm": "RSA",
"privateKey": "MIIJQQIBADANBgkqhkiG9w0BAQEFAASC...",
"publicKey": "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A...",
"attributes": {
"encrypt": true,
"decrypt": true,
"verify": true,
"sign": true,
"wrap": true,
"unwrap": true,
"derive": false,
"extractable": false,
"modifiable": true,
"destroyable": true,
"sensitive": true,
"copyable": false
},
"policy": null
}
{
"label": "import_public_key",
"algorithm": "RSA",
"publicKey": "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A...",
"attributes": {
"encrypt": true,
"decrypt": true,
"verify": true,
"sign": true,
"wrap": true,
"unwrap": true,
"derive": false,
"extractable": false,
"modifiable": true,
"destroyable": true,
"sensitive": true,
"copyable": false
}
}
If you want to export the key again, make sure that you understand the restrictions that apply. In particular:
- You must set the
"extractable": trueand"sensitive": falseattributes. - If
policyis explicitly set to null, the key will be imported as a normal key. Ifpolicyis not defined, the key will be a non-exportable SKA key with an empty, always fulfillable policy! Therefore, it is recommended to either have a null policy or a fully defined one.
Using the Imported Key
You can now use the imported key for operations inside the HSM. The following examples show how to encrypt a general payload and how to wrap another key with the imported public key.
- Encrypt with Public Key
- Wrap with Public Key
This command encrypts a payload using the public key imported into the HSM. The encrypted output can only be decrypted using the corresponding private key.
POST: /v1/encrypt
{
"encryptRequest": {
"payload": "cGF5bG9hZCB0byBiZSBlbmNyeXB0ZWQ=",
"encryptKeyName": "import_public_key",
"cipherAlgorithm": "RSA_PADDING_OAEP_WITH_SHA512"
}
}
Response:
The response will contain the encryptedPayload, which is the Base64-encoded result of the encryption process.
{
"encryptedPayload": "m7FCNVKIZgN78XQiRUlCZs8OAoSzScYLvm..."
}
Before wrapping, you need to create a symmetric key (e.g., AES) in the HSM. This key will later be encrypted (wrapped) using the previously imported RSA public key.
POST: /v1/key
{
"label": "key_to_be_wrapped",
"algorithm": "AES",
"keySize": 256,
"attributes": {
"encrypt": true,
"decrypt": true,
"verify": true,
"sign": false,
"wrap": true,
"unwrap": true,
"derive": false,
"bip32": false,
"slip10": false,
"extractable": true,
"modifiable": true,
"destroyable": true,
"sensitive": true,
"copyable": true
}
}
Next, use the RSA public key to encrypt (wrap) the AES key. The wrapped key can then be securely transmitted or stored.
POST: /v1/wrap
{
"wrapKeyRequest": {
"keyToBeWrapped": "key_to_be_wrapped",
"wrapKeyName": "import_public_key_4",
"wrapMethod": "RSA_WRAP_OAEP"
}
}
Response:
The response will contain the wrappedKey, which is the encrypted and Base64-encoded AES key.
{
"wrappedKey": "1B0/R3QbhBXCf1O6gyVKIovkAMwtJSVnBD..."
}