Yandex Cloud
Search
Contact UsGet started
  • Blog
  • Pricing
  • Documentation
  • All Services
  • System Status
    • Featured
    • Infrastructure & Network
    • Data Platform
    • Containers
    • Developer tools
    • Serverless
    • Security
    • Monitoring & Resources
    • ML & AI
    • Business tools
  • All Solutions
    • By industry
    • By use case
    • Economics and Pricing
    • Security
    • Technical Support
    • Customer Stories
    • Gateway to Russia
    • Cloud for Startups
    • Education and Science
  • Blog
  • Pricing
  • Documentation
Yandex project
© 2025 Yandex.Cloud LLC
Yandex Key Management Service
  • Getting started
    • Overview
      • Digital signature key pair
      • Digital signature
    • Envelope encryption
    • Key consistency
    • Quotas and limits
  • Access management
  • Pricing policy
  • Terraform reference
  • Monitoring metrics
  • Audit Trails events
  • FAQ

In this article:

  • Using a digital signature
  • Supported digital signature algorithms
  • Verifying digital signatures
  • ECDSA signature
  • RSA signature
  • Use cases
  1. Concepts
  2. Digital signature
  3. Digital signature

Digital signature in KMS

Written by
Yandex Cloud
Updated at March 31, 2025
  • Using a digital signature
    • Supported digital signature algorithms
  • Verifying digital signatures
    • ECDSA signature
    • RSA signature
  • Use cases

Digital signature is a product of a cryptographic operation that provides additional data protection. Digital signatures serve these main purposes:

  • Validating data
  • Checking data integrity
  • Protecting data against modification
  • Identifying the data source

The digital signature algorithm supports two operations: creating a signature and verifying a signature.

Digital signatures are based on asymmetric cryptography. An asymmetric key pair of a digital signature consists of two parts: a public key and a private key. The private key is used to create a signature and the public key to verify it.

You can use a digital signature to validate the source code, binary files, and container images. For example, you can validate an image signed with a digital signature. If the verification shows that the signature is invalid, it means that the image was changed or damaged. You can also use a digital signature to verify the subject of a certificate issued by a certificate authority.

Each key pair counts towards KMS quotas as a single key.

Using a digital signatureUsing a digital signature

The digital signature process actors are the owner of a key pair's private key and the recipients of signed data. Digital signatures are created and verified as follows:

  1. The signature owner creates an asymmetric key pair with digital signature support.
  2. The owner creates a digital signature for their own data. At this step, a hash value of user data is calculated, which is then signed by the private key based on a specified algorithm. The employed hash function is specified in the name of the algorithm.
  3. The signature owner transmits the data, the digital signature, and the public key of the asymmetric key pair to a recipient.
  4. The recipient uses the public key to verify the digital signature.
  5. If the hash decrypted by the recipient matches that of the data, it means the signature is correct.

Supported digital signature algorithmsSupported digital signature algorithms

KMS provides ECDSA and RSA cryptographic algorithms for using digital signatures. For both encryption algorithms, you can choose key size and hashing algorithm (digest):

  • RSA_2048_SIGN_PSS_SHA_256
  • RSA_2048_SIGN_PSS_SHA_384
  • RSA_2048_SIGN_PSS_SHA_512
  • RSA_3072_SIGN_PSS_SHA_256
  • RSA_3072_SIGN_PSS_SHA_384
  • RSA_3072_SIGN_PSS_SHA_512
  • RSA_4096_SIGN_PSS_SHA_256
  • RSA_4096_SIGN_PSS_SHA_384
  • RSA_4096_SIGN_PSS_SHA_512
  • ECDSA_NIST_P256_SHA_256
  • ECDSA_NIST_P384_SHA_384
  • ECDSA_NIST_P521_SHA_512
  • ECDSA_NIST_SECP256_K1_SHA_256

Verifying digital signaturesVerifying digital signatures

Digital signature verification is performed by the side that has no access to the digital signature's private key. The signature is verified using the public key.

ECDSA signatureECDSA signature

To verify a digital signature:

  1. Get the public key of the digital signature.

  2. Perform verification:

    Bash
    Java
    Go
    Python

    Verify the digital signature using OpenSSL:

    openssl dgst \
      -<hashing_algorithm> \
      -verify <path_to_public_key_file> \
      -signature <path_to_signature_file> \
      <path_to_signed_file>
    

    Where:

    • <hashing_algorithm>: Hashing algorithm used when creating a signature key pair. The possible values include:
      • sha256 for SHA-256 algorithms
      • sha384 for SHA-384 algorithms
      • sha512 for SHA-512 algorithms
    • -verify: Path to the file with a public signature key.
    • -signature: Path to the digital signature file.
    • <path_to_signed_file>: Path to the file whose digital signature is being verified.

    If the signature is correct, the OpenSSL utility returns the Verified OK status.

    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.bouncycastle.util.io.pem.PemObject;
    import org.bouncycastle.util.io.pem.PemReader;
    
    import javax.crypto.BadPaddingException;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.NoSuchPaddingException;
    import java.io.IOException;
    import java.io.StringReader;
    import java.security.*;
    import java.security.spec.*;
    import java.util.Base64;
    
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    
    public class VerifyEcdsaSign {
    
        public static void main(String[] args) throws Exception {
            String publicKeyPem =
            """
            -- -- - BEGIN PUBLIC KEY-- -- -
            <public_key_contents>
                -- -- - END PUBLIC KEY-- -- -
            """;
            String signatureStr = "<signature_string>";
            byte[] signatureDer = Base64.getDecoder().decode(signatureStr);
            System.out.println(verifyEcdsaSignature(publicKeyPem, signatureDer, "<message_string>", "<algorithm_type>"));
        }
    
        public static boolean verifyEcdsaSignature(String publicKeyPem, byte[] signatureDer, String message, String hash_algorithm)
        throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException,
        SignatureException, IOException {
    
            // Public key and subscription decoding
            PemReader pemReader = new PemReader(new StringReader(publicKeyPem));
            PemObject pemObject = pemReader.readPemObject();
            byte[] publicKeyBytes = pemObject.getContent();
    
            // Creating a PublicKey object from the decoded public key
            KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
            EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
            PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
    
            // Creating a Signature object and initializing it with a public key
            Signature signature = Signature.getInstance(hash_algorithm + "withECDSA", new BouncyCastleProvider());
            signature.initVerify(publicKey);
    
            // Updating a Signature Object with Message Data
            byte[] messageBytes = message.getBytes();
            signature.update(messageBytes);
    
            // Signature verification using original message and decoded signature
            return signature.verify(signatureDer);
        }
    }
    

    Where:

    • <public_key_contents>: Contents of the public signature key.
    • <signature_string>: Contents of the digital signature in base64 encoding.
    • <message_string>: String with the source message signed with the digital signature or the hash of the file signed with the digital signature.
    • <algorithm_type>: Hash function used for the signature. The possible values are SHA256, SHA384, and SHA512.

    The code verifies the ECDSA signature. It returns true if the signature is correct and false if it is not.

    import (
        "crypto/ecdsa"
        "crypto/sha256"
        "crypto/x509"
        "encoding/asn1"
        "encoding/base64"
        "encoding/pem"
        "fmt"
        "hash"
        "log"
        "math/big"
    )
    
    func runEcdsaSignTest() {
        publicKeyPem := `-----BEGIN PUBLIC KEY-----
        <public_key_contents>
        -----END PUBLIC KEY-----`
        signatureB64 := "<signature_string>"
        signatureDER, _ := base64.StdEncoding.DecodeString(signatureB64)
        message := "<message_string>"
    
            fmt.Println(verifyEcdsa(publicKeyPem, signatureDER, message, <algorithm_type>))
    }
    
    type ECDSASignature struct {
        R, S *big.Int
    }
    
    func verifyEcdsa(publicKeyPem string, signatureDER []byte, message string, hashFunc hash.Hash) bool {
    
        // Decode the public key
        block, _ := pem.Decode([]byte(publicKeyPem))
        if block == nil {
            log.Fatal("failed to decode PEM block containing public key")
        }
    
        // Parse the public key
        pub, err := x509.ParsePKIXPublicKey(block.Bytes)
        if err != nil {
    	    log.Fatal(err)
        }
    
        publicKey, ok := pub.(*ecdsa.PublicKey)
        if !ok {
    	    log.Fatal("not ECDSA public key")
        }
    
        // Parse the signature
        var signature ECDSASignature
        _, err = asn1.Unmarshal(signatureDER, &signature)
        if err != nil {
    	    log.Fatal(err)
        }
    
        // Compute the hash of the message
        hashFunc.Write([]byte(message))
        hashed := hashFunc.Sum(nil)
    
        // Verify the signature
        return ecdsa.Verify(publicKey, hashed, signature.R, signature.S)
    }
    

    Where:

    • <public_key_contents>: Contents of the public signature key in base64 encoding.
    • <signature_string>: Contents of the digital signature in base64 encoding.
    • <message_string>: String with the source message signed with the digital signature or the hash of the file signed with the digital signature.
    • <algorithm_type>: Hash function used for the signature. The possible values are sha256.New(), sha512.New384(), and sha512.New().

    The code verifies the ECDSA signature. It returns true if the signature is correct and false if it is not.

    import base64
    from cryptography.hazmat.primitives import serialization
    from cryptography.hazmat.primitives.asymmetric import ec
    from cryptography.hazmat.primitives import hashes
    from cryptography.exceptions import InvalidSignature
    from cryptography.hazmat.backends import default_backend
    
    # Define hash algorithms
    def verify_ecdsa_signature(public_key_b64, signature_der, message, hash_algorithm):
        hash_algorithms = {
            'SHA256': hashes.SHA256,
            'SHA384': hashes.SHA384,
            'SHA512': hashes.SHA512
        }
    
        # Check if the provided hash algorithm is supported
        if hash_algorithm not in hash_algorithms:
            raise ValueError('Unsupported hash algorithm: ' + hash_algorithm)
    
        # Loading a PEM Encoded Public Key
        public_key = serialization.load_pem_public_key(
            public_key_b64.encode(),
            backend = default_backend()
        )
    
        # Create Signature object and initialize it with the public key
        signature = ec.ECDSA(hash_algorithms[hash_algorithm]())
    
        # Update the Signature object with the message data
        message_bytes = message.encode()
    
        # Verify the signature using the original message and the decoded signature
        try:
            public_key.verify(signature_der, message_bytes, signature)
            return True
        except InvalidSignature:
            return False
    
    def test_verify_signature():
        public_key_b64 = """
        -----BEGIN PUBLIC KEY-----
        <public_key_content>
        -----END PUBLIC KEY-----"""
        signature_b64 = "<signature>"
        signature_der = base64.b64decode(signature_b64)
        message = '<message>'
        print(verify_ecdsa_signature(public_key_b64, signature_der, message, "<algorithm_type>"))
    

    Where:

    • <public_key_contents>: Contents of the public signature key.
    • <signature_string>: Contents of the digital signature in base64 encoding.
    • <message_string>: String with the source message signed with the digital signature or the hash of the file signed with the digital signature.
    • <algorithm_type>: Hash function used for the signature. The possible values are SHA256, SHA384, and SHA512.

    The code verifies the ECDSA signature. It returns true if the signature is correct and false if it is not.

RSA signatureRSA signature

To verify a digital signature:

  1. Get the public key of the digital signature.

  2. Perform verification:

    Bash
    Java
    Go
    Python

    Verify the digital signature using OpenSSL:

    openssl dgst \
      -<hashing_algorithm> \
      -sigopt rsa_padding_mode:pss \
      -sigopt rsa_pss_saltlen:-1 \
      -verify <path_to_public_key_file> \
      -signature <path_to_signature_file> \
      <path_to_signed_file>
    

    Where:

    • <hashing_algorithm>: Hashing algorithm used when creating a signature key pair. The possible values include:
      • sha256 for SHA-256 algorithms
      • sha384 for SHA-384 algorithms
      • sha512 for SHA-512 algorithms
    • -verify: Path to the file with a public signature key.
    • -signature: Path to the digital signature file.
    • <path_to_signed_file>: Path to the file whose digital signature is being verified.

    If the signature is correct, the OpenSSL utility returns the Verified OK status.

    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.bouncycastle.util.io.pem.PemObject;
    import org.bouncycastle.util.io.pem.PemReader;
    
    import javax.crypto.BadPaddingException;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.NoSuchPaddingException;
    import java.io.IOException;
    import java.io.StringReader;
    import java.security.*;
    import java.security.spec.*;
    import java.util.Base64;
    
    public class VerifyRsaSign {
    
        public static void main(String[] args) throws Exception {
            String publicKeyPem = """
            -----BEGIN PUBLIC KEY-----
            <public_key_contents>
            -----END PUBLIC KEY-----""";
            String signatureStr = "<signature_string>";
            byte[] signatureBytes = Base64.getDecoder().decode(signatureStr);
            String message = "<message_string>";
            System.out.println(verifyRsaSignature(publicKeyPem, signatureBytes, message, "<algorithm_type>"));
        }
    
        private static boolean verifyRsaSignature(String publicKeyPem, byte[] signatureBytes, String message, String hashAlgorithm)
        throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException,
        SignatureException, InvalidAlgorithmParameterException, IOException {
    
            // Get the public key
            PemReader pemReader = new PemReader(new StringReader(publicKeyPem));
            PemObject pemObject = pemReader.readPemObject();
            byte[] publicKeyBytes = pemObject.getContent();
    
            // Create a PublicKey object using the decoded public key
            KeyFactory keyFactory = KeyFactory.getInstance("RSA", new BouncyCastleProvider());
            EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
            PublicKey pubKey = keyFactory.generatePublic(publicKeySpec);
    
            MessageDigest messageDigest = MessageDigest.getInstance(hashAlgorithm);
            int saltLength = messageDigest.getDigestLength();
    
            // Initialize the PSS signer
            PSSParameterSpec pssSpec = new PSSParameterSpec(hashAlgorithm, "MGF1", new MGF1ParameterSpec(hashAlgorithm), saltLength, 1);
            Signature signer = Signature.getInstance("RSASSA-PSS");
            signer.setParameter(pssSpec);
            signer.initVerify(pubKey);
    
            // Update the signature with the hash of the message
            byte[] messageBytes = message.getBytes();
            signer.update(messageBytes);
    
            // Verify the signature
            return signer.verify(signatureBytes);
        }
    }
    

    Where:

    • <public_key_contents>: Contents of the public signature key.
    • <signature_string>: Contents of the digital signature in base64 encoding.
    • <message_string>: String with the source message signed with the digital signature or the hash of the file signed with the digital signature.
    • <algorithm_type>: Hash function used for the signature. The possible values are SHA256, SHA384, and SHA512.

    The code verifies the RSA digital signature. It returns true if the signature is correct and false if it is not.

    import (
        "crypto"
        "crypto/rsa"
        "crypto/sha256"
        "crypto/x509"
        "encoding/base64"
        "encoding/pem"
        "fmt"
        "log"
    )
    
    func runRsaSignTest() {
        publicKeyB64 := "<public_key_contents>"
        signatureB64 := "<signature_string>"
        signatureBytes, _ := base64.StdEncoding.DecodeString(signatureB64)
        message := "<message_string>"
    
            fmt.Println(verifyRsa(publicKeyB64, signatureBytes, message, <algorithm_type>))
    }
    
    func verifyRsa(publicKeyPem string, signatureBytes []byte, message string, hash crypto.Hash) bool {
    
        // Decode the public key
        block, _ := pem.Decode([]byte(publicKeyPem))
        if block == nil {
            log.Fatal("failed to decode PEM block containing public key")
        }
    
        // Parse the public key
        pub, err := x509.ParsePKIXPublicKey(block.Bytes)
        if err != nil {
    	    log.Fatal(err)
        }
    
        publicKey, ok := pub.(*rsa.PublicKey)
        if !ok {
    	    log.Fatal("not RSA public key")
        }
    
        // Calculate the hash of the message
        hasher := hash.New()
        hasher.Write([]byte(message))
        hashed := hasher.Sum(nil)
    
        // Set the PSS options: salt length auto, and the hash function
        pssOptions := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthAuto, Hash: hash}
    
        // Verify the signature
        err = rsa.VerifyPSS(publicKey, hash, hashed, signatureBytes, pssOptions)
        if err != nil {
    	    fmt.Println("Verification failed:", err)
    	    return false
        } else {
    	    return true
        }
    }
    

    Where:

    • <public_key_contents>: Contents of the public signature key in base64 encoding.
    • <signature_string>: Contents of the digital signature in base64 encoding.
    • <message_string>: String with the source message signed with the digital signature or the hash of the file signed with the digital signature.
    • <algorithm_type>: Hash function used for the signature. The possible values are crypto.SHA256, crypto.SHA384, and crypto.SHA512.

    The code verifies the RSA digital signature. It returns true if the signature is correct and false if it is not.

    import base64
    from cryptography.hazmat.primitives import hashes
    from cryptography.hazmat.primitives.asymmetric import padding
    from cryptography.hazmat.primitives import serialization
    from cryptography.exceptions import InvalidSignature
    from cryptography.hazmat.backends import default_backend
    
    # Define hash algorithms and corresponding salt lengths
    def verify_rsa_signature(public_key_b64, signature_bytes, message, hash_algorithm):
        hash_algorithms = {
            'SHA256': hashes.SHA256,
            'SHA384': hashes.SHA384,
            'SHA512': hashes.SHA512
        }
    
        # Check if the provided hash algorithm is supported
        if hash_algorithm not in hash_algorithms:
            raise ValueError('Unsupported hash algorithm: ' + hash_algorithm)
    
        # Loading a PEM Encoded Public Key
        public_key = serialization.load_pem_public_key(
            public_key_b64.encode(),
            backend=default_backend()
        )
    
        # Update the Signature object with the message data
        message_bytes = message.encode()
    
        # Automatically calculate salt length based on hash digest size
        salt_length = hash_algorithms[hash_algorithm]().digest_size
    
        # Verify the signature using the original message and the decoded signature
        try:
            public_key.verify(
                signature_bytes,
                message_bytes,
                padding.PSS(
                    mgf = padding.MGF1(hash_algorithms[hash_algorithm]()),
                    salt_length = salt_length
                ),
                hash_algorithms[hash_algorithm]()
            )
            return True
        except InvalidSignature:
            return False
    
    def test_verify_signature():
        public_key_b64 = """
        -----BEGIN PUBLIC KEY-----
        <public_key_contents>
        -----END PUBLIC KEY-----"""
        signature_b64 = '<signature>'
        signature_bytes = base64.b64decode(signature_b64)
        message = '<message>'
        print(verify_rsa_signature(public_key_b64, signature_bytes, message, '<algorithm_type>'))
    

    Where:

    • <public_key_contents>: Contents of the public signature key in base64 encoding.
    • <signature_string>: Contents of the digital signature in base64 encoding.
    • <message_string>: String with the source message signed with the digital signature or the hash of the file signed with the digital signature.
    • <algorithm_type>: Hash function used for the signature. The possible values are SHA256, SHA384, and SHA512.

    The code verifies the RSA digital signature. It returns true if the signature is correct and false if it is not.

Use casesUse cases

  • Signing and verifying Yandex Container Registry Docker images in Yandex Managed Service for Kubernetes

Was the article helpful?

Previous
Digital signature key pair
Next
Envelope encryption
Yandex project
© 2025 Yandex.Cloud LLC