[Yandex Cloud documentation](../../index.md) > [Yandex Key Management Service](../index.md) > [Concepts](index.md) > Digital signature > Digital signature

# Digital signature in KMS

_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](#signature-verification). 

Digital signatures are based on [asymmetric cryptography](asymmetric-encryption.md). 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](https://en.wikipedia.org/wiki/Certificate_authority).

Each key pair counts towards KMS [quotas](limits.md#kms-quotas) as a single key.

## Using a digital signature {#digital-signing}

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.
1. 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.
1. The signature owner transmits the data, the digital signature, and the public key of the asymmetric key pair to a recipient.
1. The recipient uses the public key to verify the digital signature.
1. If the hash decrypted by the recipient matches that of the data, it means the signature is correct.

### Supported digital signature algorithms {#supported-algorithms}

KMS provides [ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm) and [RSA](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) 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 signatures {#signature-verification}

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 signature {#ecdsa-verification}

To verify a digital signature:

1. Get the public key of the digital signature.

1. Perform verification:

    {% list tabs group=programming_language %}
    
    - Bash {#bash}
    
       Verify the digital signature using [OpenSSL](https://www.openssl.org/):
    
       ```(bash)
       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.
    
    - Java {#java}
    
       ```java
       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.
    
    - Go {#go}
    
       ```golang
       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.
    
    - Python {#python}
    
       ```python
       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.
    
    {% endlist %}

### RSA signature {#rca-verification}

To verify a digital signature:

1. Get the public key of the digital signature.

1. Perform verification:

    {% list tabs group=programming_language %}
    
    - Bash {#bash}
    
       Verify the digital signature using [OpenSSL](https://www.openssl.org/):
    
       ```(bash)
       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.
    
    - Java {#java}
    
       ```java
       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.
    
    - Go {#go}
    
       ```golang
       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.
    
    - Python {#python}
    
       ```python
       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.
    
    {% endlist %}

## Use cases {#examples}

* [Signing and verifying Yandex Container Registry Docker images in Yandex Managed Service for Kubernetes](../tutorials/sign-cr-with-cosign.md)