تتيح لك Tink إجراء تشفير من جهة العميل لبعض البيانات، كما تتيح لك حماية مفاتيحك باستخدام نظام إدارة مفاتيح (KMS) مستند إلى السحابة الإلكترونية. تعمل هذه الميزة على النحو التالي:
- ينشئ العميل مفتاح تشفير البيانات (DEK).
- يشفّر العميل البيانات باستخدام مفتاح تشفير البيانات.
- يتم تشفير مفتاح تشفير البيانات (DEK) باستخدام مفتاح تشفير المفتاح (KEK) المخزَّن في خدمة إدارة مفاتيح تشفير مستنِدة إلى السحابة الإلكترونية.
باستخدام Cloud KMS، يتم تخزين مفتاح تشفير المفتاح بأمان في السحابة الإلكترونية، حيث يمكنك تدويره أو إيقافه أو إتلافه حسب احتياجاتك.
راجِع قسم "نظرة عامة على إدارة المفاتيح" للحصول على مزيد من المعلومات حول ما تحتاج إليه Tink للتفاعل مع نظام إدارة مفاتيح على السحابة الإلكترونية.
باستخدام Tink، يمكنك إجراء التشفير من جهة العميل باستخدام نظام إدارة مفاتيح على السحابة الإلكترونية بطريقتَين:
استخدام عنصر KMS الأساسي لتشفير AEAD (
KmsEnvelopeAead): في كل عملية تشفير، تنشئ Tink مفتاح DEK جديدًا لتشفير AEAD، وتشفّره باستخدام مفتاح KEK في Cloud KMS، وتخزّنه كجزء من النص المشفّر، وبالتالي لن تحتاج إلى التعامل مع مفتاح DEK بنفسك. ونتيجةً لذلك، يكون النص المشفّر أطول قليلاً لأنّه يتضمّن مفتاح تشفير البيانات المشفّر. بالإضافة إلى ذلك، في كل مرة يتم فيها التشفير أو فك التشفير، تُجري Tink طلب إجراء عن بُعد إلى خدمة إدارة المفاتيح (يتم إجراء عملية التشفير أو فك التشفير الفعلية للبيانات محليًا).استخدام عنصر أساسي آخر وتشفير مجموعة المفاتيح باستخدام Cloud KMS: يوفّر هذا الخيار مرونة أكبر، إذ يمكنك استخدام عناصر أساسية مختلفة غير AEAD، ويمكنك الحدّ من عدد طلبات Cloud KMS.
تشفير AEAD باستخدام مغلف KMS
عند تشفير البيانات باستخدام KmsEnvelopeAead، تنفّذ Tink الإجراءات التالية نيابةً عنك:
- تنشئ هذه العملية مفتاح تشفير بيانات عشوائيًا وتشفّر بياناتك محليًا باستخدام هذا المفتاح.
- يُرسِل طلبًا إلى خدمة إدارة المفاتيح (KMS) لتشفير مفتاح تشفير البيانات (DEK) باستخدام مفتاح تشفير المفتاح (KEK) الخاص بخدمة إدارة المفاتيح (KMS).
- تدمج هذه السمة مفتاح تشفير البيانات المشفَّر باستخدام مفتاح تشفير المفتاح مع البيانات المشفَّرة.
يتم تحديد كل من نوع مفتاح تشفير البيانات ومعرّف الموارد المنتظم لمفتاح تشفير المفاتيح في مفتاح KmsEnvelopeAead.
عند فك التشفير، تنفّذ Tink العمليات العكسية:
- يستخرج مفتاح DEK المشفّر باستخدام KEK.
- يُرسِل طلبًا إلى خدمة إدارة المفاتيح (KMS) لفك تشفير مفتاح تشفير البيانات (DEK) المشفّر باستخدام مفتاح تشفير المفتاح (KEK).
- يتم فك تشفير النص المشفّر محليًا باستخدام مفتاح DEK.
يوضّح المثال التالي كيفية استخدام العنصر الأساسي KmsEnvelopeAead.
C++
في هذا المثال، تحتاج إلى إضافة Google Cloud KMS
tink-cc-gcpkms.
// A command-line utility for testing Tink Envelope AEAD with Google Cloud KMS. #include <fstream> #include <iostream> #include <memory> #include <ostream> #include <sstream> #include <string> #include <utility> #include "absl/flags/parse.h" #include "absl/flags/flag.h" #include "absl/log/check.h" #include "absl/log/log.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "tink/aead.h" #include "tink/aead/aead_config.h" #include "tink/aead/aead_key_templates.h" #include "tink/aead/kms_envelope_aead.h" #include "tink/integration/gcpkms/gcp_kms_client.h" #include "proto/tink.pb.h" ABSL_FLAG(std::string, mode, "", "Mode of operation {encrypt|decrypt}"); ABSL_FLAG(std::string, kek_uri, "", "URI of the KMS Key Encryption Key to use"); ABSL_FLAG(std::string, input_filename, "", "Input file name"); ABSL_FLAG(std::string, output_filename, "", "Output file name"); ABSL_FLAG(std::string, credentials, "", "Optional Google Cloud KMS credentials file path; if not specified, " "use the default credentials"); ABSL_FLAG(std::string, associated_data, "", "Optional associated data"); namespace { using ::crypto::tink::Aead; using ::crypto::tink::AeadKeyTemplates; using ::crypto::tink::integration::gcpkms::GcpKmsClient; using ::google::crypto::tink::KeyTemplate; constexpr absl::string_view kEncrypt = "encrypt"; constexpr absl::string_view kDecrypt = "decrypt"; void ValidateParams() { // ... } absl::StatusOr<std::string> ReadFile(absl::string_view filename) { // ... } absl::Status WriteToFile(absl::string_view data_to_write, absl::string_view filename) { // ... } } // namespace namespace tink_cc_gcpkms_examples { void KmsEnvelopAeadCli(absl::string_view mode, absl::string_view kek_uri, absl::string_view input_filename, absl::string_view output_filename, absl::string_view credentials, absl::string_view associated_data) { CHECK_OK(crypto::tink::AeadConfig::Register()); // Obtain a remote Aead that can use the KEK. absl::StatusOr<std::unique_ptr<GcpKmsClient>> gcp_kms_client = GcpKmsClient::New(kek_uri, credentials); CHECK_OK(gcp_kms_client.status()); absl::StatusOr<std::unique_ptr<Aead>> remote_aead = (*gcp_kms_client)->GetAead(kek_uri); CHECK_OK(remote_aead.status()); // Define the DEK template. KeyTemplate dek_key_template = AeadKeyTemplates::Aes256Gcm(); // Create a KmsEnvelopeAead instance. absl::StatusOr<std::unique_ptr<Aead>> aead = crypto::tink::KmsEnvelopeAead::New(dek_key_template, *std::move(remote_aead)); CHECK_OK(aead.status()); absl::StatusOr<std::string> input_file_content = ReadFile(input_filename); CHECK_OK(input_file_content.status()); if (mode == kEncrypt) { // Generate the ciphertext. absl::StatusOr<std::string> encrypt_result = (*aead)->Encrypt(*input_file_content, associated_data); CHECK_OK(encrypt_result.status()); CHECK_OK(WriteToFile(encrypt_result.value(), output_filename)); } else { // mode == kDecrypt. // Recover the plaintext. absl::StatusOr<std::string> decrypt_result = (*aead)->Decrypt(*input_file_content, associated_data); CHECK_OK(decrypt_result.status()); CHECK_OK(WriteToFile(decrypt_result.value(), output_filename)); } } } // namespace tink_cc_gcpkms_examples int main(int argc, char** argv) { absl::ParseCommandLine(argc, argv); ValidateParams(); std::string mode = absl::GetFlag(FLAGS_mode); std::string kek_uri = absl::GetFlag(FLAGS_kek_uri); std::string input_filename = absl::GetFlag(FLAGS_input_filename); std::string output_filename = absl::GetFlag(FLAGS_output_filename); std::string credentials = absl::GetFlag(FLAGS_credentials); std::string associated_data = absl::GetFlag(FLAGS_associated_data); LOG(INFO) << "Using kek-uri " << kek_uri << " with " << (credentials.empty() ? "default credentials" : absl::StrCat("credentials file ", credentials)) << " to envelope " << mode << " file " << input_filename << " with associated data '" << associated_data << "'." << '\n'; LOG(INFO) << "The resulting output will be written to " << output_filename << '\n'; tink_cc_gcpkms_examples::KmsEnvelopAeadCli(mode, kek_uri, input_filename, output_filename, credentials, associated_data); return 0; }
Go
import ( "fmt" "log" "github.com/tink-crypto/tink-go/v2/aead" "github.com/tink-crypto/tink-go/v2/testing/fakekms" ) // The fake KMS should only be used in tests. It is not secure. const keyURI = "fake-kms://CM2b3_MDElQKSAowdHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuY3J5cHRvLnRpbmsuQWVzR2NtS2V5EhIaEIK75t5L-adlUwVhWvRuWUwYARABGM2b3_MDIAE" func Example_kmsEnvelopeAEAD() { // Get a KEK (key encryption key) AEAD. This is usually a remote AEAD to a KMS. In this example, // we use a fake KMS to avoid making RPCs. client, err := fakekms.NewClient(keyURI) if err != nil { log.Fatal(err) } kekAEAD, err := client.GetAEAD(keyURI) if err != nil { log.Fatal(err) } // Get the KMS envelope AEAD primitive. primitive := aead.NewKMSEnvelopeAEAD2(aead.AES256GCMKeyTemplate(), kekAEAD) // Use the primitive. plaintext := []byte("message") associatedData := []byte("example KMS envelope AEAD encryption") ciphertext, err := primitive.Encrypt(plaintext, associatedData) if err != nil { log.Fatal(err) } decrypted, err := primitive.Decrypt(ciphertext, associatedData) if err != nil { log.Fatal(err) } fmt.Println(string(decrypted)) // Output: message }
جافا
في هذا المثال، تحتاج إلى إضافة Google Cloud KMS
tink-java-gcpkms.
package envelopeaead; import static java.nio.charset.StandardCharsets.UTF_8; import com.google.crypto.tink.Aead; import com.google.crypto.tink.KmsClient; import com.google.crypto.tink.aead.AeadConfig; import com.google.crypto.tink.aead.KmsEnvelopeAead; import com.google.crypto.tink.aead.PredefinedAeadParameters; import com.google.crypto.tink.integration.gcpkms.GcpKmsClient; import java.io.File; import java.io.FileOutputStream; import java.nio.file.Files; import java.nio.file.Paths; import java.security.GeneralSecurityException; /** * A command-line utility for encrypting small files with envelope encryption. * * <p>It requires the following arguments: * * <ul> * <li>mode: Can be "encrypt" or "decrypt" to encrypt/decrypt the input to the output. * <li>kek-uri: Use this Cloud KMS' key as the key-encrypting-key for envelope encryption. * <li>gcp-credential-file: Use this JSON credential file to connect to Cloud KMS. * <li>input-file: Read the input from this file. * <li>output-file: Write the result to this file. * <li>[optional] associated-data: Associated data used for the encryption or decryption. */ public final class EnvelopeAeadExample { private static final String MODE_ENCRYPT = "encrypt"; private static final String MODE_DECRYPT = "decrypt"; public static void main(String[] args) throws Exception { if (args.length != 5 && args.length != 6) { System.err.printf("Expected 5 or 6 parameters, got %d\n", args.length); System.err.println( "Usage: java EnvelopeAeadExample encrypt/decrypt kek-uri gcp-credential-file" + " input-file output-file [associated-data]"); System.exit(1); } String mode = args[0]; String kekUri = args[1]; String gcpCredentialFilename = args[2]; byte[] input = Files.readAllBytes(Paths.get(args[3])); File outputFile = new File(args[4]); byte[] associatedData = new byte[0]; if (args.length == 6) { System.out.println("Associated data!"); associatedData = args[5].getBytes(UTF_8); } // Initialise Tink: register all AEAD key types with the Tink runtime AeadConfig.register(); // Read the GCP credentials and create a remote AEAD object. Aead remoteAead = null; try { KmsClient kmsClient = new GcpKmsClient().withCredentials(gcpCredentialFilename); remoteAead = kmsClient.getAead(kekUri); } catch (GeneralSecurityException ex) { System.err.println("Error initializing GCP client: " + ex); System.exit(1); } // Create envelope AEAD primitive using AES256 GCM for encrypting the data Aead aead = KmsEnvelopeAead.create(PredefinedAeadParameters.AES256_GCM, remoteAead); // Use the primitive to encrypt/decrypt files. if (MODE_ENCRYPT.equals(mode)) { byte[] ciphertext = aead.encrypt(input, associatedData); try (FileOutputStream stream = new FileOutputStream(outputFile)) { stream.write(ciphertext); } } else if (MODE_DECRYPT.equals(mode)) { byte[] plaintext = aead.decrypt(input, associatedData); try (FileOutputStream stream = new FileOutputStream(outputFile)) { stream.write(plaintext); } } else { System.err.println("The first argument must be either encrypt or decrypt, got: " + mode); System.exit(1); } System.exit(0); } private EnvelopeAeadExample() {} }
Python
"""A command-line utility for encrypting small files using envelope encryption with GCP.""" from absl import app from absl import flags from absl import logging import tink from tink import aead from tink.integration import gcpkms FLAGS = flags.FLAGS flags.DEFINE_enum( 'mode', None, ['encrypt', 'decrypt'], 'The operation to perform.' ) flags.DEFINE_string( 'kek_uri', None, 'The Cloud KMS URI of the key encryption key.' ) flags.DEFINE_string( 'gcp_credential_path', None, 'Path to the GCP credentials JSON file.' ) flags.DEFINE_string('input_path', None, 'Path to the input file.') flags.DEFINE_string('output_path', None, 'Path to the output file.') flags.DEFINE_string( 'associated_data', None, 'Optional associated data used for the encryption.' ) def main(argv): del argv # Unused. associated_data = ( b'' if not FLAGS.associated_data else bytes(FLAGS.associated_data, 'utf-8') ) # Initialise Tink aead.register() try: # Read the GCP credentials and setup client client = gcpkms.GcpKmsClient(FLAGS.kek_uri, FLAGS.gcp_credential_path) except tink.TinkError as e: logging.exception('Error creating GCP KMS client: %s', e) return 1 # Create envelope AEAD primitive using AES256 GCM for encrypting the data try: remote_aead = client.get_aead(FLAGS.kek_uri) env_aead = aead.KmsEnvelopeAead( aead.aead_key_templates.AES256_GCM, remote_aead ) except tink.TinkError as e: logging.exception('Error creating primitive: %s', e) return 1 with open(FLAGS.input_path, 'rb') as input_file: input_data = input_file.read() if FLAGS.mode == 'decrypt': output_data = env_aead.decrypt(input_data, associated_data) elif FLAGS.mode == 'encrypt': output_data = env_aead.encrypt(input_data, associated_data) else: logging.error( 'Unsupported mode %s. Please choose "encrypt" or "decrypt".', FLAGS.mode, ) return 1 with open(FLAGS.output_path, 'wb') as output_file: output_file.write(output_data) if __name__ == '__main__': flags.mark_flags_as_required( ['mode', 'kek_uri', 'gcp_credential_path', 'input_path', 'output_path'] ) app.run(main)
الخطوات التالية
يمكنك استخدام التشفير من جهة العميل لتشفير البيانات قبل إضافتها إلى قاعدة بيانات Cloud SQL.
يمكنك الاطّلاع على مزيد من المعلومات حول استخدام التشفير من جهة العميل مع Tink وCloud KMS لتشفير البيانات قبل تحميلها إلى Google Cloud Storage.