Çoğu genel anahtar şifreleme kullanım alanı için DHKEM_X25519_HKDF_SHA256, HKDF_SHA256, AES_256_GCM anahtar türüyle Karma Şifreleme temelini kullanmanızı öneririz.
Herkese açık anahtar şifrelemede veriler, biri herkese açık, diğeri özel olmak üzere iki anahtarla korunur. Ortak anahtar şifreleme, özel anahtar ise şifre çözme için kullanılır. Gönderen, sırları saklayamıyorsa ve verileri ortak anahtarla şifrelemesi gerekiyorsa bu iyi bir seçenektir.
Aşağıdaki örnekler, karma şifreleme temelini kullanmaya başlamanıza yardımcı olur:
C++
// A command-line utility for testing Tink Hybrid Encryption. #include <iostream> #include <memory> #include <ostream> #include <string> #include "absl/flags/flag.h" #include "absl/flags/parse.h" #include "absl/log/absl_check.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "tink/config/global_registry.h" #include "util/util.h" #ifndef TINK_EXAMPLES_EXCLUDE_HPKE #include "tink/hybrid/hpke_config.h" #endif #include "tink/hybrid/hybrid_config.h" #include "tink/hybrid_decrypt.h" #include "tink/hybrid_encrypt.h" #include "tink/keyset_handle.h" ABSL_FLAG(std::string, keyset_filename, "", "Keyset file in JSON format"); ABSL_FLAG(std::string, mode, "", "Mode of operation {encrypt|decrypt}"); ABSL_FLAG(std::string, input_filename, "", "Input file name"); ABSL_FLAG(std::string, output_filename, "", "Output file name"); ABSL_FLAG(std::string, context_info, "", "Context info for Hybrid Encryption/Decryption"); namespace { using ::crypto::tink::HybridDecrypt; using ::crypto::tink::HybridEncrypt; using ::crypto::tink::KeysetHandle; constexpr absl::string_view kEncrypt = "encrypt"; constexpr absl::string_view kDecrypt = "decrypt"; void ValidateParams() { // ... } } // namespace namespace tink_cc_examples { absl::Status HybridCli(absl::string_view mode, const std::string& keyset_filename, const std::string& input_filename, const std::string& output_filename, absl::string_view context_info) { absl::Status result = crypto::tink::HybridConfig::Register(); if (!result.ok()) return result; #ifndef TINK_EXAMPLES_EXCLUDE_HPKE // HPKE isn't supported when using OpenSSL as a backend. result = crypto::tink::RegisterHpke(); if (!result.ok()) return result; #endif // Read the keyset from file. absl::StatusOr<std::unique_ptr<KeysetHandle>> keyset_handle = ReadJsonCleartextKeyset(keyset_filename); if (!keyset_handle.ok()) return keyset_handle.status(); // Read the input. absl::StatusOr<std::string> input_file_content = ReadFile(input_filename); if (!input_file_content.ok()) return input_file_content.status(); // Compute the output. std::string output; if (mode == kEncrypt) { // Get the hybrid encryption primitive. absl::StatusOr<std::unique_ptr<HybridEncrypt>> hybrid_encrypt_primitive = (*keyset_handle) ->GetPrimitive<crypto::tink::HybridEncrypt>( crypto::tink::ConfigGlobalRegistry()); if (!hybrid_encrypt_primitive.ok()) { return hybrid_encrypt_primitive.status(); } // Generate the ciphertext. absl::StatusOr<std::string> encrypt_result = (*hybrid_encrypt_primitive)->Encrypt(*input_file_content, context_info); if (!encrypt_result.ok()) return encrypt_result.status(); output = encrypt_result.value(); } else { // operation == kDecrypt. // Get the hybrid decryption primitive. absl::StatusOr<std::unique_ptr<HybridDecrypt>> hybrid_decrypt_primitive = (*keyset_handle) ->GetPrimitive<crypto::tink::HybridDecrypt>( crypto::tink::ConfigGlobalRegistry()); if (!hybrid_decrypt_primitive.ok()) { return hybrid_decrypt_primitive.status(); } // Recover the plaintext. absl::StatusOr<std::string> decrypt_result = (*hybrid_decrypt_primitive)->Decrypt(*input_file_content, context_info); if (!decrypt_result.ok()) return decrypt_result.status(); output = decrypt_result.value(); } // Write the output to the output file. return WriteToFile(output, output_filename); } } // 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 output_filename = absl::GetFlag(FLAGS_output_filename); std::string context_info = absl::GetFlag(FLAGS_context_info); std::clog << "Using keyset from file " << keyset_filename << " to hybrid " << mode << " file " << input_filename << " with context info '" << context_info << "'." << '\n'; std::clog << "The resulting output will be written to " << output_filename << '\n'; ABSL_CHECK_OK(tink_cc_examples::HybridCli( mode, keyset_filename, input_filename, output_filename, context_info)); return 0; }
Go
import ( "bytes" "fmt" "log" "github.com/tink-crypto/tink-go/v2/hybrid" "github.com/tink-crypto/tink-go/v2/insecurecleartextkeyset" "github.com/tink-crypto/tink-go/v2/keyset" ) func Example() { // A private keyset created with // "tinkey create-keyset --key-template=DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM --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.HpkePrivateKey", "value": "EioSBggBEAEYAhogVWQpmQoz74jcAp5WOD36KiBQ71MVCpn2iWfOzWLtKV4aINfn8qlMbyijNJcCzrafjsgJ493ZZGN256KTfKw0WN+p" }, "keyId": 958452012, "outputPrefixType": "TINK", "status": "ENABLED" }], "primaryKeyId": 958452012 }` // 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.HpkePublicKey", "value": "EgYIARABGAIaIFVkKZkKM++I3AKeVjg9+iogUO9TFQqZ9olnzs1i7Sle" }, "keyId": 958452012, "outputPrefixType": "TINK", "status": "ENABLED" }], "primaryKeyId": 958452012 }` // 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 HybridEncrypt primitive from publicKeysetHandle. encPrimitive, err := hybrid.NewHybridEncrypt(publicKeysetHandle) if err != nil { log.Fatal(err) } plaintext := []byte("message") encryptionContext := []byte("encryption context") ciphertext, err := encPrimitive.Encrypt(plaintext, encryptionContext) if err != nil { log.Fatal(err) } // 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 HybridDecrypt primitive from privateKeysetHandle. decPrimitive, err := hybrid.NewHybridDecrypt(privateKeysetHandle) if err != nil { log.Fatal(err) } decrypted, err := decPrimitive.Decrypt(ciphertext, encryptionContext) if err != nil { log.Fatal(err) } fmt.Println(string(decrypted)) // Output: message }
Java
package hybrid; import static java.nio.charset.StandardCharsets.UTF_8; import com.google.crypto.tink.HybridDecrypt; import com.google.crypto.tink.HybridEncrypt; import com.google.crypto.tink.InsecureSecretKeyAccess; import com.google.crypto.tink.KeysetHandle; import com.google.crypto.tink.RegistryConfiguration; import com.google.crypto.tink.TinkJsonProtoKeysetFormat; import com.google.crypto.tink.hybrid.HybridConfig; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; /** * A command-line utility for hybrid encryption. * * <p>It loads cleartext keys from disk - this is not recommended! * * <p>It requires the following arguments: * * <ul> * <li>mode: either 'encrypt' or 'decrypt'. * <li>key-file: Read the key material from this file. * <li>input-file: Read the input from this file. * <li>output-file: Write the result to this file. * <li>[optional] contex-info: Bind the encryption to this context info. */ public final class HybridExample { public static void main(String[] args) throws Exception { if (args.length != 4 && args.length != 5) { System.err.printf("Expected 4 or 5 parameters, got %d\n", args.length); System.err.println( "Usage: java HybridExample encrypt/decrypt key-file input-file output-file context-info"); System.exit(1); } String mode = args[0]; if (!mode.equals("encrypt") && !mode.equals("decrypt")) { System.err.println("Incorrect mode. Please select encrypt or decrypt."); System.exit(1); } Path keyFile = Paths.get(args[1]); Path inputFile = Paths.get(args[2]); byte[] input = Files.readAllBytes(inputFile); Path outputFile = Paths.get(args[3]); byte[] contextInfo = new byte[0]; if (args.length == 5) { contextInfo = args[4].getBytes(UTF_8); } // Register all hybrid encryption key types with the Tink runtime. HybridConfig.register(); // Read the keyset into a KeysetHandle. KeysetHandle handle = TinkJsonProtoKeysetFormat.parseKeyset( new String(Files.readAllBytes(keyFile), UTF_8), InsecureSecretKeyAccess.get()); if (mode.equals("encrypt")) { // Get the primitive. HybridEncrypt encryptor = handle.getPrimitive(RegistryConfiguration.get(), HybridEncrypt.class); // Use the primitive to encrypt data. byte[] ciphertext = encryptor.encrypt(input, contextInfo); Files.write(outputFile, ciphertext); } else { HybridDecrypt decryptor = handle.getPrimitive(RegistryConfiguration.get(), HybridDecrypt.class); // Use the primitive to decrypt data. byte[] plaintext = decryptor.decrypt(input, contextInfo); Files.write(outputFile, plaintext); } } private HybridExample() {} }
Obj-C
Python
import tink from tink import hybrid from tink import secret_key_access def example(): """Encrypt and decrypt using hybrid encryption.""" # Register the hybrid encryption key managers. This is needed to create # HybridEncrypt and HybridDecrypt primitives later. hybrid.register() # A private keyset created with # tinkey create-keyset \ # --key-template=DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM \ # --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.HpkePrivateKey", "value": "EioSBggBEAEYAhogVWQpmQoz74jcAp5WOD36KiBQ71MVCpn2iWfOzWLtKV4aINfn8qlMbyijNJcCzrafjsgJ493ZZGN256KTfKw0WN+p" }, "keyId": 958452012, "outputPrefixType": "TINK", "status": "ENABLED" }], "primaryKeyId": 958452012 }""" # 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.HpkePublicKey", "value": "EgYIARABGAIaIFVkKZkKM++I3AKeVjg9+iogUO9TFQqZ9olnzs1i7Sle" }, "keyId": 958452012, "outputPrefixType": "TINK", "status": "ENABLED" }], "primaryKeyId": 958452012 }""" # 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 HybridEncrypt primitive from the keyset handle. enc_primitive = public_keyset_handle.primitive(hybrid.HybridEncrypt) # Use enc_primitive to encrypt a message. In this case the primary key of the # keyset will be used (which is also the only key in this example). ciphertext = enc_primitive.encrypt(b'message', b'context_info') # Create a keyset handle from the private keyset. 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 a 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 HybridDecrypt primitive from the private keyset handle. dec_primitive = private_keyset_handle.primitive(hybrid.HybridDecrypt) # Use dec_primitive to decrypt the message. Decrypt finds the correct key in # the keyset and decrypts the ciphertext. If no key is found or decryption # fails, it raises an error. decrypted = dec_primitive.decrypt(ciphertext, b'context_info')
Karma Şifreleme
Karma şifreleme temeli, simetrik şifrelemenin verimliliğini ortak anahtar (asimetrik) kriptografinin rahatlığıyla birleştirir. Herkese açık anahtarı kullanarak verileri şifreleyebilir ancak verilerin şifresini yalnızca özel anahtara sahip kullanıcılar çözebilir.
Karma şifrelemede gönderen, her iletinin düz metnini şifreleyerek şifreli metin oluşturmak için yeni bir simetrik anahtar üretir. Bu simetrik anahtar, alıcının ortak anahtarıyla kapsüllenir. Karma şifre çözme işleminde, simetrik anahtar alıcı tarafından kapsülden çıkarılır ve ardından orijinal düz metni kurtarmak için şifreli metnin şifresini çözmek üzere kullanılır. Şifrelenmiş metni anahtar kapsülleme ile birlikte depolama veya iletme hakkında ayrıntılı bilgi için Tink Hybrid Encryption wire format başlıklı makaleyi inceleyin.
Karma şifrelemenin özellikleri şunlardır:
- Secrecy: Şifrelenmiş düz metinle ilgili hiçbir bilgi (uzunluk hariç) özel anahtara erişimi olmayan kişiler tarafından alınamaz.
- Asimetri: Şifreli metnin şifrelenmesi ortak anahtarla yapılabilir ancak şifre çözme için özel anahtar gerekir.
- Rastgele hale getirme: Şifreleme rastgele hale getirilir. Aynı düz metne sahip iki mesaj aynı şifreli metni oluşturmaz. Bu, saldırganların hangi şifreli metnin belirli bir düz metne karşılık geldiğini bilmesini engeller.
Karma şifreleme, Tink'te iki temel öğe çifti olarak gösterilir:
- Şifreleme için HybridEncrypt
- Şifre çözme için HybridDecrypt
Bağlam bilgisi parametresi
Hibrit şifreleme, şifrelenmemiş metne ek olarak genellikle bağlamdan gelen örtülü herkese açık veriler olan ancak sonuçtaki şifrelenmiş metne bağlı olması gereken ek bir parametre olan context_info'yı da kabul eder. Bu, şifreli metnin bağlam bilgilerinin bütünlüğünü doğrulamanıza olanak tanıdığı ancak gizliliği veya gerçekliği konusunda herhangi bir garanti verilmediği anlamına gelir. Gerçek bağlam bilgisi boş veya null olabilir ancak ortaya çıkan şifreli metnin doğru şekilde şifresinin çözülmesini sağlamak için şifre çözme işleminde aynı bağlam bilgisi değeri sağlanmalıdır.
Karma şifrelemenin somut bir uygulaması, bağlam bilgilerini çeşitli şekillerde şifreli metne bağlayabilir. Örneğin:
- AEAD simetrik şifreleme için ilişkili veri girişi olarak
context_infokullanın (RFC 5116 ile karşılaştırın). - Uygulamada anahtar türetme işlevi olarak HKDF kullanılıyorsa (RFC 5869'a bakın) HKDF için "CtxInfo" girişi olarak
context_infokullanın.
Anahtar türü seçin
Çoğu kullanım alanı için DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM
anahtar türünü kullanmanızı öneririz. Bu anahtar türü, RFC 9180'de belirtildiği gibi Karma Genel Anahtar Şifreleme (HPKE) standardını uygular. HPKE; anahtar kapsülleme mekanizması (KEM), anahtar türetme işlevi (KDF) ve ilişkili verilerle kimliği doğrulanmış şifreleme (AEAD) algoritmasından oluşur.
DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM özellikle şu yöntemleri kullanır:
- KEM: Ortak gizli diziyi türetmek için HKDF-SHA-256 ile Curve25519 üzerinden Diffie-Hellman.
- KDF: Gönderen ve alıcı bağlamını türetmek için HKDF-SHA-256.
- AEAD: HPKE standardına göre oluşturulan 12 baytlık tek kullanımlık sayılarla AES-256-GCM.
Desteklenen diğer HPKE anahtar türleri şunları içerir ancak bunlarla sınırlı değildir:
DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_128_GCMDHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305DHKEM_P256_HKDF_SHA256_HKDF_SHA256_AES_128_GCMDHKEM_P521_HKDF_SHA512_HKDF_SHA512_AES_256_GCM
KEM, KDF ve AEAD için algoritma seçenekleri hakkında daha fazla bilgi edinmek istiyorsanız RFC 9180'i inceleyin.
Artık önerilmese de Tink, Victor Shoup'un ISO 18033-2 standardında açıklandığı gibi ECIES'in bazı varyasyonlarını da destekler. Desteklenen bazı ECIES anahtar türleri aşağıda listelenmiştir:
ECIES_P256_HKDF_HMAC_SHA256_AES128_GCMECIES_P256_COMPRESSED_HKDF_HMAC_SHA256_AES128_GCMECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256ECIES_P256_COMPRESSED_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256
Minimum özellikler
- Düz metin ve bağlam bilgileri, 0..232 bayt aralığında olmak üzere rastgele uzunlukta olabilir.
- Uyarlanabilir seçilmiş şifreli metin saldırılarına karşı güvenli
- Elips biçimli eğri tabanlı şemalar için 128 bit güvenlik