本主题介绍如何基于 MAC 密钥创建和验证数字签名。
生产者和验证者共享一个密钥,用于计算输入数据的 MAC 标记(即签名)。验证者收到消息及其关联的 MAC 标记后,会为其内容生成自己的标记,并比较这些标记以查看它们是否匹配。
准备工作
将 MAC 密钥的
cloudkms.cryptoKeyVersions.useToSign
权限授予将执行签名的用户或服务。您可以参阅权限和角色,了解 Cloud Key Management Service 中的权限。如果您要验证签名,请将 MAC 密钥的
cloudkms.cryptoKeyVersions.useToVerify
权限授予将执行验证的用户或服务。
创建 MAC 签名
gcloud
如需在命令行上使用 Cloud KMS,请先安装或升级到最新版本的 Google Cloud CLI。
gcloud kms mac-sign \ --version key-version \ --key key \ --keyring key-ring \ --location location \ --input-file input-file \ --signature-file signature-file
将 key-version 替换为用于签名的密钥的版本。将 key 替换为密钥名称。将 key-ring 替换为密钥所在的密钥环的名称。将 location 替换为密钥环的 Cloud KMS 位置。将 input-file 和 signature-file 分别替换为要签名的文件和签名文件的本地路径。
如需了解所有标志和可能值,请使用 --help
标志运行命令。
C#
要运行此代码,请先设置 C# 开发环境并安装 Cloud KMS C# SDK。
using Google.Cloud.Kms.V1;
using Google.Protobuf;
public class SignMacSample
{
public byte[] SignMac(
string projectId = "my-project", string locationId = "us-east1", string keyRingId = "my-key-ring", string keyId = "my-key", string keyVersionId = "123",
string data = "Sample data")
{
// Create the client.
KeyManagementServiceClient client = KeyManagementServiceClient.Create();
// Build the key version name.
CryptoKeyVersionName keyVersionName = new CryptoKeyVersionName(projectId, locationId, keyRingId, keyId, keyVersionId);
// Convert the data into a ByteString.
ByteString dataByteString = ByteString.CopyFromUtf8(data);
// Call the API.
MacSignResponse result = client.MacSign(keyVersionName, dataByteString);
// The data comes back as raw bytes, which may include non-printable
// characters. To print the result, you could encode it as base64.
// string encodedSignature = result.Mac.ToBase64();
// Get the signature.
byte[] signature = result.Mac.ToByteArray();
// Return the result.
return signature;
}
}
Go
要运行此代码,请先设置 Go 开发环境并安装 Cloud KMS Go SDK。
import (
"context"
"encoding/base64"
"fmt"
"io"
kms "cloud.google.com/go/kms/apiv1"
kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
)
// signMac will sign a plaintext message using the HMAC algorithm.
func signMac(w io.Writer, name string, data string) error {
// name := "projects/my-project/locations/us-east1/keyRings/my-key-ring/cryptoKeys/my-key/cryptoKeyVersions/123"
// data := "my data to sign"
// Create the client.
ctx := context.Background()
client, err := kms.NewKeyManagementClient(ctx)
if err != nil {
return fmt.Errorf("failed to create kms client: %v", err)
}
defer client.Close()
// Build the request.
req := &kmspb.MacSignRequest{
Name: name,
Data: []byte(data),
}
// Generate HMAC of data.
result, err := client.MacSign(ctx, req)
if err != nil {
return fmt.Errorf("failed to hmac sign: %v", err)
}
// The data comes back as raw bytes, which may include non-printable
// characters. This base64-encodes the result so it can be printed below.
encodedSignature := base64.StdEncoding.EncodeToString(result.Mac)
fmt.Fprintf(w, "Signature: %s", encodedSignature)
return nil
}
Java
要运行此代码,请先设置 Java 开发环境并安装 Cloud KMS Java SDK。
import com.google.cloud.kms.v1.CryptoKeyVersionName;
import com.google.cloud.kms.v1.KeyManagementServiceClient;
import com.google.cloud.kms.v1.MacSignResponse;
import com.google.protobuf.ByteString;
import java.io.IOException;
import java.util.Base64;
public class SignMac {
public void signMac() 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";
String data = "Data to sign";
signMac(projectId, locationId, keyRingId, keyId, keyVersionId, data);
}
// Sign data with a given mac key.
public void signMac(
String projectId,
String locationId,
String keyRingId,
String keyId,
String keyVersionId,
String data)
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);
// Generate an HMAC of the data.
MacSignResponse response = client.macSign(keyVersionName, ByteString.copyFromUtf8(data));
// The data comes back as raw bytes, which may include non-printable
// characters. This base64-encodes the result so it can be printed below.
String encodedSignature = Base64.getEncoder().encodeToString(response.getMac().toByteArray());
System.out.printf("Signature: %s%n", encodedSignature);
}
}
}
Node.js
要运行此代码,请先设置 Node.js 开发环境并安装 Cloud KMS Node.js SDK。
//
// TODO(developer): Uncomment these variables before running the sample.
//
// const projectId = 'your-project-id';
// const locationId = 'us-east1';
// const keyRingId = 'my-key-ring';
// const keyId = 'my-key';
// const versionId = '123';
// const data = Buffer.from('...');
// Imports the Cloud KMS library
const {KeyManagementServiceClient} = require('@google-cloud/kms');
// Instantiates a client
const client = new KeyManagementServiceClient();
// Build the version name
const versionName = client.cryptoKeyVersionPath(
projectId,
locationId,
keyRingId,
keyId,
versionId
);
async function signMac() {
// Sign the data with Cloud KMS
const [signResponse] = await client.macSign({
name: versionName,
data: data,
});
// Example of how to display signature. Because the signature is in a binary
// format, you need to encode the output before printing it to a console or
// displaying it on a screen.
const encoded = signResponse.mac.toString('base64');
console.log(`Signature: ${encoded}`);
return signResponse;
}
return signMac();
Python
要运行此代码,请先设置 Python 开发环境并安装 Cloud KMS Python SDK。
def sign_mac(project_id, location_id, key_ring_id, key_id, version_id, data):
"""
Sign a message using the public key part 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): Version to use (e.g. '1').
data (string): Data to sign.
Returns:
MacSignResponse: Signature.
"""
# Import the client library.
from google.cloud import kms
# Import base64 for printing the ciphertext.
import base64
# 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)
# Convert the message to bytes.
data_bytes = data.encode('utf-8')
# Call the API
sign_response = client.mac_sign(
request={'name': key_version_name, 'data': data_bytes})
print('Signature: {}'.format(base64.b64encode(sign_response.mac)))
return sign_response
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"
# data = "my data"
# Require the library.
require "google/cloud/kms"
# Require digest.
require "digest"
# 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.
sign_response = client.mac_sign name: key_version_name, data: data
# The data comes back as raw bytes, which may include non-printable
# characters. This base64-encodes the result so it can be printed below.
encoded_signature = Base64.strict_encode64 sign_response.mac
puts "Signature: #{encoded_signature}"
API
这些示例使用 curl 作为 HTTP 客户端来演示如何使用 API。如需详细了解访问权限控制,请参阅访问 Cloud KMS API。
使用 CryptoKeyVersions.macSign
方法执行签名。此方法返回的响应包含 base64 编码的签名。
验证 MAC 签名
gcloud
如需在命令行上使用 Cloud KMS,请先安装或升级到最新版本的 Google Cloud CLI。
gcloud kms mac-verify \ --version key-version \ --key key \ --keyring key-ring \ --location location \ --input-file input-file \ --signature-file signature-file
将 key-version 替换为要用于验证的密钥的版本。将 key 替换为密钥名称。将 key-ring 替换为密钥所在的密钥环的名称。将 location 替换为密钥环的 Cloud KMS 位置。将 input-file 和 signature-file 分别替换为要验证的输入数据和签名文件的本地路径。
如需了解所有标志和可能值,请使用 --help
标志运行命令。
C#
要运行此代码,请先设置 C# 开发环境并安装 Cloud KMS C# SDK。
using Google.Cloud.Kms.V1;
using Google.Protobuf;
public class VerifyMacSample
{
public bool VerifyMac(
string projectId = "my-project", string locationId = "us-east1", string keyRingId = "my-key-ring", string keyId = "my-key", string keyVersionId = "123",
string data = "my data",
byte[] signature = null)
{
// Build the key version name.
CryptoKeyVersionName keyVersionName = new CryptoKeyVersionName(projectId, locationId, keyRingId, keyId, keyVersionId);
// Create the client.
KeyManagementServiceClient client = KeyManagementServiceClient.Create();
// Convert the data and signatures into ByteStrings.
ByteString dataByteString = ByteString.CopyFromUtf8(data);
ByteString signatureByteString = ByteString.CopyFrom(signature);
// Verify the signature.
MacVerifyResponse result = client.MacVerify(keyVersionName, dataByteString, signatureByteString);
// Return the result.
return result.Success;
}
}
Go
要运行此代码,请先设置 Go 开发环境并安装 Cloud KMS Go SDK。
import (
"context"
"fmt"
"io"
kms "cloud.google.com/go/kms/apiv1"
kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
)
// verifyMac will verify a previous HMAC signature.
func verifyMac(w io.Writer, name string, data, signature []byte) error {
// name := "projects/my-project/locations/us-east1/keyRings/my-key-ring/cryptoKeys/my-key/cryptoKeyVersions/123"
// data := "my previous data"
// signature := []byte("...") // Response from a sign request
// Create the client.
ctx := context.Background()
client, err := kms.NewKeyManagementClient(ctx)
if err != nil {
return fmt.Errorf("failed to create kms client: %v", err)
}
defer client.Close()
// Build the request.
req := &kmspb.MacVerifyRequest{
Name: name,
Data: data,
Mac: signature,
}
// Verify the signature.
result, err := client.MacVerify(ctx, req)
if err != nil {
return fmt.Errorf("failed to verify signature: %v", err)
}
fmt.Fprintf(w, "Verified: %t", result.Success)
return nil
}
Java
要运行此代码,请先设置 Java 开发环境并安装 Cloud KMS Java SDK。
import com.google.cloud.kms.v1.CryptoKeyVersionName;
import com.google.cloud.kms.v1.KeyManagementServiceClient;
import com.google.cloud.kms.v1.MacVerifyResponse;
import com.google.protobuf.ByteString;
import java.io.IOException;
public class VerifyMac {
public void verifyMac() 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";
String data = "Data to sign";
byte[] signature = null;
verifyMac(projectId, locationId, keyRingId, keyId, keyVersionId, data, signature);
}
// Sign data with a given mac key.
public void verifyMac(
String projectId,
String locationId,
String keyRingId,
String keyId,
String keyVersionId,
String data,
byte[] signature)
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);
// Verify the signature
MacVerifyResponse response =
client.macVerify(
keyVersionName, ByteString.copyFromUtf8(data), ByteString.copyFrom(signature));
// The data comes back as raw bytes, which may include non-printable
// characters. This base64-encodes the result so it can be printed below.
System.out.printf("Success: %s%n", response.getSuccess());
}
}
}
Node.js
要运行此代码,请先设置 Node.js 开发环境并安装 Cloud KMS Node.js SDK。
//
// TODO(developer): Uncomment these variables before running the sample.
//
// const projectId = 'your-project-id';
// const locationId = 'us-east1';
// const keyRingId = 'my-key-ring';
// const keyId = 'my-key';
// const versionId = '123';
// const data = Buffer.from('...');
// const signature = Buffer.from('...');
// Imports the Cloud KMS library
const {KeyManagementServiceClient} = require('@google-cloud/kms');
// Instantiates a client
const client = new KeyManagementServiceClient();
// Build the version name
const versionName = client.cryptoKeyVersionPath(
projectId,
locationId,
keyRingId,
keyId,
versionId
);
async function verifyMac() {
// Verify the data with Cloud KMS
const [verifyResponse] = await client.macVerify({
name: versionName,
data: data,
mac: signature,
});
console.log(`Verified: ${verifyResponse.success}`);
return verifyResponse;
}
return verifyMac();
Python
要运行此代码,请先设置 Python 开发环境并安装 Cloud KMS Python SDK。
def verify_mac(project_id, location_id, key_ring_id, key_id, version_id, data, signature):
"""
Verify the signature of data from an HMAC 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): Version to use (e.g. '1').
data (string): Data that was signed.
signature (bytes): Signature bytes.
Returns:
MacVerifyResponse: Success.
"""
# Import the client library.
from google.cloud import kms
# 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)
# Convert the message to bytes.
data_bytes = data.encode('utf-8')
# Call the API
verify_response = client.mac_verify(
request={'name': key_version_name, 'data': data_bytes, 'mac': signature})
print('Verified: {}'.format(verify_response.success))
return verify_response
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"
# data = "my data"
# signature = "..."
# Require the library.
require "google/cloud/kms"
# Require digest.
require "digest"
# 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.
verify_response = client.mac_verify name: key_version_name, data: data, mac: signature
puts "Verified: #{verify_response.success}"
API
这些示例使用 curl 作为 HTTP 客户端来演示如何使用 API。如需详细了解访问权限控制,请参阅访问 Cloud KMS API。
使用 CryptoKeyVersions.macVerify
方法执行验证。要验证的签名应采用 base64 编码。此方法返回的响应包含布尔值,指示签名是否验证成功。