디지털 서명 생성 및 검증

이 주제에서는 비대칭 키를 기반으로 한 디지털 서명 생성 및 검증에 대한 정보를 제공합니다.

디지털 서명은 비대칭 키의 비공개 키 부분을 사용하여 생성됩니다. 서명은 동일한 비대칭 키의 공개 키 부분을 사용하여 검증됩니다.

시작하기 전에

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

  • 서명을 확인하려면 키를 만들 때 사용한 전체 알고리즘을 알아야 합니다. 아래의 openssl 명령어를 사용하는 명령줄 안내의 경우 이 정보를 해당 명령어에 전달해야 합니다.

  • 서명을 수행할 사용자 또는 서비스에 비대칭 키에 대한 cloudkms.cryptoKeyVersions.useToSign 권한을 부여합니다. Cloud Key Management Service의 권한은 권한 및 역할에서 확인할 수 있습니다.

  • 서명을 검증하려면 검증에 사용할 공개 키를 다운로드할 사용자 또는 서비스에 비대칭 키에 대한 cloudkms.cryptoKeyVersions.viewPublicKey 권한을 부여합니다.

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

데이터와 다이제스트 비교

AsymmetricSign 요청에 제공된 입력은 data 필드 또는 digest 필드를 통해 전달될 수 있습니다. 두 필드를 동시에 지정할 수는 없습니다. 원시 알고리즘Cloud 외부 키 관리자 키로 서명하는 것과 같이 데이터 필드가 필요한 몇 가지 알고리즘이 있습니다.

원시 알고리즘

RSA_SIGN_RAW_ 프리픽스로 식별되는 '원시' 알고리즘은 DigestInfo로의 인코딩을 생략하는 PKCS #1 서명의 변형입니다. 이 변형은 다음과 같은 특징이 있습니다.

  • 다이제스트는 서명될 메시지를 대상으로 계산됩니다.
  • PKCS #1 패딩은 다이제스트에 직접 적용됩니다.
  • 패딩된 다이제스트의 서명은 RSA 비공개 키를 사용하여 계산됩니다.

이러한 알고리즘을 사용하려면 다음 안내를 따르세요.

  • data 필드의 일부로 다이제스트 대신 원시 데이터를 제공해야 합니다.
  • 데이터의 길이 한도는 RSA 키 크기보다 11바이트 적습니다. 예를 들어, 2048비트 RSA 키가 있는 PKCS #1은 최대 245바이트에 서명할 수 있습니다.
  • cloudkms.expertRawPKCS1 역할을 적절한 사용자 또는 서비스에 부여합니다. Cloud Key Management Service의 권한은 권한 및 역할에서 확인할 수 있습니다.

원시 알고리즘을 사용하면 사전 정의된 알고리즘을 사용할 수 없는 다이제스트 유형에 서명할 수도 있습니다. 예를 들어 RSA_SIGN_RAW_2048 키를 사용하여 이미 외부에서 계산한 SHA-512 PKCS #1 DigestInfo 구조에 서명할 수 있습니다. 이 프로세스는 표준 RSA_SIGN_PKCS1_2048_SHA512 알고리즘과 동일한 결과를 생성합니다.

기타 해시 알고리즘에 대한 ECDSA 지원

ECDSA 서명 알고리즘은 일반적인 형식을 가집니다.

EC_SIGN_ELLIPTIC_CURVE_[DIGEST_ALGORITHM]

DIGEST_ALGORITHM의 값은 SHA256, SHA384 또는 SHA512입니다. 해싱은 서명을 만들기 전에 실행되므로 이러한 서명 알고리즘은 Keccak과 같은 SHA 이외의 다이제스트와도 사용할 수 있습니다. Keccak 다이제스트를 사용하려면 Keccak 해시 값을 제공하고 동일한 길이의 SHA 다이제스트 알고리즘을 사용합니다. 예를 들어 EC_SIGN_P256_SHA256 알고리즘을 사용하는 요청에서 KECCAK256 다이제스트를 사용할 수 있습니다.

서명 만들기

gcloud

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

gcloud kms asymmetric-sign \
    --version key-version \
    --key key \
    --keyring key-ring \
    --location location \
    --digest-algorithm digest-algorithm \
    --input-file input-file \
    --signature-file signature-file

key-version을 서명에 사용할 키 버전으로 바꿉니다. key를 키 이름으로 바꿉니다. key-ring을 키가 배치된 키링의 이름으로 바꿉니다. location을 키링의 Cloud KMS 위치로 바꿉니다. digest-algorithm을 사용할 알고리즘으로 바꿉니다. digest-algorithm을 생략하여 input-file을 서명할 Cloud KMS로 보냅니다. input-filesignature-file을 서명할 파일의 로컬 경로와 서명 파일을 대체합니다.

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

C#

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


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

public class SignAsymmetricSample
{
    public byte[] SignAsymmetric(
      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);

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

        // Calculate the digest.
        SHA256 sha256 = SHA256.Create();
        byte[] hash = sha256.ComputeHash(plaintext);

        // Build the digest.
        //
        // Note: Key algorithms will require a varying hash function. For
        // example, EC_SIGN_P384_SHA384 requires SHA-384.
        Digest digest = new Digest
        {
            Sha256 = ByteString.CopyFrom(hash),
        };

        // Call the API.
        AsymmetricSignResponse result = client.AsymmetricSign(keyVersionName, digest);

        // Get the signature.
        byte[] signature = result.Signature.ToByteArray();

        // Return the result.
        return signature;
    }
}

Go

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

import (
	"context"
	"crypto/sha256"
	"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"
)

// signAsymmetric will sign a plaintext message using a saved asymmetric private
// key stored in Cloud KMS.
func signAsymmetric(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 := "my 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()

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

	// Calculate the digest of the message.
	digest := sha256.New()
	if _, err := digest.Write(plaintext); err != nil {
		return fmt.Errorf("failed to create digest: %w", err)
	}

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