Creating and validating digital signatures

This topic provides information about creating and validating digital signaturesbased on asymmetric keys.

A digital signature is created using the private key portion of an asymmetrickey. The signature is validated using the public key portion of the sameasymmetric key.

Before you begin

  • When creating digital signatures, you must use a key that has thekey purpose ofASYMMETRIC_SIGN. When youcreate the key, useASYMMETRIC_SIGN.

  • To validate a signature, you need to know the fullalgorithm that wasused when creating the key. For command-line instructions below that use theopenssl command, you need to pass this information to those commands.

  • Grant thecloudkms.cryptoKeyVersions.useToSign permission on the asymmetrickey to the user or service that will perform the signing. You can learn aboutpermissions in Cloud Key Management Service atPermissions and roles.

  • If you are going to validate a signature, grantcloudkms.cryptoKeyVersions.viewPublicKey permission on the asymmetric key tothe user or service that will download the public key to use for validation.

  • If you are going to use the command line, installOpenSSL if you do notalready have it. If you useCloud Shell, OpenSSL is already installed.

Data versus digest

The input provided forAsymmetricSign requests can be passed through thedata field or thedigest field. These fields cannot be both specified atthe same time. There are some algorithms that require the data field, such asraw algorithms and signingwith aCloud External Key Manager key.

Raw algorithms

"Raw" algorithms, identified by theRSA_SIGN_RAW_ prefix, are avariant of PKCS #1 signing that omits encoding into a DigestInfo. In thevariant:

  • A digest is computed over the message that will be signed.
  • PKCS #1 padding is applied to the digest directly.
  • A signature of the padded digest is computed, using the RSA private key.

To use these algorithms:

  • The raw data needs to be provided (instead of a digest) as part of thedatafield.
  • The data has a length limit of 11 bytes fewer than the RSA key size. Forexample, PKCS #1 with a 2048-bit RSA key can sign at most 245 bytes.
  • Grant thecloudkms.expertRawPKCS1 role to the appropriate user or service.You can learn about permissions in Cloud Key Management Service atPermissions and roles.

By using raw algorithms, you can also sign a digest type for whicha predefined algorithm is not available. For example, you can use anRSA_SIGN_RAW_2048 key to sign aSHA-512 PKCS #1 DigestInfo structure thatyou already computed externally. This process creates the same results asa standardRSA_SIGN_PKCS1_2048_SHA512 algorithm.

ECDSA support for other hash algorithms

Our ECDSA signingalgorithms have the general format:

EC_SIGN_ELLIPTIC_CURVE_[DIGEST_ALGORITHM]

DIGEST_ALGORITHM has the valueSHA256,SHA384, orSHA512.Because the hash is performed before you create the signature, these signingalgorithms can also be used with digests other than SHA, such as Keccak. To usea Keccak digest, provide a Keccak hash value and use the SHA digest algorithmwith the same length. For example, you can use aKECCAK256 digest in a requestwith theEC_SIGN_P256_SHA256 algorithm.

Creating a signature

gcloud

To use Cloud KMS on the command line, firstInstall or upgrade to the latest version of Google Cloud CLI.

gcloud kms asymmetric-sign \    --versionkey-version \    --keykey \    --keyringkey-ring \    --locationlocation \    --digest-algorithmdigest-algorithm \    --input-fileinput-file \    --signature-filesignature-file

Replacekey-version with the version of the key to to use for signing.Replacekey with the key name. Replacekey-ring withthe name of the key ring where the key is located. Replacelocationwith the Cloud KMS location the key ring. Replacedigest-algorithm with the algorithm to use. Omitdigest-algorithm to sendinput-file toCloud KMS to sign. Replaceinput-file andsignature-file with the local paths for the file to sign and thesignature file.

For information on all flags and possible values, run the command with the--help flag.

C#

To run this code, firstset up a C# development environment andinstall the Cloud KMS C# SDK.

usingGoogle.Cloud.Kms.V1;usingGoogle.Protobuf;usingSystem.Security.Cryptography;usingSystem.Text;publicclassSignAsymmetricSample{publicbyte[]SignAsymmetric(stringprojectId="my-project",stringlocationId="us-east1",stringkeyRingId="my-key-ring",stringkeyId="my-key",stringkeyVersionId="123",stringmessage="Sample message"){// Create the client.KeyManagementServiceClientclient=KeyManagementServiceClient.Create();// Build the key version name.CryptoKeyVersionNamekeyVersionName=newCryptoKeyVersionName(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.SHA256sha256=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.Digestdigest=newDigest{Sha256=ByteString.CopyFrom(hash),};// Call the API.AsymmetricSignResponseresult=client.AsymmetricSign(keyVersionName,digest);// Get the signature.byte[]signature=result.Signature.ToByteArray();// Return the result.returnsignature;}}

Go

To run this code, firstset up a Go development environment andinstall the 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.funcsignAsymmetric(wio.Writer,namestring,messagestring)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)iferr!=nil{returnfmt.Errorf("failed to create kms client: %w",err)}deferclient.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{returnfmt.Errorf("failed to create digest: %w",err)}// Optional but recommended: Compute digest's CRC32C.crc32c:=func(data[]byte)uint32{t:=crc32.MakeTable(crc32.Castagnoli)returncrc32.Checksum(data,t)}digestCRC32C:=crc32c(digest.Sum(nil))// Build the signing request.//// Note: Key algorithms will require a varying hash function. For example,// EC_SIGN_P384_SHA384 requires SHA-384.req:=&kmspb.AsymmetricSignRequest{Name:name,Digest:&kmspb.Digest{Digest:&kmspb.Digest_Sha256{Sha256:digest.Sum(nil),},},DigestCrc32C:wrapperspb.Int64(int64(digestCRC32C)),}// Call the API.result,err:=client.AsymmetricSign(ctx,req)iferr!=nil{returnfmt.Errorf("failed to sign digest: %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-guidelinesifresult.VerifiedDigestCrc32C==false{returnfmt.Errorf("AsymmetricSign: request corrupted in-transit")}ifresult.Name!=req.Name{returnfmt.Errorf("AsymmetricSign: request corrupted in-transit")}ifint64(crc32c(result.Signature))!=result.SignatureCrc32C.Value{returnfmt.Errorf("AsymmetricSign: response corrupted in-transit")}fmt.Fprintf(w,"Signed digest: %s",result.Signature)returnnil}

Java

To run this code, firstset up a Java development environment andinstall the Cloud KMS Java SDK.

importcom.google.cloud.kms.v1.AsymmetricSignResponse;importcom.google.cloud.kms.v1.CryptoKeyVersionName;importcom.google.cloud.kms.v1.Digest;importcom.google.cloud.kms.v1.KeyManagementServiceClient;importcom.google.protobuf.ByteString;importjava.io.IOException;importjava.nio.charset.StandardCharsets;importjava.security.GeneralSecurityException;importjava.security.MessageDigest;publicclassSignAsymmetric{publicvoidsignAsymmetric()throwsIOException,GeneralSecurityException{// TODO(developer): Replace these variables before running the sample.StringprojectId="your-project-id";StringlocationId="us-east1";StringkeyRingId="my-key-ring";StringkeyId="my-key";StringkeyVersionId="123";Stringmessage="my message";signAsymmetric(projectId,locationId,keyRingId,keyId,keyVersionId,message);}// Get the public key associated with an asymmetric key.publicvoidsignAsymmetric(StringprojectId,StringlocationId,StringkeyRingId,StringkeyId,StringkeyVersionId,Stringmessage)throwsIOException,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(KeyManagementServiceClientclient=KeyManagementServiceClient.create()){// Build the key version name from the project, location, key ring, key,// and key version.CryptoKeyVersionNamekeyVersionName=CryptoKeyVersionName.of(projectId,locationId,keyRingId,keyId,keyVersionId);// Convert the message into bytes. Cryptographic plaintexts and// ciphertexts are always byte arrays.byte[]plaintext=message.getBytes(StandardCharsets.UTF_8);// Calculate the digest.MessageDigestsha256=MessageDigest.getInstance("SHA-256");byte[]hash=sha256.digest(plaintext);// Build the digest object.Digestdigest=Digest.newBuilder().setSha256(ByteString.copyFrom(hash)).build();// Sign the digest.AsymmetricSignResponseresult=client.asymmetricSign(keyVersionName,digest);// Get the signature.byte[]signature=result.getSignature().toByteArray();System.out.printf("Signature %s%n",signature);}}}

Node.js

To run this code, firstset up a Node.js development environment andinstall the 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 message = Buffer.from('...');// Imports the Cloud KMS libraryconst{KeyManagementServiceClient}=require('@google-cloud/kms');// Instantiates a clientconstclient=newKeyManagementServiceClient();// Build the version nameconstversionName=client.cryptoKeyVersionPath(projectId,locationId,keyRingId,keyId,versionId);asyncfunctionsignAsymmetric(){// Create a digest of the message. The digest needs to match the digest// configured for the Cloud KMS key.constcrypto=require('crypto');consthash=crypto.createHash('sha256');hash.update(message);constdigest=hash.digest();// Optional but recommended: Compute digest's CRC32C.// Ensure fast-crc32c has been installed, `npm i fast-crc32c`.constcrc32c=require('fast-crc32c');constdigestCrc32c=crc32c.calculate(digest);// Sign the message with Cloud KMSconst[signResponse]=awaitclient.asymmetricSign({name:versionName,digest:{sha256:digest,},digestCrc32c:{value:digestCrc32c,},});// Optional, but recommended: perform integrity verification on signResponse.// For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit:// https://cloud.google.com/kms/docs/data-integrity-guidelinesif(signResponse.name!==versionName){thrownewError('AsymmetricSign: request corrupted in-transit');}if(!signResponse.verifiedDigestCrc32c){thrownewError('AsymmetricSign: request corrupted in-transit');}if(crc32c.calculate(signResponse.signature)!==Number(signResponse.signatureCrc32c.value)){thrownewError('AsymmetricSign: response corrupted in-transit');}// 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.constencoded=signResponse.signature.toString('base64');console.log(`Signature:${encoded}`);returnsignResponse.signature;}returnsignAsymmetric();

PHP

To run this code, first learn aboutusing PHP on Google Cloud andinstall the Cloud KMS PHP SDK.

use Google\Cloud\Kms\V1\AsymmetricSignRequest;use Google\Cloud\Kms\V1\Client\KeyManagementServiceClient;use Google\Cloud\Kms\V1\Digest;function sign_asymmetric(    string $projectId = 'my-project',    string $locationId = 'us-east1',    string $keyRingId = 'my-key-ring',    string $keyId = 'my-key',    string $versionId = '123',    string $message = '...') {    // Create the Cloud KMS client.    $client = new KeyManagementServiceClient();    // Build the key version name.    $keyVersionName = $client->cryptoKeyVersionName($projectId, $locationId, $keyRingId, $keyId, $versionId);    // Calculate the hash.    $hash = hash('sha256', $message, true);    // Build the digest.    //    // Note: Key algorithms will require a varying hash function. For    // example, EC_SIGN_P384_SHA384 requires SHA-384.    $digest = (new Digest())        ->setSha256($hash);    // Call the API.    $asymmetricSignRequest = (new AsymmetricSignRequest())        ->setName($keyVersionName)        ->setDigest($digest);    $signResponse = $client->asymmetricSign($asymmetricSignRequest);    printf('Signature: %s' . PHP_EOL, $signResponse->getSignature());    return $signResponse;}

Python

To run this code, firstset up a Python development environment andinstall the Cloud KMS Python SDK.

# Import base64 for printing the ciphertext.importbase64# Import hashlib for calculating hashes.importhashlib# Import the client library.fromgoogle.cloudimportkmsdefsign_asymmetric(project_id:str,location_id:str,key_ring_id:str,key_id:str,version_id:str,message:str,)->kms.AsymmetricSignResponse:"""    Sign a message using the private 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').        message (string): Message to sign.    Returns:        AsymmetricSignResponse: Signature.    """# 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.message_bytes=message.encode("utf-8")# Calculate the hash.hash_=hashlib.sha256(message_bytes).digest()# Build the digest.## Note: Key algorithms will require a varying hash function. For# example, EC_SIGN_P384_SHA384 requires SHA-384.digest={"sha256":hash_}# Optional, but recommended: compute digest's CRC32C.# See crc32c() function defined below.digest_crc32c=crc32c(hash_)# Call the APIsign_response=client.asymmetric_sign(request={"name":key_version_name,"digest":digest,"digest_crc32c":digest_crc32c,})# Optional, but recommended: perform integrity verification on sign_response.# For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit:# https://cloud.google.com/kms/docs/data-integrity-guidelinesifnotsign_response.verified_digest_crc32c:raiseException("The request sent to the server was corrupted in-transit.")ifnotsign_response.name==key_version_name:raiseException("The request sent to the server was corrupted in-transit.")ifnotsign_response.signature_crc32c==crc32c(sign_response.signature):raiseException("The response received from the server was corrupted in-transit.")# End integrity verificationprint(f"Signature:{base64.b64encode(sign_response.signature)!r}")returnsign_responsedefcrc32c(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.    """importcrcmod# type: ignorecrc32c_fun=crcmod.predefined.mkPredefinedCrcFun("crc-32c")returncrc32c_fun(data)

Ruby

To run this code, firstset up a Ruby development environment andinstall the 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"# message     = "my message"# 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_pathproject:project_id,location:location_id,key_ring:key_ring_id,crypto_key:key_id,crypto_key_version:version_id# Calculate the hash.## Note: Key algorithms will require a varying hash function. For# example, EC_SIGN_P384_SHA384 requires SHA-384.digest={sha256:Digest::SHA256.digest(message)}# Call the API.sign_response=client.asymmetric_signname:key_version_name,digest:digestputs"Signature:#{Base64.strict_encode64sign_response.signature}"

API

These examples usecurl as an HTTP client to demonstrate using the API. For more information about access control, seeAccessing the Cloud KMS API.

Use theCryptoKeyVersions.asymmetricSignmethod to perform the signing. The response from this method contains thebase64-encoded signature.

Tip: You can base64-encode or decode datausing thebase64 command on Linux or macOS, or theBase64.exe command on Windows. Programming and scriptinglanguages typically include libraries for base64-encoding. For command-lineexamples, seeBase64 Encoding in theCloud Vision API documentation.

Validating an elliptic curve signature

gcloud

To use Cloud KMS on the command line, firstInstall or upgrade to the latest version of Google Cloud CLI.

Get the public key

gcloud kms keys versions get-public-keykey-version \    --keykey \    --keyringkey-ring \    --locationlocation \    --output-fileoutput-file

Replacekey-version with the key version. Replacekey withthe name of the key. Replacekey-ring with the name of the key ringwhere the key is located. Replacelocation with theCloud KMS location for the key ring. Replaceoutput-filewith the file path to save the public key on the local system.

For information on all flags and possible values, run the command with the--help flag.

Verify the signature

The OpenSSL commands to validate the signature depend on what signaturetype was created. For example, to validate a SHA-256 elliptic curvesignature using OpenSSL, you must specify-sha256. To validate a SHA-384elliptical curve signature, you must specify-sha384.

openssl dgst \    -sha256 \    -verifypublic-key-file \    -signaturesignature-file \message-file

Replace the variables with your own values:

  • public-key-file. Path to a file that contains the public key(e.g."./my-key.pub").

  • signature-file. Path to a file that contains the signature toverify (e.g."./my-data.sig").

  • message-file. Path to a file that contains the message (e.g."./my-data.txt").

If the signature is valid, the command outputs the stringVerified OK.

For information on all flags and possible values, run the command with thehelp subcommand.

C#

To run this code, firstset up a C# development environment andinstall the Cloud KMS C# SDK.

publicclassVerifyAsymmetricSignatureEcSample{// Cloud KMS returns signatures in a DER-encoded format. .NET requires// signatures to be in IEEE 1363 format, and converting between these formats// is a few hundred lines of code.//// https://github.com/dotnet/runtime/pull/1612 exposes these helpers, but will// not be available until .NET 5. Until then, you will need to use an external// library or package to validate signatures.}

Go

To run this code, firstset up a Go development environment andinstall the Cloud KMS Go SDK.

import("context""crypto/ecdsa""crypto/sha256""crypto/x509""encoding/asn1""encoding/pem""fmt""io""math/big"kms"cloud.google.com/go/kms/apiv1""cloud.google.com/go/kms/apiv1/kmspb")// verifyAsymmetricSignatureEC will verify that an 'EC_SIGN_P256_SHA256' signature is// valid for a given message.funcverifyAsymmetricSignatureEC(wio.Writer,namestring,message,signature[]byte)error{// name := "projects/my-project/locations/us-east1/keyRings/my-key-ring/cryptoKeys/my-key/cryptoKeyVersions/123"// message := "my message"// signature := []byte("...")  // Response from a sign request// Create the client.ctx:=context.Background()client,err:=kms.NewKeyManagementClient(ctx)iferr!=nil{returnfmt.Errorf("failed to create kms client: %w",err)}deferclient.Close()// Retrieve the public key from KMS.response,err:=client.GetPublicKey(ctx,&kmspb.GetPublicKeyRequest{Name:name})iferr!=nil{returnfmt.Errorf("failed to get public key: %w",err)}// Parse the public key. Note, this example assumes the public key is in the// ECDSA format.block,_:=pem.Decode([]byte(response.Pem))publicKey,err:=x509.ParsePKIXPublicKey(block.Bytes)iferr!=nil{returnfmt.Errorf("failed to parse public key: %w",err)}ecKey,ok:=publicKey.(*ecdsa.PublicKey)if!ok{returnfmt.Errorf("public key is not elliptic curve")}// Verify Elliptic Curve signature.varparsedSigstruct{R,S*big.Int}if_,err=asn1.Unmarshal(signature,&parsedSig);err!=nil{returnfmt.Errorf("asn1.Unmarshal: %w",err)}digest:=sha256.Sum256(message)if!ecdsa.Verify(ecKey,digest[:],parsedSig.R,parsedSig.S){returnfmt.Errorf("failed to verify signature")}fmt.Fprintf(w,"Verified signature!")returnnil}

Java

To run this code, firstset up a Java development environment andinstall the Cloud KMS Java SDK.

importcom.google.cloud.kms.v1.CryptoKeyVersionName;importcom.google.cloud.kms.v1.KeyManagementServiceClient;importcom.google.cloud.kms.v1.PublicKey;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.StringReader;importjava.nio.charset.StandardCharsets;importjava.security.GeneralSecurityException;importjava.security.KeyFactory;importjava.security.Signature;importjava.security.spec.X509EncodedKeySpec;importjava.util.Base64;importjava.util.stream.Collectors;publicclassVerifyAsymmetricEc{publicvoidverifyAsymmetricEc()throwsIOException,GeneralSecurityException{// TODO(developer): Replace these variables before running the sample.StringprojectId="your-project-id";StringlocationId="us-east1";StringkeyRingId="my-key-ring";StringkeyId="my-key";StringkeyVersionId="123";Stringmessage="my message";byte[]signature=null;verifyAsymmetricEc(projectId,locationId,keyRingId,keyId,keyVersionId,message,signature);}// Verify the signature of a message signed with an RSA key.publicvoidverifyAsymmetricEc(StringprojectId,StringlocationId,StringkeyRingId,StringkeyId,StringkeyVersionId,Stringmessage,byte[]signature)throwsIOException,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(KeyManagementServiceClientclient=KeyManagementServiceClient.create()){// Build the name from the project, location, and key ring, key, and key version.CryptoKeyVersionNamekeyVersionName=CryptoKeyVersionName.of(projectId,locationId,keyRingId,keyId,keyVersionId);// Convert the message into bytes. Cryptographic plaintexts and// ciphertexts are always byte arrays.byte[]plaintext=message.getBytes(StandardCharsets.UTF_8);// Get the public key.PublicKeypublicKey=client.getPublicKey(keyVersionName);// Convert the public PEM key to a DER key (see helper below).byte[]derKey=convertPemToDer(publicKey.getPem());X509EncodedKeySpeckeySpec=newX509EncodedKeySpec(derKey);java.security.PublicKeyecKey=KeyFactory.getInstance("EC").generatePublic(keySpec);// Verify the 'RSA_SIGN_PKCS1_2048_SHA256' signature.// For other key algorithms:// http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SignatureSignatureecVerify=Signature.getInstance("SHA256withECDSA");ecVerify.initVerify(ecKey);ecVerify.update(plaintext);// Verify the signature.booleanverified=ecVerify.verify(signature);System.out.printf("Signature verified: %s",verified);}}// Converts a base64-encoded PEM certificate like the one returned from Cloud// KMS into a DER formatted certificate for use with the Java APIs.privatebyte[]convertPemToDer(Stringpem){BufferedReaderbufferedReader=newBufferedReader(newStringReader(pem));Stringencoded=bufferedReader.lines().filter(line->!line.startsWith("-----BEGIN") &&!line.startsWith("-----END")).collect(Collectors.joining());returnBase64.getDecoder().decode(encoded);}}

Node.js

To run this code, firstset up a Node.js development environment andinstall the 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 = '1';// const message = 'my message to verify';// const signatureBuffer = Buffer.from('...');// Imports the Cloud KMS libraryconst{KeyManagementServiceClient}=require('@google-cloud/kms');// Instantiates a clientconstclient=newKeyManagementServiceClient();// Build the key nameconstversionName=client.cryptoKeyVersionPath(projectId,locationId,keyRingId,keyId,versionId);asyncfunctionverifyAsymmetricSignatureEc(){// Get public keyconst[publicKey]=awaitclient.getPublicKey({name:versionName,});// Create the verifier. The algorithm must match the algorithm of the key.constcrypto=require('crypto');constverify=crypto.createVerify('sha256');verify.update(message);verify.end();// Build the key objectconstkey={key:publicKey.pem,};// Verify the signature using the public keyconstverified=verify.verify(key,signatureBuffer);returnverified;}returnverifyAsymmetricSignatureEc();

PHP

To run this code, first learn aboutusing PHP on Google Cloud andinstall the Cloud KMS PHP SDK.

use Google\Cloud\Kms\V1\Client\KeyManagementServiceClient;use Google\Cloud\Kms\V1\GetPublicKeyRequest;function verify_asymmetric_ec(    string $projectId = 'my-project',    string $locationId = 'us-east1',    string $keyRingId = 'my-key-ring',    string $keyId = 'my-key',    string $versionId = '123',    string $message = '...',    string $signature = '...'): bool {    // Create the Cloud KMS client.    $client = new KeyManagementServiceClient();    // Build the key version name.    $keyVersionName = $client->cryptoKeyVersionName($projectId, $locationId, $keyRingId, $keyId, $versionId);    // Get the public key.    $getPublicKeyRequest = (new GetPublicKeyRequest())        ->setName($keyVersionName);    $publicKey = $client->getPublicKey($getPublicKeyRequest);    // Verify the signature. The hash algorithm must correspond to the key    // algorithm. The openssl_verify command returns 1 on success, 0 on falure.    $verified = openssl_verify($message, $signature, $publicKey->getPem(), OPENSSL_ALGO_SHA256) === 1;    printf('Signature verified: %s', $verified);    return $verified;}

Python

To run this code, firstset up a Python development environment andinstall the Cloud KMS Python SDK.

# Import hashlib.importhashlib# Import cryptographic helpers from the cryptography package.fromcryptography.exceptionsimportInvalidSignaturefromcryptography.hazmat.backendsimportdefault_backendfromcryptography.hazmat.primitivesimporthashesfromcryptography.hazmat.primitivesimportserializationfromcryptography.hazmat.primitives.asymmetricimportecfromcryptography.hazmat.primitives.asymmetricimportutils# Import the client library.fromgoogle.cloudimportkmsdefverify_asymmetric_ec(project_id:str,location_id:str,key_ring_id:str,key_id:str,version_id:str,message:str,signature:str,)->bool:"""    Verify the signature of an message signed with an asymmetric EC 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 version to use (e.g. '1').        message (string): Original message (e.g. 'my message')        signature (bytes): Signature from a sign request.    Returns:        bool: True if verified, False otherwise    """# Convert the message to bytes.message_bytes=message.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 EC key.pem=public_key.pem.encode("utf-8")ec_key=serialization.load_pem_public_key(pem,default_backend())hash_=hashlib.sha256(message_bytes).digest()# Attempt to verify.try:sha256=hashes.SHA256()ec_key.verify(signature,hash_,ec.ECDSA(utils.Prehashed(sha256)))print("Signature verified")returnTrueexceptInvalidSignature:print("Signature failed to verify")returnFalse

Ruby

To run this code, firstset up a Ruby development environment andinstall the 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"# message     = "my message"# signature   = "..."# Require the library.require"google/cloud/kms"require"openssl"# Create the client.client=Google::Cloud::Kms.key_management_service# Build the key version name.key_version_name=client.crypto_key_version_pathproject:project_id,location:location_id,key_ring:key_ring_id,crypto_key:key_id,crypto_key_version:version_id# Get the public key.public_key=client.get_public_keyname:key_version_name# Parse the public key.ec_key=OpenSSL::PKey::EC.newpublic_key.pem# Verify the signature.verified=ec_key.verify"sha256",signature,messageputs"Verified:#{verified}"

API

These examples usecurl as an HTTP client to demonstrate using the API. For more information about access control, seeAccessing the Cloud KMS API.

Use theCryptoKeyVersions.getPublicKeymethod to retrieve the public key, and then use the commands shown for thecommand-line example to validate the signature.

Validating an RSA signature

gcloud

To use Cloud KMS on the command line, firstInstall or upgrade to the latest version of Google Cloud CLI.

Get the public key

gcloud kms keys versions get-public-keykey-version \    --keykey \    --keyringkey-ring \    --locationlocation \    --output-fileoutput-file

Replacekey-version with the key version. Replacekey withthe name of the key. Replacekey-ring with the name of the key ringwhere the key is located. Replacelocation with theCloud KMS location for the key ring. Replaceoutput-filewith the path to save the public key on the local system.

For information on all flags and possible values, run the command with the--help flag.

Verify the signature

The OpenSSL commands to validate the signature depend on what signature type wascreated. For example, to validate a SHA-256 RSA signature with PSS padding, youmust specify-sha256 and-sigopt rsa_padding_mode:pss. To validate a SHA-512RSA signature with PSS padding, you must specify-sha512 and-sigoptrsa_padding_mode:pss.

openssl dgst \    -sha256 \    -sigopt rsa_padding_mode:pss \    -sigopt rsa_pss_saltlen:-1 \    -verifypublic-key-file \    -signaturesignature-file \message-file

Replace the variables with your own values:

  • public-key-file. Path to a file that contains the public key(e.g."./my-key.pub").

  • signature-file. Path to a file that contains the signature toverify (e.g."./my-data.sig").

  • message-file. Path to a file that contains the message (e.g."./my-data.txt").

If the signature is valid, the command outputs the stringVerified OK.

For information on all flags and possible values, run the command with thehelp subcommand.

C#

To run this code, firstset up a C# development environment andinstall the Cloud KMS C# SDK.

usingGoogle.Cloud.Kms.V1;usingSystem;usingSystem.Security.Cryptography;usingSystem.Text;publicclassVerifyAsymmetricSignatureRsaSample{publicboolVerifyAsymmetricSignatureRsa(stringprojectId="my-project",stringlocationId="us-east1",stringkeyRingId="my-key-ring",stringkeyId="my-key",stringkeyVersionId="123",stringmessage="my message",byte[]signature=null){// Build the key version name.CryptoKeyVersionNamekeyVersionName=newCryptoKeyVersionName(projectId,locationId,keyRingId,keyId,keyVersionId);// Calculate the digest of the message.SHA256sha256=SHA256.Create();byte[]digest=sha256.ComputeHash(Encoding.UTF8.GetBytes(message));// Get the public key.KeyManagementServiceClientclient=KeyManagementServiceClient.Create();PublicKeypublicKey=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.RSArsa=RSA.Create();rsa.ImportSubjectPublicKeyInfo(pem,out_);// Verify the signature.boolverified=rsa.VerifyHash(digest,signature,HashAlgorithmName.SHA256,RSASignaturePadding.Pss);// Return the result.returnverified;}}

Go

To run this code, firstset up a Go development environment andinstall the Cloud KMS Go SDK.

import("context""crypto""crypto/rsa""crypto/sha256""crypto/x509""encoding/pem""fmt""io"kms"cloud.google.com/go/kms/apiv1""cloud.google.com/go/kms/apiv1/kmspb")// verifyAsymmetricSignatureRSA will verify that an 'RSA_SIGN_PSS_2048_SHA256' signature// is valid for a given message.funcverifyAsymmetricSignatureRSA(wio.Writer,namestring,message,signature[]byte)error{// name := "projects/my-project/locations/us-east1/keyRings/my-key-ring/cryptoKeys/my-key/cryptoKeyVersions/123"// message := "my message"// signature := []byte("...")  // Response from a sign request// Create the client.ctx:=context.Background()client,err:=kms.NewKeyManagementClient(ctx)iferr!=nil{returnfmt.Errorf("failed to create kms client: %w",err)}deferclient.Close()// Retrieve the public key from KMS.response,err:=client.GetPublicKey(ctx,&kmspb.GetPublicKeyRequest{Name:name})iferr!=nil{returnfmt.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)iferr!=nil{returnfmt.Errorf("failed to parse public key: %w",err)}rsaKey,ok:=publicKey.(*rsa.PublicKey)if!ok{returnfmt.Errorf("public key is not rsa")}// Verify the RSA signature.digest:=sha256.Sum256(message)iferr:=rsa.VerifyPSS(rsaKey,crypto.SHA256,digest[:],signature,&rsa.PSSOptions{SaltLength:len(digest),Hash:crypto.SHA256,});err!=nil{returnfmt.Errorf("failed to verify signature: %w",err)}fmt.Fprint(w,"Verified signature!\n")returnnil}

Java

To run this code, firstset up a Java development environment andinstall the Cloud KMS Java SDK.

importcom.google.cloud.kms.v1.CryptoKeyVersionName;importcom.google.cloud.kms.v1.KeyManagementServiceClient;importcom.google.cloud.kms.v1.PublicKey;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.StringReader;importjava.nio.charset.StandardCharsets;importjava.security.GeneralSecurityException;importjava.security.KeyFactory;importjava.security.Signature;importjava.security.spec.X509EncodedKeySpec;importjava.util.Base64;importjava.util.stream.Collectors;publicclassVerifyAsymmetricRsa{publicvoidverifyAsymmetricRsa()throwsIOException,GeneralSecurityException{// TODO(developer): Replace these variables before running the sample.StringprojectId="your-project-id";StringlocationId="us-east1";StringkeyRingId="my-key-ring";StringkeyId="my-key";StringkeyVersionId="123";Stringmessage="my message";byte[]signature=null;verifyAsymmetricRsa(projectId,locationId,keyRingId,keyId,keyVersionId,message,signature);}// Verify the signature of a message signed with an RSA key.publicvoidverifyAsymmetricRsa(StringprojectId,StringlocationId,StringkeyRingId,StringkeyId,StringkeyVersionId,Stringmessage,byte[]signature)throwsIOException,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(KeyManagementServiceClientclient=KeyManagementServiceClient.create()){// Build the name from the project, location, and key ring, key, and key version.CryptoKeyVersionNamekeyVersionName=CryptoKeyVersionName.of(projectId,locationId,keyRingId,keyId,keyVersionId);// Convert the message into bytes. Cryptographic plaintexts and// ciphertexts are always byte arrays.byte[]plaintext=message.getBytes(StandardCharsets.UTF_8);// Get the public key.PublicKeypublicKey=client.getPublicKey(keyVersionName);// Convert the public PEM key to a DER key (see helper below).byte[]derKey=convertPemToDer(publicKey.getPem());X509EncodedKeySpeckeySpec=newX509EncodedKeySpec(derKey);java.security.PublicKeyrsaKey=KeyFactory.getInstance("RSA").generatePublic(keySpec);// Verify the 'RSA_SIGN_PKCS1_2048_SHA256' signature.// For other key algorithms:// http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SignatureSignaturersaVerify=Signature.getInstance("SHA256withRSA");rsaVerify.initVerify(rsaKey);rsaVerify.update(plaintext);// Verify the signature.booleanverified=rsaVerify.verify(signature);System.out.printf("Signature verified: %s",verified);}}// Converts a base64-encoded PEM certificate like the one returned from Cloud// KMS into a DER formatted certificate for use with the Java APIs.privatebyte[]convertPemToDer(Stringpem){BufferedReaderbufferedReader=newBufferedReader(newStringReader(pem));Stringencoded=bufferedReader.lines().filter(line->!line.startsWith("-----BEGIN") &&!line.startsWith("-----END")).collect(Collectors.joining());returnBase64.getDecoder().decode(encoded);}}

Node.js

To run this code, firstset up a Node.js development environment andinstall the 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 = '1';// const message = 'my message to verify';// const signatureBuffer = Buffer.from('...');// Imports the Cloud KMS libraryconst{KeyManagementServiceClient}=require('@google-cloud/kms');// Instantiates a clientconstclient=newKeyManagementServiceClient();// Build the key nameconstversionName=client.cryptoKeyVersionPath(projectId,locationId,keyRingId,keyId,versionId);asyncfunctionverifyAsymmetricSignatureRsa(){// Get public keyconst[publicKey]=awaitclient.getPublicKey({name:versionName,});// Create the verifier. The algorithm must match the algorithm of the key.constcrypto=require('crypto');constverify=crypto.createVerify('sha256');verify.update(message);verify.end();// Build the key objectconstkey={key:publicKey.pem,padding:crypto.constants.RSA_PKCS1_PSS_PADDING,};// Verify the signature using the public keyconstverified=verify.verify(key,signatureBuffer);returnverified;}returnverifyAsymmetricSignatureRsa();

PHP

To run this code, first learn aboutusing PHP on Google Cloud andinstall the Cloud KMS PHP SDK.

function verify_asymmetric_rsa(    string $projectId = 'my-project',    string $locationId = 'us-east1',    string $keyRingId = 'my-key-ring',    string $keyId = 'my-key',    string $versionId = '123',    string $message = '...',    string $signature = '...'): 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

To run this code, firstset up a Python development environment andinstall the Cloud KMS Python SDK.

# Import hashlib.importhashlib# Import cryptographic helpers from the cryptography package.fromcryptography.exceptionsimportInvalidSignaturefromcryptography.hazmat.backendsimportdefault_backendfromcryptography.hazmat.primitivesimporthashesfromcryptography.hazmat.primitivesimportserializationfromcryptography.hazmat.primitives.asymmetricimportpaddingfromcryptography.hazmat.primitives.asymmetricimportutils# Import the client library.fromgoogle.cloudimportkmsdefverify_asymmetric_rsa(project_id:str,location_id:str,key_ring_id:str,key_id:str,version_id:str,message:str,signature:str,)->bool:"""    Verify the signature of an message signed with an asymmetric RSA 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 version to use (e.g. '1').        message (string): Original message (e.g. 'my message')        signature (bytes): Signature from a sign request.    Returns:        bool: True if verified, False otherwise    """# Convert the message to bytes.message_bytes=message.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())hash_=hashlib.sha256(message_bytes).digest()# Attempt to verify.try:sha256=hashes.SHA256()pad=padding.PKCS1v15()rsa_key.verify(signature,hash_,pad,utils.Prehashed(sha256))print("Signature verified")returnTrueexceptInvalidSignature:print("Signature failed to verify")returnFalse

Ruby

To run this code, firstset up a Ruby development environment andinstall the 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"# message     = "my message"# signature   = "..."# Require the library.require"google/cloud/kms"require"openssl"# Create the client.client=Google::Cloud::Kms.key_management_service# Build the key version name.key_version_name=client.crypto_key_version_pathproject:project_id,location:location_id,key_ring:key_ring_id,crypto_key:key_id,crypto_key_version:version_id# Get the public key.public_key=client.get_public_keyname:key_version_name# Parse the public key.rsa_key=OpenSSL::PKey::RSA.newpublic_key.pem# Verify the signature.## Note: The verify_pss() method only exists in Ruby 2.5+.verified=rsa_key.verify_pss"sha256",signature,message,salt_length::digest,mgf1_hash:"sha256"puts"Verified:#{verified}"

API

These examples usecurl as an HTTP client to demonstrate using the API. For more information about access control, seeAccessing the Cloud KMS API.

Use theCryptoKeyVersions.getPublicKeymethod to retrieve the public key, and then use the commands shown for thecommand-line example to validate the signature.

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-12-17 UTC.