I want to digitally sign data

We recommend the Digital Signature primitive with ECDSA_P256 key type for most use cases.

The Digital Signature primitive ensures that no one has tampered with your data and proves that the data came from you. It is asymmetric, using the private key to sign the data and the public key verify it.

The following examples get you started using the Digital Signature primitive:

C++

 // A utility for signing and verifying files using digital signatures. 
 #include <iostream> 
 #include <memory> 
 #include <ostream> 
 #include <string> 
 #include 
  
 "absl/flags/flag.h" 
 #include 
  
 "absl/flags/parse.h" 
 #include 
  
 "absl/log/check.h" 
 #include 
  
 "absl/strings/string_view.h" 
 #include 
  
 "tink/config/global_registry.h" 
 #include 
  
 "util/util.h" 
 #include 
  
 "tink/keyset_handle.h" 
 #include 
  
 "tink/public_key_sign.h" 
 #include 
  
 "tink/public_key_verify.h" 
 #include 
  
 "tink/signature/signature_config.h" 
 #include 
  
 "tink/util/status.h" 
 ABSL_FLAG 
 ( 
 std 
 :: 
 string 
 , 
  
 keyset_filename 
 , 
  
 "" 
 , 
  
 "Keyset file in JSON format" 
 ); 
 ABSL_FLAG 
 ( 
 std 
 :: 
 string 
 , 
  
 mode 
 , 
  
 "" 
 , 
  
 "Mode of operation (sign|verify)" 
 ); 
 ABSL_FLAG 
 ( 
 std 
 :: 
 string 
 , 
  
 input_filename 
 , 
  
 "" 
 , 
  
 "Filename to operate on" 
 ); 
 ABSL_FLAG 
 ( 
 std 
 :: 
 string 
 , 
  
 signature_filename 
 , 
  
 "" 
 , 
  
 "Path to the signature file" 
 ); 
 namespace 
  
 { 
 using 
  
 :: 
 crypto 
 :: 
 tink 
 :: 
 KeysetHandle 
 ; 
 using 
  
 :: 
 crypto 
 :: 
 tink 
 :: 
 PublicKeySign 
 ; 
 using 
  
 :: 
 crypto 
 :: 
 tink 
 :: 
 PublicKeyVerify 
 ; 
 using 
  
 :: 
 crypto 
 :: 
 tink 
 :: 
 util 
 :: 
 Status 
 ; 
 using 
  
 :: 
 crypto 
 :: 
 tink 
 :: 
 util 
 :: 
 StatusOr 
 ; 
 constexpr 
  
 absl 
 :: 
 string_view 
  
 kSign 
  
 = 
  
 "sign" 
 ; 
 constexpr 
  
 absl 
 :: 
 string_view 
  
 kVerify 
  
 = 
  
 "verify" 
 ; 
 void 
  
 ValidateParams 
 () 
  
 { 
  
 // ... 
 } 
 } 
  
 // namespace 
 namespace 
  
 tink_cc_examples 
  
 { 
 // Digital signature example CLI implementation. 
 Status 
  
 DigitalSignatureCli 
 ( 
 absl 
 :: 
 string_view 
  
 mode 
 , 
  
 const 
  
 std 
 :: 
 string 
&  
 keyset_filename 
 , 
  
 const 
  
 std 
 :: 
 string 
&  
 input_filename 
 , 
  
 const 
  
 std 
 :: 
 string 
&  
 signature_filename 
 ) 
  
 { 
  
 Status 
  
 result 
  
 = 
  
 crypto 
 :: 
 tink 
 :: 
 SignatureConfig 
 :: 
 Register 
 (); 
  
 if 
  
 ( 
 ! 
 result 
 . 
 ok 
 ()) 
  
 return 
  
 result 
 ; 
  
 // Read the keyset from file. 
  
 StatusOr<std 
 :: 
 unique_ptr<KeysetHandle> 
>  
 keyset_handle 
  
 = 
  
 ReadJsonCleartextKeyset 
 ( 
 keyset_filename 
 ); 
  
 if 
  
 ( 
 ! 
 keyset_handle 
 . 
 ok 
 ()) 
  
 return 
  
 keyset_handle 
 . 
 status 
 (); 
  
 // Read the input. 
  
 StatusOr<std 
 :: 
 string 
>  
 input_file_content 
  
 = 
  
 ReadFile 
 ( 
 input_filename 
 ); 
  
 if 
  
 ( 
 ! 
 input_file_content 
 . 
 ok 
 ()) 
  
 return 
  
 input_file_content 
 . 
 status 
 (); 
  
 if 
  
 ( 
 mode 
  
 == 
  
 kSign 
 ) 
  
 { 
  
 StatusOr<std 
 :: 
 unique_ptr<PublicKeySign> 
>  
 public_key_sign 
  
 = 
  
 ( 
 * 
 keyset_handle 
 ) 
  
 - 
> GetPrimitive<crypto 
 :: 
 tink 
 :: 
 PublicKeySign 
> ( 
  
 crypto 
 :: 
 tink 
 :: 
 ConfigGlobalRegistry 
 ()); 
  
 if 
  
 ( 
 ! 
 public_key_sign 
 . 
 ok 
 ()) 
  
 return 
  
 public_key_sign 
 . 
 status 
 (); 
  
 StatusOr<std 
 :: 
 string 
>  
 signature 
  
 = 
  
 ( 
 * 
 public_key_sign 
 ) 
 - 
> Sign 
 ( 
 * 
 input_file_content 
 ); 
  
 if 
  
 ( 
 ! 
 signature 
 . 
 ok 
 ()) 
  
 return 
  
 signature 
 . 
 status 
 (); 
  
 return 
  
 WriteToFile 
 ( 
 * 
 signature 
 , 
  
 signature_filename 
 ); 
  
 } 
  
 else 
  
 { 
  
 // mode == kVerify 
  
 StatusOr<std 
 :: 
 unique_ptr<PublicKeyVerify> 
>  
 public_key_verify 
  
 = 
  
 ( 
 * 
 keyset_handle 
 ) 
  
 - 
> GetPrimitive<crypto 
 :: 
 tink 
 :: 
 PublicKeyVerify 
> ( 
  
 crypto 
 :: 
 tink 
 :: 
 ConfigGlobalRegistry 
 ()); 
  
 if 
  
 ( 
 ! 
 public_key_verify 
 . 
 ok 
 ()) 
  
 return 
  
 public_key_verify 
 . 
 status 
 (); 
  
 // Read the signature. 
  
 StatusOr<std 
 :: 
 string 
>  
 signature_file_content 
  
 = 
  
 ReadFile 
 ( 
 signature_filename 
 ); 
  
 if 
  
 ( 
 ! 
 signature_file_content 
 . 
 ok 
 ()) 
  
 return 
  
 signature_file_content 
 . 
 status 
 (); 
  
 return 
  
 ( 
 * 
 public_key_verify 
 ) 
  
 - 
> Verify 
 ( 
 * 
 signature_file_content 
 , 
  
 * 
 input_file_content 
 ); 
  
 } 
 } 
 } 
  
 // namespace tink_cc_examples 
 int 
  
 main 
 ( 
 int 
  
 argc 
 , 
  
 char 
 ** 
  
 argv 
 ) 
  
 { 
  
 absl 
 :: 
 ParseCommandLine 
 ( 
 argc 
 , 
  
 argv 
 ); 
  
 ValidateParams 
 (); 
  
 std 
 :: 
 string 
  
 mode 
  
 = 
  
 absl 
 :: 
 GetFlag 
 ( 
 FLAGS_mode 
 ); 
  
 std 
 :: 
 string 
  
 keyset_filename 
  
 = 
  
 absl 
 :: 
 GetFlag 
 ( 
 FLAGS_keyset_filename 
 ); 
  
 std 
 :: 
 string 
  
 input_filename 
  
 = 
  
 absl 
 :: 
 GetFlag 
 ( 
 FLAGS_input_filename 
 ); 
  
 std 
 :: 
 string 
  
 signature_filename 
  
 = 
  
 absl 
 :: 
 GetFlag 
 ( 
 FLAGS_signature_filename 
 ); 
  
 std 
 :: 
 clog 
 << 
 "Using keyset in " 
 << 
 keyset_filename 
 << 
 " to " 
 << 
 mode 
 ; 
  
 if 
  
 ( 
 mode 
  
 == 
  
 kSign 
 ) 
  
 { 
  
 std 
 :: 
 clog 
 << 
 " file " 
 << 
 input_filename 
 << 
 "; the resulting signature is written to " 
 << 
 signature_filename 
 << 
 '\n' 
 ; 
  
 } 
  
 else 
  
 { 
  
 // mode == kVerify 
  
 std 
 :: 
 clog 
 << 
 " the signature in " 
 << 
 signature_filename 
 << 
 " over the content of " 
 << 
 input_filename 
 << 
 '\n' 
 ; 
  
 } 
  
 CHECK_OK 
 ( 
 tink_cc_examples 
 :: 
 DigitalSignatureCli 
 ( 
  
 mode 
 , 
  
 keyset_filename 
 , 
  
 input_filename 
 , 
  
 signature_filename 
 )); 
  
 return 
  
 0 
 ; 
 } 
  

Go

 import 
  
 ( 
  
 "bytes" 
  
 "fmt" 
  
 "log" 
  
 "github.com/tink-crypto/tink-go/v2/insecurecleartextkeyset" 
  
 "github.com/tink-crypto/tink-go/v2/keyset" 
  
 "github.com/tink-crypto/tink-go/v2/signature" 
 ) 
 func 
  
 Example 
 () 
  
 { 
  
 // A private keyset created with 
  
 // "tinkey create-keyset --key-template=ECDSA_P256 --out private_keyset.cfg". 
  
 // Note that this keyset has the secret key information in cleartext. 
  
 privateJSONKeyset 
  
 := 
  
 `{ 
 "key": [{ 
 "keyData": { 
 "keyMaterialType": 
 "ASYMMETRIC_PRIVATE", 
 "typeUrl": 
 "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey", 
 "value": 
 "EkwSBggDEAIYAhogEiSZ9u2nDtvZuDgWgGsVTIZ5/V08N4ycUspTX0RYRrkiIHpEwHxQd1bImkyMvV2bqtUbgMh5uPSTdnUEGrPXdt56GiEA3iUi+CRN71qy0fOCK66xAW/IvFyjOGtxjppRhSFUneo=" 
 }, 
 "keyId": 611814836, 
 "outputPrefixType": "TINK", 
 "status": "ENABLED" 
 }], 
 "primaryKeyId": 611814836 
 }` 
  
 // The corresponding public keyset created with 
  
 // "tinkey create-public-keyset --in private_keyset.cfg" 
  
 publicJSONKeyset 
  
 := 
  
 `{ 
 "key": [{ 
 "keyData": { 
 "keyMaterialType": 
 "ASYMMETRIC_PUBLIC", 
 "typeUrl": 
 "type.googleapis.com/google.crypto.tink.EcdsaPublicKey", 
 "value": 
 "EgYIAxACGAIaIBIkmfbtpw7b2bg4FoBrFUyGef1dPDeMnFLKU19EWEa5IiB6RMB8UHdWyJpMjL1dm6rVG4DIebj0k3Z1BBqz13beeg==" 
 }, 
 "keyId": 611814836, 
 "outputPrefixType": "TINK", 
 "status": "ENABLED" 
 }], 
 "primaryKeyId": 611814836 
 }` 
  
 // Create a keyset handle from the cleartext private keyset in the previous 
  
 // step. The keyset handle provides abstract access to the underlying keyset to 
  
 // limit the access of the raw key material. WARNING: In practice, 
  
 // it is unlikely you will want to use a insecurecleartextkeyset, as it implies 
  
 // that your key material is passed in cleartext, which is a security risk. 
  
 // Consider encrypting it with a remote key in Cloud KMS, AWS KMS or HashiCorp Vault. 
  
 // See https://github.com/google/tink/blob/master/docs/GOLANG-HOWTO.md#storing-and-loading-existing-keysets. 
  
 privateKeysetHandle 
 , 
  
 err 
  
 := 
  
 insecurecleartextkeyset 
 . 
 Read 
 ( 
  
 keyset 
 . 
 NewJSONReader 
 ( 
 bytes 
 . 
 NewBufferString 
 ( 
 privateJSONKeyset 
 ))) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 log 
 . 
 Fatal 
 ( 
 err 
 ) 
  
 } 
  
 // Retrieve the Signer primitive from privateKeysetHandle. 
  
 signer 
 , 
  
 err 
  
 := 
  
 signature 
 . 
 NewSigner 
 ( 
 privateKeysetHandle 
 ) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 log 
 . 
 Fatal 
 ( 
 err 
 ) 
  
 } 
  
 // Use the primitive to sign a message. In this case, the primary key of the 
  
 // keyset will be used (which is also the only key in this example). 
  
 data 
  
 := 
  
 [] 
 byte 
 ( 
 "data" 
 ) 
  
 sig 
 , 
  
 err 
  
 := 
  
 signer 
 . 
 Sign 
 ( 
 data 
 ) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 log 
 . 
 Fatal 
 ( 
 err 
 ) 
  
 } 
  
 // Create a keyset handle from the keyset containing the public key. Because the 
  
 // public keyset does not contain any secrets, we can use [keyset.ReadWithNoSecrets]. 
  
 publicKeysetHandle 
 , 
  
 err 
  
 := 
  
 keyset 
 . 
 ReadWithNoSecrets 
 ( 
  
 keyset 
 . 
 NewJSONReader 
 ( 
 bytes 
 . 
 NewBufferString 
 ( 
 publicJSONKeyset 
 ))) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 log 
 . 
 Fatal 
 ( 
 err 
 ) 
  
 } 
  
 // Retrieve the Verifier primitive from publicKeysetHandle. 
  
 verifier 
 , 
  
 err 
  
 := 
  
 signature 
 . 
 NewVerifier 
 ( 
 publicKeysetHandle 
 ) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 log 
 . 
 Fatal 
 ( 
 err 
 ) 
  
 } 
  
 if 
  
 err 
  
 = 
  
 verifier 
 . 
 Verify 
 ( 
 sig 
 , 
  
 data 
 ); 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 log 
 . 
 Fatal 
 ( 
 err 
 ) 
  
 } 
  
 fmt 
 . 
 Printf 
 ( 
 "sig is valid" 
 ) 
  
 // Output: sig is valid 
 } 
  

Java

 package 
  
 signature 
 ; 
 import static 
  
 java.nio.charset.StandardCharsets.UTF_8 
 ; 
 import 
  
 com.google.crypto.tink.InsecureSecretKeyAccess 
 ; 
 import 
  
 com.google.crypto.tink.KeysetHandle 
 ; 
 import 
  
 com.google.crypto.tink.PublicKeySign 
 ; 
 import 
  
 com.google.crypto.tink.PublicKeyVerify 
 ; 
 import 
  
 com.google.crypto.tink.RegistryConfiguration 
 ; 
 import 
  
 com.google.crypto.tink.TinkJsonProtoKeysetFormat 
 ; 
 import 
  
 com.google.crypto.tink.signature.SignatureConfig 
 ; 
 import 
  
 java.nio.file.Files 
 ; 
 import 
  
 java.nio.file.Path 
 ; 
 import 
  
 java.nio.file.Paths 
 ; 
 /** 
 * A command-line utility for digitally signing and verifying a file. 
 * 
 * <p>It loads cleartext keys from disk - this is not recommended! 
 * 
 * <p>It requires the following arguments: 
 * 
 * <ul> 
 *   <li>mode: either 'sign' or 'verify'. 
 *   <li>key-file: Read the key material from this file. 
 *   <li>input-file: Read the input from this file. 
 *   <li>signature-file: name of the file containing a hexadecimal signature of the input file. 
 */ 
 public 
  
 final 
  
 class 
 SignatureExample 
  
 { 
  
 public 
  
 static 
  
 void 
  
 main 
 ( 
 String 
 [] 
  
 args 
 ) 
  
 throws 
  
 Exception 
  
 { 
  
 if 
  
 ( 
 args 
 . 
 length 
  
 != 
  
 4 
 ) 
  
 { 
  
 System 
 . 
 err 
 . 
 printf 
 ( 
 "Expected 4 parameters, got %d\n" 
 , 
  
 args 
 . 
 length 
 ); 
  
 System 
 . 
 err 
 . 
 println 
 ( 
  
 "Usage: java SignatureExample sign/verify key-file input-file signature-file" 
 ); 
  
 System 
 . 
 exit 
 ( 
 1 
 ); 
  
 } 
  
 String 
  
 mode 
  
 = 
  
 args 
 [ 
 0 
 ] 
 ; 
  
 if 
  
 ( 
 ! 
 mode 
 . 
 equals 
 ( 
 "sign" 
 ) 
 && 
 ! 
 mode 
 . 
 equals 
 ( 
 "verify" 
 )) 
  
 { 
  
 System 
 . 
 err 
 . 
 println 
 ( 
 "Incorrect mode. Please select sign or verify." 
 ); 
  
 System 
 . 
 exit 
 ( 
 1 
 ); 
  
 } 
  
 Path 
  
 keyFile 
  
 = 
  
 Paths 
 . 
 get 
 ( 
 args 
 [ 
 1 
 ] 
 ); 
  
 byte 
 [] 
  
 msg 
  
 = 
  
 Files 
 . 
 readAllBytes 
 ( 
 Paths 
 . 
 get 
 ( 
 args 
 [ 
 2 
 ] 
 )); 
  
 Path 
  
 signatureFile 
  
 = 
  
 Paths 
 . 
 get 
 ( 
 args 
 [ 
 3 
 ] 
 ); 
  
 // Register all signature key types with the Tink runtime. 
  
 SignatureConfig 
 . 
 register 
 (); 
  
 // Read the keyset into a KeysetHandle. 
  
 KeysetHandle 
  
 handle 
  
 = 
  
 TinkJsonProtoKeysetFormat 
 . 
 parseKeyset 
 ( 
  
 new 
  
 String 
 ( 
 Files 
 . 
 readAllBytes 
 ( 
 keyFile 
 ), 
  
 UTF_8 
 ), 
  
 InsecureSecretKeyAccess 
 . 
 get 
 ()); 
  
 if 
  
 ( 
 mode 
 . 
 equals 
 ( 
 "sign" 
 )) 
  
 { 
  
 // Get the primitive. 
  
 PublicKeySign 
  
 signer 
  
 = 
  
 handle 
 . 
 getPrimitive 
 ( 
 RegistryConfiguration 
 . 
 get 
 (), 
  
 PublicKeySign 
 . 
 class 
 ); 
  
 // Use the primitive to sign data. 
  
 byte 
 [] 
  
 signature 
  
 = 
  
 signer 
 . 
 sign 
 ( 
 msg 
 ); 
  
 Files 
 . 
 write 
 ( 
 signatureFile 
 , 
  
 signature 
 ); 
  
 } 
  
 else 
  
 { 
  
 byte 
 [] 
  
 signature 
  
 = 
  
 Files 
 . 
 readAllBytes 
 ( 
 signatureFile 
 ); 
  
 // Get the primitive. 
  
 PublicKeyVerify 
  
 verifier 
  
 = 
  
 handle 
 . 
 getPrimitive 
 ( 
 RegistryConfiguration 
 . 
 get 
 (), 
  
 PublicKeyVerify 
 . 
 class 
 ); 
  
 verifier 
 . 
 verify 
 ( 
 signature 
 , 
  
 msg 
 ); 
  
 } 
  
 } 
  
 private 
  
 SignatureExample 
 () 
  
 {} 
 } 
  

Obj-C

HOW-TO

Python

 import 
  
 tink 
 from 
  
 tink 
  
 import 
 secret_key_access 
 from 
  
 tink 
  
 import 
 signature 
 def 
  
 example 
 (): 
  
 """Sign and verify using digital signatures.""" 
 # Register the signature key managers. This is needed to create 
 # PublicKeySign and PublicKeyVerify primitives later. 
 signature 
 . 
 register 
 () 
 # A private keyset created with 
 # "tinkey create-keyset --key-template=ECDSA_P256 --out private_keyset.cfg". 
 # Note that this keyset has the secret key information in cleartext. 
 private_keyset 
 = 
 r 
 """{ 
 "key": [{ 
 "keyData": { 
 "keyMaterialType": 
 "ASYMMETRIC_PRIVATE", 
 "typeUrl": 
 "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey", 
 "value": 
 "EkwSBggDEAIYAhogEiSZ9u2nDtvZuDgWgGsVTIZ5/V08N4ycUspTX0RYRrkiIHpEwHxQd1bImkyMvV2bqtUbgMh5uPSTdnUEGrPXdt56GiEA3iUi+CRN71qy0fOCK66xAW/IvFyjOGtxjppRhSFUneo=" 
 }, 
 "keyId": 611814836, 
 "outputPrefixType": "TINK", 
 "status": "ENABLED" 
 }], 
 "primaryKeyId": 611814836 
 }""" 
 # The corresponding public keyset created with 
 # "tinkey create-public-keyset --in private_keyset.cfg" 
 public_keyset 
 = 
 r 
 """{ 
 "key": [{ 
 "keyData": { 
 "keyMaterialType": 
 "ASYMMETRIC_PUBLIC", 
 "typeUrl": 
 "type.googleapis.com/google.crypto.tink.EcdsaPublicKey", 
 "value": 
 "EgYIAxACGAIaIBIkmfbtpw7b2bg4FoBrFUyGef1dPDeMnFLKU19EWEa5IiB6RMB8UHdWyJpMjL1dm6rVG4DIebj0k3Z1BBqz13beeg==" 
 }, 
 "keyId": 611814836, 
 "outputPrefixType": "TINK", 
 "status": "ENABLED" 
 }], 
 "primaryKeyId": 611814836 
 }""" 
 # Create a keyset handle from the cleartext keyset in the previous 
 # step. The keyset handle provides abstract access to the underlying keyset to 
 # limit the exposure of accessing the raw key material. WARNING: In practice, 
 # it is unlikely you will want to use tink.json_proto_keyset_format.parse, as 
 # it implies that your key material is passed in cleartext which is a security 
 # risk. 
 private_keyset_handle 
 = 
 tink 
 . 
 json_proto_keyset_format 
 . 
 parse 
 ( 
 private_keyset 
 , 
 secret_key_access 
 . 
 TOKEN 
 ) 
 # Retrieve the PublicKeySign primitive we want to use from the keyset 
 # handle. 
 sign_primitive 
 = 
 private_keyset_handle 
 . 
 primitive 
 ( 
 signature 
 . 
 PublicKeySign 
 ) 
 # Use the primitive to sign a message. In this case the primary key of the 
 # keyset will be used (which is also the only key in this example). 
 sig 
 = 
 sign_primitive 
 . 
 sign 
 ( 
 b 
 'msg' 
 ) 
 # Create a keyset handle from the keyset containing the public key. Because 
 # this keyset does not contain any secrets, we can use 
 # `parse_without_secret`. 
 public_keyset_handle 
 = 
 tink 
 . 
 json_proto_keyset_format 
 . 
 parse_without_secret 
 ( 
 public_keyset 
 ) 
 # Retrieve the PublicKeyVerify primitive we want to use from the keyset 
 # handle. 
 verify_primitive 
 = 
 public_keyset_handle 
 . 
 primitive 
 ( 
 signature 
 . 
 PublicKeyVerify 
 ) 
 # Use the primitive to verify that `sig` is valid signature for the message. 
 # Verify finds the correct key in the keyset. If no key is found or 
 # verification fails, it raises an error. 
 verify_primitive 
 . 
 verify 
 ( 
 sig 
 , 
 b 
 'msg' 
 ) 
 # Note that we can also get the public keyset handle from the private keyset 
 # handle. The verification works the same as above. 
 public_keyset_handle2 
 = 
 private_keyset_handle 
 . 
 public_keyset_handle 
 () 
 verify_primitive2 
 = 
 public_keyset_handle2 
 . 
 primitive 
 ( 
 signature 
 . 
 PublicKeyVerify 
 ) 
 verify_primitive2 
 . 
 verify 
 ( 
 sig 
 , 
 b 
 'msg' 
 ) 
  

Digital Signature

The Digital Signature primitive lets you verify that no one has tampered with your data. It provides authenticity and integrity, but not secrecy, of the signed data. It is asymmetric, meaning it uses a pair of keys (public key and private key).

The Digital Signature primitive has the following properties:

  • Authenticity: It is impossible to create a signature for which PublicKeyVerify.Verify(signature, message) validates, unless you have the private key.
  • Asymmetric: Creating the signature uses a different key than verifying it. This lets you distribute the public key to verify signatures to parties that can't create signatures themselves.

If you don't need asymmetry, consider using the simpler and more efficient MAC primitive instead.

The functionality of digital signatures is represented in Tink as a pair of primitives:

  • PublicKeySign for signing data
  • PublicKeyVerify for verifying the signature

Choose a key type

We recommend using ECDSA_P256for most use cases, but there are a variety of options. In general, the following holds true:

  • ECDSA_P256 is the most widely used option and a reasonable default. Note though that ECDSA signatures are malleable .
  • ED25519 creates deterministic signatures and provides better performance than ECDSA_P256.
  • RSA_SSA_PKCS1_3072_SHA256_F4 creates deterministic signatures and provides the best verification performance (but signing is much slower than ECDSA_P256 or ED25519).

Minimal security guarantees

  • Data to be signed can have arbitrary length
  • 128-bit security level against adaptive chosen-message attacks for elliptic curve based schemes
  • 112-bit security level against adaptive chosen-message attacks for RSA based schemes (allows 2048-bit keys)

Malleability

A signature scheme is malleable if an attacker can create a different valid signature for an already signed message. While this is not a problem for most scenarios, in some cases programmers implicitly assume that valid signatures are unique, and this can lead to unexpected results.

Design a Mobile Site
View Site in Mobile | Classic
Share by: