비대칭 키로 데이터 암호화 및 복호화

이 주제에서는 RSA 키를 사용하여 비대칭 암호화를 위한 키를 만들고 사용하는 방법에 대한 정보를 제공합니다. 비대칭 키를 사용하여 서명을 만들고 검증하려면 디지털 서명 만들기 및 검증을 참조하세요. 암호화 및 복호화에 대칭 키를 사용하려면 데이터 암호화 및 복호화를 참조하세요.

비대칭 암호화는 비대칭 키의 공개 키 부분을 사용하고, 복호화는 키의 비공개 키 부분을 사용합니다. Cloud Key Management Service는 공개 키를 검색할 수 있는 기능과 공개 키로 암호화된 암호문을 복호화할 수 있는 기능을 제공합니다. Cloud KMS에서는 비공개 키에 직접 액세스할 수 없습니다.

시작하기 전에

  • 이 주제에서는 명령줄에서 실행되는 예를 제공합니다. 예시를 간단히 사용하려면 Cloud Shell을 사용하세요. 암호화 예시는 Cloud Shell에 사전 설치된 OpenSSL을 사용합니다.

  • 키 용도ASYMMETRIC_DECRYPT비대칭 키를 만듭니다. 키 용도 ASYMMETRIC_DECRYPT를 지원하는 알고리즘을 확인하려면 비대칭 암호화 알고리즘을 참조하세요. 이 절차는 ASYMMETRIC_SIGN 용도의 키로 수행할 수 없습니다.

  • 명령줄을 사용하려고 하지만 OpenSSL을 아직 설치하지 않았으면 설치합니다. Cloud Shell을 사용하는 경우에는 OpenSSL이 이미 설치되어 있습니다.

  • macOS 사용자: macOS에 설치된 OpenSSL 버전은 이 주제에서 데이터를 복호화하는 데 사용되는 플래그를 지원하지 않습니다. macOS에서 이 단계를 수행하려면 Homebrew에서 OpenSSL을 설치하세요.

키 액세스 제어

  • 공개 키를 검색할 사용자 또는 서비스에 비대칭 키에 대한 cloudkms.cryptoKeyVersions.viewPublicKey 권한을 부여합니다. 데이터를 암호화하는 데 공개 키가 필요합니다.

  • 공개 키로 암호화된 데이터를 복호화할 사용자나 서비스에 비대칭 키에 대한 cloudkms.cryptoKeyVersions.useToDecrypt 권한을 부여합니다.

권한 및 역할에서 Cloud KMS의 권한과 역할을 알아보세요.

데이터 암호화

비대칭 암호화 키를 사용하여 데이터를 암호화하려면 공개 키를 검색하고 이 공개 키를 사용해서 데이터를 암호화합니다.

gcloud

이 샘플은 로컬 시스템에 OpenSSL이 설치되어 있어야 합니다.

공개 키 다운로드

공개 키를 다운로드합니다.

gcloud kms keys versions get-public-key key-version \
    --key key \
    --keyring key-ring \
    --location location  \
    --output-file public-key-path

key-version을 공개 키가 있는 키 버전으로 바꿉니다. key를 키 이름으로 바꿉니다. key-ring을 키가 배치된 키링의 이름으로 바꿉니다. location을 키링의 Cloud KMS 위치로 바꿉니다. public-key-path를 로컬 시스템에 공개 키를 저장할 위치로 바꿉니다.

데이터 암호화

방금 다운로드한 공개 키를 사용하여 데이터를 암호화하고 출력을 파일에 저장합니다.

openssl pkeyutl -in cleartext-data-input-file \
    -encrypt \
    -pubin \
    -inkey public-key-path \
    -pkeyopt rsa_padding_mode:oaep \
    -pkeyopt rsa_oaep_md:sha256 \
    -pkeyopt rsa_mgf1_md:sha256 \
    > encrypted-data-output-file
  • cleartext-data-input-file을 암호화할 파일 이름 및 경로로 바꿉니다.

  • public-key-path를 공개 키를 다운로드한 파일 이름 및 경로로 바꿉니다.

  • encrypted-data-output-file을 암호화된 데이터를 저장할 파일 이름 및 경로로 바꿉니다.

C#

이 코드를 실행하려면 먼저 C# 개발 환경을 설정하고 Cloud KMS C# SDK를 설치합니다.


using Google.Cloud.Kms.V1;
using System;
using System.Security.Cryptography;
using System.Text;

public class EncryptAsymmetricSample
{
    public byte[] EncryptAsymmetric(
      string projectId = "my-project", string locationId = "us-east1", string keyRingId = "my-key-ring", string keyId = "my-key", string keyVersionId = "123",
      string message = "Sample message")
    {
        // Create the client.
        KeyManagementServiceClient client = KeyManagementServiceClient.Create();

        // Build the key version name.
        CryptoKeyVersionName keyVersionName = new CryptoKeyVersionName(projectId, locationId, keyRingId, keyId, keyVersionId);

        // Get the public key.
        PublicKey publicKey = client.GetPublicKey(keyVersionName);

        // Split the key into blocks and base64-decode the PEM parts.
        string[] blocks = publicKey.Pem.Split("-", StringSplitOptions.RemoveEmptyEntries);
        byte[] pem = Convert.FromBase64String(blocks[1]);

        // Create a new RSA key.
        RSA rsa = RSA.Create();
        rsa.ImportSubjectPublicKeyInfo(pem, out _);

        // Convert the message into bytes. Cryptographic plaintexts and
        // ciphertexts are always byte arrays.
        byte[] plaintext = Encoding.UTF8.GetBytes(message);

        // Encrypt the data.
        byte[] ciphertext = rsa.Encrypt(plaintext, RSAEncryptionPadding.OaepSHA256);
        return ciphertext;
    }
}

Go

명령줄에서 Cloud KMS를 사용하려면 먼저 최신 버전의 Google Cloud CLI로 설치 또는 업그레이드하세요.

import (
	"context"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io"

	kms "cloud.google.com/go/kms/apiv1"
	"cloud.google.com/go/kms/apiv1/kmspb"
)

// encryptAsymmetric encrypts data on your local machine using an
// 'RSA_DECRYPT_OAEP_2048_SHA256' public key retrieved from Cloud KMS.
func encryptAsymmetric(w io.Writer, name string, message string) error {
	// name := "projects/my-project/locations/us-east1/keyRings/my-key-ring/cryptoKeys/my-key/cryptoKeyVersions/123"
	// message := "Sample message"

	// Create the client.
	ctx := context.Background()
	client, err := kms.NewKeyManagementClient(ctx)
	if err != nil {
		return fmt.Errorf("failed to create kms client: %w", err)
	}
	defer client.Close()

	// Retrieve the public key from Cloud KMS. This is the only operation that
	// involves Cloud KMS. The remaining operations take place on your local
	// machine.
	response, err := client.GetPublicKey(ctx, &kmspb.GetPublicKeyRequest{
		Name: name,
	})
	if err != nil {
		return fmt.Errorf("failed to get public key: %w", err)
	}

	// Parse the public key. Note, this example assumes the public key is in the
	// RSA format.
	block, _ := pem.Decode([]byte(response.Pem))
	publicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return fmt.Errorf("failed to parse public key: %w", err)
	}
	rsaKey, ok := publicKey.(*rsa.PublicKey)
	if !ok {
		return fmt.Errorf("public key is not rsa")
	}

	// Convert the message into bytes. Cryptographic plaintexts and
	// ciphertexts are always byte arrays.
	plaintext := []byte(message)

	// Encrypt data using the RSA public key.
	ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, rsaKey, plaintext, nil)
	if err != nil {
		return fmt.Errorf("rsa.EncryptOAEP: %w", err)
	}
	fmt.Fprintf(w, "Encrypted ciphertext: %s", ciphertext)
	return nil
}

Java

이 코드를 실행하려면 먼저 자바 개발 환경을 설정하고 Cloud KMS 자바 SDK를 설치합니다.

import com.google.cloud.kms.v1.CryptoKeyVersionName;
import com.google.cloud.kms.v1.KeyManagementServiceClient;
import com.google.cloud.kms.v1.PublicKey;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.stream.Collectors;
import javax.crypto.Cipher;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;

public class EncryptAsymmetric {

  public void encryptAsymmetric() throws IOException, GeneralSecurityException {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "your-project-id";
    String locationId = "us-east1";
    String keyRingId = "my-key-ring";
    String keyId = "my-key";
    String keyVersionId = "123";
    String plaintext = "Plaintext to encrypt";
    encryptAsymmetric(projectId, locationId, keyRingId, keyId, keyVersionId, plaintext);
  }

  // Encrypt data that was encrypted using the public key component of the given
  // key version.
  public void encryptAsymmetric(
      String projectId,
      String locationId,
      String keyRingId,
      String keyId,
      String keyVersionId,
      String plaintext)
      throws IOException, GeneralSecurityException {
    // Initialize client that will be used to send requests. This client only
    // needs to be created once, and can be reused for multiple requests. After
    // completing all of your requests, call the "close" method on the client to
    // safely clean up any remaining background resources.
    try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) {
      // Build the key version name from the project, location, key ring, key,
      // and key version.
      CryptoKeyVersionName keyVersionName =
          CryptoKeyVersionName.of(projectId, locationId, keyRingId, keyId, keyVersionId);

      // Get the public key.
      PublicKey publicKey = client.getPublicKey(keyVersionName);

      // Convert the public PEM key to a DER key (see helper below).
      byte[] derKey = convertPemToDer(publicKey.getPem());
      X509EncodedKeySpec keySpec = new X509EncodedKeySpec(derKey);
      java.security.PublicKey rsaKey = KeyFactory.getInstance("RSA").generatePublic(keySpec);

      // Encrypt plaintext for the 'RSA_DECRYPT_OAEP_2048_SHA256' key.
      // For other key algorithms:
      // https://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html
      Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
      OAEPParameterSpec oaepParams =
          new OAEPParameterSpec(
              "SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);
      cipher.init(Cipher.ENCRYPT_MODE, rsaKey, oaepParams);
      byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
      System.out.printf("Ciphertext: %s%n", ciphertext);
    }
  }

  // Converts a base64-encoded PEM certificate like the one returned from Cloud
  // KMS into a DER formatted certificate for use with the Java APIs.
  private byte[] convertPemToDer(String pem) {
    BufferedReader bufferedReader = new BufferedReader(new StringReader(pem));
    String encoded =
        bufferedReader
            .lines()
            .filter(line -> !line.startsWith("-----BEGIN") && !line.startsWith("-----END"))
            .collect(Collectors.joining());
    return Base64.getDecoder().decode(encoded);
  }
}

Node.js

이 코드를 실행하려면 먼저 Node.js 개발 환경을 설정하고 Cloud KMS Node.js SDK를 설치합니다.

//
// TODO(developer): Uncomment these variables before running the sample.
//
// const projectId = 'my-project';
// const locationId = 'us-east1';
// const keyRingId = 'my-key-ring';
// const keyId = 'my-key';
// const versionId = '123';
// const plaintextBuffer = Buffer.from('...');

// Imports the Cloud KMS library
const {KeyManagementServiceClient} = require('@google-cloud/kms');

// Instantiates a client
const client = new KeyManagementServiceClient();

// Build the key version name
const versionName = client.cryptoKeyVersionPath(
  projectId,
  locationId,
  keyRingId,
  keyId,
  versionId
);

async function encryptAsymmetric() {
  // Get public key from Cloud KMS
  const [publicKey] = await client.getPublicKey({
    name: versionName,
  });

  // Optional, but recommended: perform integrity verification on publicKey.
  // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit:
  // https://cloud.google.com/kms/docs/data-integrity-guidelines
  const crc32c = require('fast-crc32c');
  if (publicKey.name !== versionName) {
    throw new Error('GetPublicKey: request corrupted in-transit');
  }
  if (crc32c.calculate(publicKey.pem) !== Number(publicKey.pemCrc32c.value)) {
    throw new Error('GetPublicKey: response corrupted in-transit');
  }

  // Import and setup crypto
  const crypto = require('crypto');

  // Encrypt plaintext locally using the public key. This example uses a key
  // that was configured with sha256 hash with OAEP padding. Update these
  // values to match the Cloud KMS key.
  //
  // NOTE: In Node < 12, this function does not properly consume the OAEP
  // padding and thus produces invalid ciphertext. If you are using Node to do
  // public key encryption, please use version 12+.
  const ciphertextBuffer = crypto.publicEncrypt(
    {
      key: publicKey.pem,
      oaepHash: 'sha256',
      padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
    },
    plaintextBuffer
  );

  console.log(`Ciphertext: ${ciphertextBuffer.toString('base64')}`);
  return ciphertextBuffer;
}

return encryptAsymmetric();

PHP

이 코드를 실행하려면 먼저 Google Cloud에서 PHP 사용에 관해 알아보고 Cloud KMS PHP SDK 설치하세요.

function encrypt_asymmetric(
    string $projectId = 'my-project',
    string $locationId = 'us-east1',
    string $keyRingId = 'my-key-ring',
    string $keyId = 'my-key',
    string $versionId = '123',
    string $plaintext = '...'
): void {
    // PHP has limited support for asymmetric encryption operations.
    // Specifically, openssl_public_encrypt() does not allow customizing
    // algorithms or padding. Thus, it is not currently possible to use PHP
    // core for asymmetric operations on RSA keys.
    //
    // Third party libraries like phpseclib may provide the required
    // functionality. Google does not endorse this external library.
}

Python

이 코드를 실행하려면 먼저 Python 개발 환경을 설정하고 Cloud KMS Python SDK를 설치합니다.


# Import base64 for printing the ciphertext.
import base64

# Import cryptographic helpers from the cryptography package.
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding

# Import the client library.
from google.cloud import kms


def encrypt_asymmetric(
    project_id: str,
    location_id: str,
    key_ring_id: str,
    key_id: str,
    version_id: str,
    plaintext: str,
) -> bytes:
    """
    Encrypt plaintext using the public key portion of an asymmetric key.

    Args:
        project_id (string): Google Cloud project ID (e.g. 'my-project').
        location_id (string): Cloud KMS location (e.g. 'us-east1').
        key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring').
        key_id (string): ID of the key to use (e.g. 'my-key').
        version_id (string): ID of the key version to use (e.g. '1').
        plaintext (string): message to encrypt

    Returns:
        bytes: Encrypted ciphertext.

    """

    # Convert the plaintext to bytes.
    plaintext_bytes = plaintext.encode("utf-8")

    # Create the client.
    client = kms.KeyManagementServiceClient()

    # Build the key version name.
    key_version_name = client.crypto_key_version_path(
        project_id, location_id, key_ring_id, key_id, version_id
    )

    # Get the public key.
    public_key = client.get_public_key(request={"name": key_version_name})

    # Extract and parse the public key as a PEM-encoded RSA key.
    pem = public_key.pem.encode("utf-8")
    rsa_key = serialization.load_pem_public_key(pem, default_backend())

    # Construct the padding. Note that the padding differs based on key choice.
    sha256 = hashes.SHA256()
    mgf = padding.MGF1(algorithm=sha256)
    pad = padding.OAEP(mgf=mgf, algorithm=sha256, label=None)

    # Encrypt the data using the public key.
    ciphertext = rsa_key.encrypt(plaintext_bytes, pad)
    print(f"Ciphertext: {base64.b64encode(ciphertext)!r}")
    return ciphertext

Ruby

이 코드를 실행하려면 먼저 Ruby 개발 환경을 설정하고 Cloud KMS Ruby SDK를 설치합니다.

# Ruby has limited support for asymmetric encryption operations. Specifically,
# public_encrypt() does not allow customizing the MGF hash algorithm. Thus, it
# is not currently possible to use Ruby core for asymmetric encryption
# operations on RSA keys from Cloud KMS.
#
# Third party libraries may provide the required functionality. Google does
# not endorse these external libraries.

데이터 복호화

Cloud KMS를 사용하여 복호화를 수행합니다.

gcloud

명령줄에서 Cloud KMS를 사용하려면 먼저 최신 버전의 Google Cloud CLI로 설치 또는 업그레이드하세요.

gcloud kms asymmetric-decrypt \
    --version key-version \
    --key key \
    --keyring key-ring \
    --location location  \
    --ciphertext-file file-path-with-encrypted-data \
    --plaintext-file file-path-to-store-plaintext

key-version을 키 버전으로 바꾸거나 --version 플래그를 생략하여 버전을 자동으로 인식합니다. key를 복호화에 사용할 키 이름으로 바꿉니다. key-ring을 키를 배치할 키링의 이름으로 바꿉니다. location을 키링의 Cloud KMS 위치로 바꿉니다. file-path-with-encrypted-datafile-path-to-store-plaintext를 암호화된 데이터를 읽고 복호화된 출력을 저장할 로컬 파일 경로로 바꿉니다.

모든 플래그 및 가능한 값에 대한 정보를 보려면 --help 플래그와 함께 명령어를 실행하세요.

복호화된 파일의 콘텐츠를 표시하려면 편집기 또는 터미널에서 엽니다. 다음은 cat 명령어를 사용하여 파일 콘텐츠를 보여주는 예시입니다.

cat ./my-file.txt

C#

이 코드를 실행하려면 먼저 C# 개발 환경을 설정하고 Cloud KMS C# SDK를 설치합니다.


using Google.Cloud.Kms.V1;
using Google.Protobuf;
using System.Text;

public class DecryptAsymmetricSample
{
    public string DecryptAsymmetric(
      string projectId = "my-project", string locationId = "us-east1", string keyRingId = "my-key-ring", string keyId = "my-key", string keyVersionId = "123",
      byte[] ciphertext = null)
    {
        // Create the client.
        KeyManagementServiceClient client = KeyManagementServiceClient.Create();

        // Build the key version name.
        CryptoKeyVersionName keyVersionName = new CryptoKeyVersionName(projectId, locationId, keyRingId, keyId, keyVersionId);

        // Call the API.
        AsymmetricDecryptResponse result = client.AsymmetricDecrypt(keyVersionName, ByteString.CopyFrom(ciphertext));

        // Get the plaintext. Cryptographic plaintexts and ciphertexts are
        // always byte arrays.
        byte[] plaintext = result.Plaintext.ToByteArray();

        // Return the result.
        return Encoding.UTF8.GetString(plaintext);
    }
}

Go

이 코드를 실행하려면 먼저 Go 개발 환경을 설정하고 Cloud KMS Go SDK를 설치합니다.

import (
	"context"
	"fmt"
	"hash/crc32"
	"io"

	kms "cloud.google.com/go/kms/apiv1"
	"cloud.google.com/go/kms/apiv1/kmspb"
	"google.golang.org/protobuf/types/known/wrapperspb"
)

// decryptAsymmetric will attempt to decrypt a given ciphertext with an
// 'RSA_DECRYPT_OAEP_2048_SHA256' key from Cloud KMS.
func decryptAsymmetric(w io.Writer, name string, ciphertext []byte) error {
	// name := "projects/my-project/locations/us-east1/keyRings/my-key-ring/cryptoKeys/my-key/cryptoKeyVersions/123"
	// ciphertext := []byte("...")  // result of an asymmetric encryption call

	// Create the client.
	ctx := context.Background()
	client, err := kms.NewKeyManagementClient(ctx)
	if err != nil {
		return fmt.Errorf("failed to create kms client: %w", err)
	}
	defer client.Close()

	// Optional but recommended: Compute ciphertext's CRC32C.
	crc32c := func(data []byte) uint32 {
		t := crc32.MakeTable(crc32.Castagnoli)
		return crc32.Checksum(data, t)
	}
	ciphertextCRC32C := crc32c(ciphertext)

	// Build the request.
	req := &kmspb.AsymmetricDecryptRequest{
		Name:             name,
		Ciphertext:       ciphertext,
		CiphertextCrc32C: wrapperspb.Int64(int64(ciphertextCRC32C)),
	}

	// Call the API.
	result, err := client.AsymmetricDecrypt(ctx, req)
	if err != nil {
		return fmt.Errorf("failed to decrypt ciphertext: %w", err)
	}

	// Optional, but recommended: perform integrity verification on result.
	// For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit:
	// https://cloud.google.com/kms/docs/data-integrity-guidelines
	if result.VerifiedCiphertextCrc32C == false {
		return fmt.Errorf("AsymmetricDecrypt: request corrupted in-transit")
	}
	if int64(crc32c(result.Plaintext)) != result.PlaintextCrc32C.Value {
		return fmt.Errorf("AsymmetricDecrypt: response corrupted in-transit")
	}

	fmt.Fprintf(w, "Decrypted plaintext: %s", result.Plaintext)
	return nil
}

Java

이 코드를 실행하려면 먼저 자바 개발 환경을 설정하고 Cloud KMS 자바 SDK를 설치합니다.

import com.google.cloud.kms.v1.AsymmetricDecryptResponse;
import com.google.cloud.kms.v1.CryptoKeyVersionName;
import com.google.cloud.kms.v1.KeyManagementServiceClient;
import com.google.protobuf.ByteString;
import java.io.IOException;

public class DecryptAsymmetric {

  public void decryptAsymmetric() throws IOException {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "your-project-id";
    String locationId = "us-east1";
    String keyRingId = "my-key-ring";
    String keyId = "my-key";
    String keyVersionId = "123";
    byte[] ciphertext = null;
    decryptAsymmetric(projectId, locationId, keyRingId, keyId, keyVersionId, ciphertext);
  }

  // Decrypt data that was encrypted using the public key component of the given
  // key version.
  public void decryptAsymmetric(
      String projectId,
      String locationId,
      String keyRingId,
      String keyId,
      String keyVersionId,
      byte[] ciphertext)
      throws IOException {
    // Initialize client that will be used to send requests. This client only
    // needs to be created once, and can be reused for multiple requests. After
    // completing all of your requests, call the "close" method on the client to
    // safely clean up any remaining background resources.
    try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) {
      // Build the key version name from the project, location, key ring, key,
      // and key version.
      CryptoKeyVersionName keyVersionName =
          CryptoKeyVersionName.of(projectId, locationId, keyRingId, keyId, keyVersionId);

      // Decrypt the ciphertext.
      AsymmetricDecryptResponse response =
          client.asymmetricDecrypt(keyVersionName, ByteString.copyFrom(ciphertext));
      System.out.printf("Plaintext: %s%n", response.getPlaintext().toStringUtf8());
    }
  }
}

Node.js

이 코드를 실행하려면 먼저 Node.js 개발 환경을 설정하고 Cloud KMS Node.js SDK를 설치합니다.

//
// TODO(developer): Uncomment these variables before running the sample.
//
// const projectId = 'my-project';
// const locationId = 'us-east1';
// const keyRingId = 'my-key-ring';
// const keyId = 'my-key';
// const versionId = '123';
// const ciphertext = Buffer.from('...');

// Imports the Cloud KMS library
const {KeyManagementServiceClient} = require('@google-cloud/kms');

// Instantiates a client
const client = new KeyManagementServiceClient();

// Build the key version name
const versionName = client.cryptoKeyVersionPath(
  projectId,
  locationId,
  keyRingId,
  keyId,
  versionId
);

// Optional, but recommended: compute plaintext's CRC32C.
const crc32c = require('fast-crc32c');
const ciphertextCrc32c = crc32c.calculate(ciphertext);

async function decryptAsymmetric() {
  const [decryptResponse] = await client.asymmetricDecrypt({
    name: versionName,
    ciphertext: ciphertext,
    ciphertextCrc32c: {
      value: ciphertextCrc32c,
    },
  });

  // Optional, but recommended: perform integrity verification on decryptResponse.
  // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit:
  // https://cloud.google.com/kms/docs/data-integrity-guidelines
  if (!decryptResponse.verifiedCiphertextCrc32c) {
    throw new Error('AsymmetricDecrypt: request corrupted in-transit');
  }
  if (
    crc32c.calculate(decryptResponse.plaintext) !==
    Number(decryptResponse.plaintextCrc32c.value)
  ) {
    throw new Error('AsymmetricDecrypt: response corrupted in-transit');
  }

  // NOTE: The ciphertext must be properly formatted. In Node < 12, the
  // crypto.publicEncrypt() function does not properly consume the OAEP
  // padding and thus produces invalid ciphertext. If you are using Node to do
  // public key encryption, please use version 12+.
  const plaintext = decryptResponse.plaintext.toString('utf8');

  console.log(`Plaintext: ${plaintext}`);
  return plaintext;
}

return decryptAsymmetric();

PHP

이 코드를 실행하려면 먼저 Google Cloud에서 PHP 사용에 관해 알아보고 Cloud KMS PHP SDK 설치하세요.

use Google\Cloud\Kms\V1\AsymmetricDecryptRequest;
use Google\Cloud\Kms\V1\Client\KeyManagementServiceClient;

function decrypt_asymmetric(
    string $projectId = 'my-project',
    string $locationId = 'us-east1',
    string $keyRingId = 'my-key-ring',
    string $keyId = 'my-key',
    string $versionId = '123',
    string $ciphertext = '...'
) {
    // Create the Cloud KMS client.
    $client = new KeyManagementServiceClient();

    // Build the key version name.
    $keyVersionName = $client->cryptoKeyVersionName($projectId, $locationId, $keyRingId, $keyId, $versionId);

    // Call the API.
    $asymmetricDecryptRequest = (new AsymmetricDecryptRequest())
        ->setName($keyVersionName)
        ->setCiphertext($ciphertext);
    $decryptResponse = $client->asymmetricDecrypt($asymmetricDecryptRequest);
    printf('Plaintext: %s' . PHP_EOL, $decryptResponse->getPlaintext());

    return $decryptResponse;
}

Python

이 코드를 실행하려면 먼저 Python 개발 환경을 설정하고 Cloud KMS Python SDK를 설치합니다.

from google.cloud import kms


def decrypt_asymmetric(
    project_id: str,
    location_id: str,
    key_ring_id: str,
    key_id: str,
    version_id: str,
    ciphertext: bytes,
) -> kms.DecryptResponse:
    """
    Decrypt the ciphertext using an asymmetric key.

    Args:
        project_id (string): Google Cloud project ID (e.g. 'my-project').
        location_id (string): Cloud KMS location (e.g. 'us-east1').
        key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring').
        key_id (string): ID of the key to use (e.g. 'my-key').
        version_id (string): ID of the key version to use (e.g. '1').
        ciphertext (bytes): Encrypted bytes to decrypt.

    Returns:
        DecryptResponse: Response including plaintext.

    """

    # Create the client.
    client = kms.KeyManagementServiceClient()

    # Build the key version name.
    key_version_name = client.crypto_key_version_path(
        project_id, location_id, key_ring_id, key_id, version_id
    )

    # Optional, but recommended: compute ciphertext's CRC32C.
    # See crc32c() function defined below.
    ciphertext_crc32c = crc32c(ciphertext)

    # Call the API.
    decrypt_response = client.asymmetric_decrypt(
        request={
            "name": key_version_name,
            "ciphertext": ciphertext,
            "ciphertext_crc32c": ciphertext_crc32c,
        }
    )

    # Optional, but recommended: perform integrity verification on decrypt_response.
    # For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit:
    # https://cloud.google.com/kms/docs/data-integrity-guidelines
    if not decrypt_response.verified_ciphertext_crc32c:
        raise Exception("The request sent to the server was corrupted in-transit.")
    if not decrypt_response.plaintext_crc32c == crc32c(decrypt_response.plaintext):
        raise Exception(
            "The response received from the server was corrupted in-transit."
        )
    # End integrity verification

    print(f"Plaintext: {decrypt_response.plaintext!r}")
    return decrypt_response


def crc32c(data: bytes) -> int:
    """
    Calculates the CRC32C checksum of the provided data.
    Args:
        data: the bytes over which the checksum should be calculated.
    Returns:
        An int representing the CRC32C checksum of the provided bytes.
    """
    import crcmod  # type: ignore

    crc32c_fun = crcmod.predefined.mkPredefinedCrcFun("crc-32c")
    return crc32c_fun(data)

Ruby

이 코드를 실행하려면 먼저 Ruby 개발 환경을 설정하고 Cloud KMS Ruby SDK를 설치합니다.

# TODO(developer): uncomment these values before running the sample.
# project_id  = "my-project"
# location_id = "us-east1"
# key_ring_id = "my-key-ring"
# key_id      = "my-key"
# version_id  = "123"
# ciphertext  = "..."

# Require the library.
require "google/cloud/kms"

# Create the client.
client = Google::Cloud::Kms.key_management_service

# Build the key version name.
key_version_name = client.crypto_key_version_path project:            project_id,
                                                  location:           location_id,
                                                  key_ring:           key_ring_id,
                                                  crypto_key:         key_id,
                                                  crypto_key_version: version_id

# Call the API.
response = client.asymmetric_decrypt key_version_name, ciphertext
puts "Plaintext: #{response.plaintext}"

API

이 예시에서는 curl을 HTTP 클라이언트로 사용하여 API 사용을 보여줍니다. 액세스 제어에 대한 자세한 내용은 Cloud KMS API 액세스를 참조하세요.

CryptoKeyVersions.asymmetricDecrypt 메서드를 사용합니다.

문제 해결

incorrect key purpose: ASYMMETRIC_SIGN

키 용도ASYMMETRIC_DECRYPT인 키로만 데이터를 복호화할 수 있습니다.

macOS에서 복호화하는 경우 invalid parameter

macOS에 설치된 OpenSSL 버전은 이 주제에서 데이터 복호화에 사용되는 플래그를 지원하지 않습니다. macOS에서 이 단계를 수행하려면 Homebrew에서 OpenSSL을 설치하세요.

data too large for key size

RSA 복호화의 최대 페이로드 크기는 키 크기와 패딩 알고리즘에 따라 다릅니다. Cloud KMS에서 사용하는 모든 RSA 암호화 형식은 RFC 2437에서 표준화된 OAEP를 사용합니다. 다음 알고리즘은 다음과 같은 최대 페이로드 크기(maxMLen, 바이트)를 지원합니다.

알고리즘 매개변수 최대 메시지 길이
RSA_DECRYPT_OAEP_2048_SHA256 k = 256, hLen = 32, maxMLen = 190
RSA_DECRYPT_OAEP_3072_SHA256 k = 384, hLen = 32, maxMLen = 318
RSA_DECRYPT_OAEP_4096_SHA256 k = 512, hLen = 32, maxMLen = 446
RSA_DECRYPT_OAEP_4096_SHA512 k = 512, hLen = 64, maxMLen = 382

이러한 한도보다 큰 다양한 길이의 메시지에는 비대칭 암호화를 사용하지 않는 것이 좋습니다. 대신 하이브리드 암호화를 사용해보세요. Tink는 이 접근 방식을 사용하는 암호화 라이브러리입니다.