使用非对称密钥加密和解密数据

本主题介绍了如何使用 RSA 密钥创建和使用非对称加密密钥。如果要使用非对称密钥创建和验证签名,请参阅创建和验证数字签名。如果要使用对称密钥进行加密和解密,请参阅加密和解密数据

非对称加密使用非对称密钥的公钥部分,非对称解密使用该密钥的私钥部分。Cloud KMS 提供检索公钥以及对使用该公钥加密的密文进行解密的功能。Cloud KMS 不允许直接对私钥进行访问。

准备工作

对密钥的访问权限控制

  • 对于将检索公钥的用户或服务,向非对称密钥授予 cloudkms.cryptoKeyVersions.viewPublicKey 权限。对数据进行加密时需要该公钥。

  • 对于将对使用公钥加密的数据进行解密的用户或服务,向非对称密钥授予 cloudkms.cryptoKeyVersions.useToDecrypt 权限。

如需了解 Cloud KMS 中的权限和角色,请参阅权限和角色

加密数据

如果您还没有公钥,请检索公钥

命令行

此示例假定公钥位于名为 rsa-decrypt-key.pub 的文件中。

  1. 点击控制台窗口顶部的 Activate Cloud Shell 按钮。 Activate Cloud Shell一个 Cloud Shell 会话随即会在控制台底部的新框内打开,并显示命令行提示符。该 Shell 会话可能需要几秒钟来完成初始化。 Cloud Shell 会话

  2. 在 Cloud Shell 命令行提示符处,创建明文文件。

    echo "my secret message" > ~/my-secret-file
    
  3. 使用 OpenSSL 加密该文件。该示例使用 SHA-256 摘要。目前,所有非对称加密算法都使用 SHA-256 摘要。

    openssl pkeyutl -in ~/my-secret-file \
      -encrypt -pubin \
      -inkey ~/rsa-decrypt-key.pub \
      -pkeyopt rsa_padding_mode:oaep \
      -pkeyopt rsa_oaep_md:sha256 \
      -pkeyopt rsa_mgf1_md:sha256 > ~/my-secret-file.enc
    

Go


// encryptRSA will encrypt data locally using an 'RSA_DECRYPT_OAEP_2048_SHA256' public key retrieved from Cloud KMS
// example keyName: "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys/KEY_ID/cryptoKeyVersions/1"
func encryptRSA(keyName string, plaintext []byte) ([]byte, error) {
	ctx := context.Background()
	client, err := cloudkms.NewKeyManagementClient(ctx)
	if err != nil {
		return nil, err
	}

	// Retrieve the public key from KMS.
	response, err := client.GetPublicKey(ctx, &kmspb.GetPublicKeyRequest{Name: keyName})
	if err != nil {
		return nil, fmt.Errorf("failed to fetch public key: %+v", err)
	}
	// Parse the key.
	block, _ := pem.Decode([]byte(response.Pem))
	abstractKey, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, fmt.Errorf("failed to parse public key: %+v", err)
	}
	rsaKey, ok := abstractKey.(*rsa.PublicKey)
	if !ok {
		return nil, fmt.Errorf("key '%s' is not RSA", keyName)
	}
	// Encrypt data using the RSA public key.
	ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, rsaKey, plaintext, nil)
	if err != nil {
		return nil, fmt.Errorf("encryption failed: %+v", err)
	}
	return ciphertext, nil
}

Java

/**
 * Encrypt data locally using an 'RSA_DECRYPT_OAEP_2048_SHA256' public key
 * retrieved from Cloud KMS
 *
 * Example keyName:
 *   "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys/KEY_ID/cryptoKeyVersions/1"
 */
public static byte[] encryptRSA(String keyName, byte[] plaintext)
    throws IOException, GeneralSecurityException {
  // Create the Cloud KMS client.
  try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) {
    // Get the public key
    com.google.cloud.kms.v1.PublicKey pub = client.getPublicKey(keyName);
    String pemKey = pub.getPem();
    pemKey = pemKey.replaceFirst("-----BEGIN PUBLIC KEY-----", "");
    pemKey = pemKey.replaceFirst("-----END PUBLIC KEY-----", "");
    pemKey = pemKey.replaceAll("\\s", "");
    byte[] derKey = BaseEncoding.base64().decode(pemKey);
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(derKey);
    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);

    return cipher.doFinal(plaintext);
  }
}

Python

def encrypt_rsa(plaintext, key_name):
    """
    Encrypt the input plaintext (bytes) locally using an
    'RSA_DECRYPT_OAEP_2048_SHA256' public key retrieved from Cloud KMS

    Example key_name:
      "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\
              /KEY_ID/cryptoKeyVersions/1"

    Requires:
      cryptography.hazmat.primitives.asymmetric.padding
      cryptography.hazmat.primitives.hashes
    """
    # get the public key
    client = kms_v1.KeyManagementServiceClient()
    response = client.get_public_key(key_name)
    key_txt = response.pem.encode('ascii')
    public_key = serialization.load_pem_public_key(key_txt, default_backend())

    # encrypt plaintext
    pad = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
                       algorithm=hashes.SHA256(),
                       label=None)
    return public_key.encrypt(plaintext, pad)

解密数据

使用 Cloud KMS 执行解密。

命令行

gcloud kms asymmetric-decrypt \
  --location [LOCATION] \
  --keyring [KEYRING_NAME] \
  --key [KEY_NAME] \
  --version [KEY_VERSION] \
  --ciphertext-file ~/my-secret-file.enc \
  --plaintext-file ~/my-secret-file.dec

显示文件解密后的内容。

cat ~/my-secret-file.dec

您应该看到为纯文本文件创建的相同文本。

my secret message

API

使用 CryptoKeyVersions.asymmetricDecrypt 方法。

  • 将请求的 ciphertext 值设置为加密该纯文本时创建的密文。

CryptoKeyVersions.asymmetricDecrypt 响应包含解密后的数据。

Go


// decryptRSA will attempt to decrypt a given ciphertext with an 'RSA_DECRYPT_OAEP_2048_SHA256' private key.stored on Cloud KMS
// example keyName: "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys/KEY_ID/cryptoKeyVersions/1"
func decryptRSA(keyName string, ciphertext []byte) ([]byte, error) {
	ctx := context.Background()
	client, err := cloudkms.NewKeyManagementClient(ctx)
	if err != nil {
		return nil, err
	}

	// Build the request.
	req := &kmspb.AsymmetricDecryptRequest{
		Name:       keyName,
		Ciphertext: ciphertext,
	}
	// Call the API.
	response, err := client.AsymmetricDecrypt(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("decryption request failed: %+v", err)
	}
	return response.Plaintext, nil
}

Java

/**
 * Decrypt a given ciphertext using an 'RSA_DECRYPT_OAEP_2048_SHA256' private key
 * stored on Cloud KMS
 *
 * Example keyName:
 *   "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys/KEY_ID/cryptoKeyVersions/1"
 */
public static byte[] decryptRSA(String keyName, byte[] ciphertext) throws IOException {
  // Create the Cloud KMS client.
  try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) {
    AsymmetricDecryptResponse response = client.asymmetricDecrypt(
        keyName, ByteString.copyFrom(ciphertext));
    return response.getPlaintext().toByteArray();
  }
}

Python

def decrypt_rsa(ciphertext, key_name):
    """
    Decrypt the input ciphertext (bytes) using an
    'RSA_DECRYPT_OAEP_2048_SHA256' private key stored on Cloud KMS

    Example key_name:
      "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\
              /KEY_ID/cryptoKeyVersions/1"
    """

    client = kms_v1.KeyManagementServiceClient()
    response = client.asymmetric_decrypt(key_name, ciphertext)
    return response.plaintext

此页内容是否有用?请给出您的反馈和评价:

发送以下问题的反馈:

此网页
Cloud KMS