Asymmetric data encryption
In this section, you will learn how to use KMS to encrypt and decrypt data using asymmetric encryption.
Getting started
This guide uses OpenSSL
Run this command:
sudo apt-get install openssl
Use the Chocolatey
choco install openssl
Encrypt data
-
If you do not have an encryption key pair, create one.
-
Get a public encryption key and save it:
Management consoleCLIAPI- In the management console
, select the folder with the appropriate key pair. - In the list of services, select Key Management Service.
- In the left-hand panel, select Asymmetric keys.
- Go to the Encryption tab.
- In the row with the appropriate key pair, click
and select Public key. - In the window that opens, click Download to download a public encryption key.
If you do not have the Yandex Cloud command line interface yet, install and initialize it.
The folder specified in the CLI profile is used by default. You can specify a different folder using the
--folder-name
or--folder-id
parameter.-
See the description of the CLI command to get a public encryption key:
yc kms asymmetric-encryption-crypto get-public-key --help
-
Get the ID of the folder where the encryption key pair is saved.
-
Get the ID of the required encryption key pair by specifying the folder ID:
yc kms asymmetric-encryption-key list \ --folder-id <folder_ID>
Result:
+----------------------+-----------------------+---------------------------+---------------------+--------+ | ID | NAME | ENCRYPTION ALGORITHM | CREATED AT | STATUS | +----------------------+-----------------------+---------------------------+---------------------+--------+ | abjfmo5enqlr******** | sample-encryption-key | RSA_2048_ENC_OAEP_SHA_256 | 2023-08-16 18:10:03 | ACTIVE | +----------------------+-----------------------+---------------------------+---------------------+--------+
-
Get a public encryption key by specifying the previously obtained key pair ID:
yc kms asymmetric-encryption-crypto get-public-key \ --id <key_pair_ID>
Result:
key_id: abj9g2dil5sj******** public_key: | -----BEGIN PUBLIC KEY----- MIIB... ...QAB -----END PUBLIC KEY-----
Save this key to a file, e.g.,
public.key
. Make sure that lines in the file do not start with spaces.
To get a public encryption key, use the AsymmetricEncryptionCryptoService/GetPublicKey gRPC API call.
- In the management console
-
Encrypt the message file:
Note
The size of a message to encrypt depends on the length of an encryption key and hash function.
BashJavaGoPythonIn the terminal, run this command:
openssl pkeyutl \ -in <message_file_path> \ -encrypt \ -pubin \ -inkey <public_key_file_path> \ -pkeyopt rsa_padding_mode:oaep \ -pkeyopt rsa_oaep_md:sha256 \ -pkeyopt rsa_mgf1_md:sha256 | base64 > <ciphertext_file_path>
Where:
-in
: Path to the file with the message to encrypt.-inkey
: Path to the file with the public encryption key.<ciphertext_file_path>
: Path to the file the encrypted message will be saved to.
As a result, the encrypted message will be saved to the specified file in the
base64
encoding.import org.bouncycastle.util.io.pem.PemObject; import org.bouncycastle.util.io.pem.PemReader; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import java.io.IOException; import java.io.StringReader; import java.security.*; import java.security.spec.*; import java.util.Base64; public class EncryptRsa { public static void main(String[] args) throws Exception { String plaintext = "<message>"; String publicKeyPem = """ -----BEGIN PUBLIC KEY----- <public_key_contents> -----END PUBLIC KEY-----"""; byte[] cipherTextBytes = encryptWithRsaOaep(plaintext, publicKeyPem); System.out.println(Base64.getEncoder().encodeToString(cipherTextBytes)); } private static byte[] encryptWithRsaOaep(String plaintext, String publicKeyPem) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { // Parsing PEM-encoded public key PemReader pemReader = new PemReader(new StringReader(publicKeyPem)); PemObject pemObject = pemReader.readPemObject(); byte[] publicKeyBytes = pemObject.getContent(); // Creating a PublicKey object from encoded key bytes X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); // Creating a Cipher object for encryption Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); // Text encryption byte[] plaintextBytes = plaintext.getBytes(); // return cipher bytes return cipher.doFinal(plaintextBytes); } }
Where:
<message_text>
: Message text to encrypt.<public_key_contents>
: Contents of the public encryption key.
Encryption is based on the RSA
algorithm usingOAEP
andSHA-256
. The code will return ciphertext as a string inbase64
encoding.import ( "crypto" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "fmt" "log" ) func runRsaEncryption() { plaintext := "<message>" publicKeyPem := `-----BEGIN PUBLIC KEY----- <public_key_contents> -----END PUBLIC KEY-----` ciphertextBytes := encryptRSA(publicKeyPem, plaintext, crypto.SHA256) ciphertextBase64 := base64.StdEncoding.EncodeToString(ciphertextBytes) fmt.Println("Ciphertext:", ciphertextBase64) } func encryptRSA(publicKeyPem string, plaintext string, hash crypto.Hash) []byte { block, _ := pem.Decode([]byte(publicKeyPem)) if block == nil { log.Fatal("failed to decode PEM block containing public key") } pub, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { log.Fatal(err) } publicKey, ok := pub.(*rsa.PublicKey) if !ok { log.Fatal("not RSA public key") } ciphertext, err := rsa.EncryptOAEP(hash.New(), rand.Reader, publicKey, []byte(plaintext), nil) if err != nil { log.Fatal(err) } return ciphertext }
Where:
<message_text>
: Message text to encrypt.<public_key_contents>
: Contents of the public encryption key.
Encryption is based on the RSA
algorithm usingOAEP
andSHA-256
. The code will return ciphertext as a string inbase64
encoding.from cryptography.hazmat.primitives.asymmetric import rsa, padding from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import serialization # Define hash algorithms and corresponding salt lengths def encrypt_with_rsa_oaep(plaintext, public_key_string, hash_algorithm): hash_algorithms = { 'SHA256': hashes.SHA256, 'SHA384': hashes.SHA384, 'SHA512': hashes.SHA512 } # Check if the provided hash algorithm is supported if hash_algorithm not in hash_algorithms: raise ValueError('Unsupported hash algorithm: ' + hash_algorithm) # Loading a PEM Encoded Public Key public_key = serialization.load_pem_public_key( public_key_string.encode() ) # Text encryption ciphertext = public_key.encrypt( plaintext.encode(), padding.OAEP( mgf=padding.MGF1(algorithm=hash_algorithms[hash_algorithm]()), algorithm=hash_algorithms[hash_algorithm](), label=None ) ) # Return ciphertext in Byte array format return ciphertext def test_encrypt_text(): plaintext = "<message>" public_key_string = """ -----BEGIN PUBLIC KEY----- <public_key_contents> -----END PUBLIC KEY-----""" ciphertext = encrypt_with_rsa_oaep(plaintext, public_key_string,'SHA256') ciphertext_base64 = base64.b64encode(ciphertext).decode() print("Ciphertext:", ciphertext_base64)
Where:
<message_text>
: Message text to encrypt.<public_key_contents>
: Contents of the public encryption key.
Encryption is based on the RSA
algorithm usingOAEP
andSHA-256
. The code will return ciphertext as a string inbase64
encoding.
Decrypt data
If you do not have the Yandex Cloud command line interface yet, install and initialize it.
The folder specified in the CLI profile is used by default. You can specify a different folder using the --folder-name
or --folder-id
parameter.
-
See the description of the CLI command to decrypt data with a private encryption key:
yc kms asymmetric-encryption-crypto decrypt --help
-
Get the ID of the folder where the encryption key pair is saved.
-
Get the ID of the required encryption key pair by specifying the folder ID:
yc kms asymmetric-encryption-key list \ --folder-id <folder_ID>
Result:
+----------------------+-----------------------+---------------------------+---------------------+--------+ | ID | NAME | ENCRYPTION ALGORITHM | CREATED AT | STATUS | +----------------------+-----------------------+---------------------------+---------------------+--------+ | abjfmo5enqlr******** | sample-encryption-key | RSA_2048_ENC_OAEP_SHA_256 | 2023-08-16 18:10:03 | ACTIVE | +----------------------+-----------------------+---------------------------+---------------------+--------+
-
Decrypt the ciphertext:
yc kms asymmetric-encryption-crypto decrypt \ --id <key_pair_ID> \ --ciphertext-file <ciphertext_file_path> \ --plaintext-file <path_to_file_with_decrypted_message> \ --inform base64
Where:
--id
: Encryption key pair ID you obtained previously.--ciphertext-file
: Path to the file with thebase64
-encoded ciphertext.--plaintext-file
: Path to the file to save the decrypted message to.
Result:
key_id: abjt22qubivb******** plaintext: 0KHQv...QuSE=
As a result of executing the command, the encrypted message will be decrypted with the private encryption key in KMS and the decrypted text will be saved to the specified file.
To decrypt data, use the AsymmetricEncryptionCryptoService/Decrypt gRPC API call.