MAC 디지털 서명 생성 및 검증

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

이 주제에서는 MAC 키를 기반으로 한 디지털 서명 생성 및 검증을 설명합니다.

제작자와 확인자가 모두 공유하는 단일 키는 입력 데이터로 MAC 태그를 계산하는 데 사용됩니다. MAC 태그는 디지털 서명 역할을 합니다. 확인자는 메시지 및 연결된 MAC 태그를 수신하면 메시지 콘텐츠로 자체 태그를 생성합니다. 그런 다음 확인자는 수신된 태그와 생성된 태그를 비교하여 일치 여부를 확인할 수 있습니다. 두 태그가 일치하면 확인자는 수신된 메시지와 생성자가 서명한 메시지가 서로 동일함을 인식합니다.

시작하기 전에

  • MAC 디지털 서명을 만들 때는 키 용도MAC인 키를 사용해야 합니다. 키를 만들 때는 MAC을 사용합니다.

  • 서명하려는 파일이 파일 크기 한도 이내인지 확인하세요. Cloud HSM 키를 사용하여 MAC 서명을 만들거나 확인할 때 최대 파일 크기는 16KiB입니다. 다른 모든 키의 최대 파일 크기는 64KiB입니다.

필요한 역할

서명을 만들고 확인하는 데 필요한 권한을 얻으려면 관리자에게 키에 대한 다음 IAM 역할을 부여해 달라고 요청하세요.

  • 서명 만들기: Cloud KMS CryptoKey 서명자(roles/cloudkms.signer)
  • 서명 확인: Cloud KMS CryptoKey 확인자(roles/cloudkms.verifier)
  • 서명 만들기 및 확인: Cloud KMS CryptoKey 서명자/확인자(roles/cloudkms.signerVerifier)

역할 부여에 대한 자세한 내용은 액세스 관리를 참조하세요.

MAC 서명 만들기

gcloud CLI

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

gcloud kms mac-sign \
    --version KEY_VERSION \
    --key KEY_NAME \
    --keyring KEY_RING \
    --location LOCATION \
    --input-file INPUT_FILE_PATH \
    --signature-file SIGNED_FILE_PATH

다음을 바꿉니다.

  • KEY_VERSION: 키 버전 번호입니다.
  • KEY_NAME: 키의 이름입니다.
  • KEY_RING: 키가 포함된 키링의 이름입니다.
  • LOCATION: 키링의 Cloud KMS 위치입니다.
  • INPUT_FILE_PATH: 서명할 파일의 로컬 경로입니다.
  • SIGNED_FILE_PATH: 생성된 서명을 저장할 로컬 경로입니다.

모든 플래그 및 가능한 값에 대한 정보를 보려면 --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"
	"cloud.google.com/go/kms/apiv1/kmspb"
)

// 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

이 코드를 실행하려면 먼저 자바 개발 환경을 설정하고 Cloud KMS 자바 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 CLI

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

gcloud kms mac-verify \
    --version KEY_VERSION \
    --key KEY_NAME \
    --keyring KEY_RING \
    --location LOCATION \
    --input-file INPUT_FILE_PATH \
    --signature-file SIGNED_FILE_PATH
  • KEY_VERSION: 키 버전 번호입니다.
  • KEY_NAME: 키의 이름입니다.
  • KEY_RING: 키가 포함된 키링의 이름입니다.
  • LOCATION: 키링의 Cloud KMS 위치입니다.
  • INPUT_FILE_PATH: 서명된 파일의 로컬 경로입니다.
  • SIGNED_FILE_PATH: 확인할 서명 파일의 로컬 경로입니다.

모든 플래그 및 가능한 값에 대한 정보를 보려면 --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"
	"cloud.google.com/go/kms/apiv1/kmspb"
)

// 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

이 코드를 실행하려면 먼저 자바 개발 환경을 설정하고 Cloud KMS 자바 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로 인코딩되어야 합니다. 이 메서드의 응답에는 서명이 성공적으로 검증되었는지 여부를 나타내는 부울이 포함됩니다.