Я хочу зашифровать данные

Для большинства случаев шифрования данных мы рекомендуем использовать примитив AEAD с типом ключа AES128_GCM .

Аутентифицированное шифрование с ассоциированными данными (AEAD) — самый простой и подходящий примитив для большинства случаев использования. AEAD обеспечивает секретность и подлинность, а также гарантирует, что сообщения всегда имеют разные шифротексты (зашифрованные выходные данные), даже если открытые тексты (входные данные для шифрования) одинаковы. Этот алгоритм симметричен, поскольку для шифрования и дешифрования используется один и тот же ключ.

Следующие примеры помогут вам начать использовать примитив AEAD:

С++

// A command-line utility for testing Tink AEAD.
#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/aead.h"
#include "tink/aead/aead_config.h"
#include "tink/config/global_registry.h"
#include "util/util.h"
#include "tink/keyset_handle.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 {encrypt|decrypt}");
ABSL_FLAG(std::string, input_filename, "", "Filename to operate on");
ABSL_FLAG(std::string, output_filename, "", "Output file name");
ABSL_FLAG(std::string, associated_data, "",
          "Associated data for AEAD (default: empty");

namespace {

using ::crypto::tink::Aead;
using ::crypto::tink::AeadConfig;
using ::crypto::tink::KeysetHandle;
using ::crypto::tink::util::Status;
using ::crypto::tink::util::StatusOr;

constexpr absl::string_view kEncrypt = "encrypt";
constexpr absl::string_view kDecrypt = "decrypt";

void ValidateParams() {
  // ...
}

}  // namespace

namespace tink_cc_examples {

// AEAD example CLI implementation.
Status AeadCli(absl::string_view mode, const std::string& keyset_filename,
               const std::string& input_filename,
               const std::string& output_filename,
               absl::string_view associated_data) {
  Status result = AeadConfig::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();

  // Get the primitive.
  StatusOr<std::unique_ptr<Aead>> aead =
      (*keyset_handle)
          ->GetPrimitive<crypto::tink::Aead>(
              crypto::tink::ConfigGlobalRegistry());
  if (!aead.ok()) return aead.status();

  // Read the input.
  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) {
    StatusOr<std::string> encrypt_result =
        (*aead)->Encrypt(*input_file_content, associated_data);
    if (!encrypt_result.ok()) return encrypt_result.status();
    output = encrypt_result.value();
  } else {  // operation == kDecrypt.
    StatusOr<std::string> decrypt_result =
        (*aead)->Decrypt(*input_file_content, associated_data);
    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 associated_data = absl::GetFlag(FLAGS_associated_data);

  std::clog << "Using keyset from file " << keyset_filename << " to AEAD-"
            << mode << " file " << input_filename << " with associated data '"
            << associated_data << "'." << '\n';
  std::clog << "The resulting output will be written to " << output_filename
            << '\n';

  CHECK_OK(tink_cc_examples::AeadCli(mode, keyset_filename, input_filename,
                                     output_filename, associated_data));
  return 0;
}

Идти

import (
	"bytes"
	"fmt"
	"log"

	"github.com/tink-crypto/tink-go/v2/aead"
	"github.com/tink-crypto/tink-go/v2/insecurecleartextkeyset"
	"github.com/tink-crypto/tink-go/v2/keyset"
)

func Example() {
	// A keyset created with "tinkey create-keyset --key-template=AES256_GCM". Note
	// that this keyset has the secret key information in cleartext.
	jsonKeyset := `{
			"key": [{
					"keyData": {
							"keyMaterialType":
									"SYMMETRIC",
							"typeUrl":
									"type.googleapis.com/google.crypto.tink.AesGcmKey",
							"value":
									"GiBWyUfGgYk3RTRhj/LIUzSudIWlyjCftCOypTr0jCNSLg=="
					},
					"keyId": 294406504,
					"outputPrefixType": "TINK",
					"status": "ENABLED"
			}],
			"primaryKeyId": 294406504
	}`

	// 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 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.
	keysetHandle, err := insecurecleartextkeyset.Read(
		keyset.NewJSONReader(bytes.NewBufferString(jsonKeyset)))
	if err != nil {
		log.Fatal(err)
	}

	// Retrieve the AEAD primitive we want to use from the keyset handle.
	primitive, err := aead.New(keysetHandle)
	if err != nil {
		log.Fatal(err)
	}

	// Use the 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).
	plaintext := []byte("message")
	associatedData := []byte("associated data")
	ciphertext, err := primitive.Encrypt(plaintext, associatedData)
	if err != nil {
		log.Fatal(err)
	}

	// Use the 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 returns an error.
	decrypted, err := primitive.Decrypt(ciphertext, associatedData)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(decrypted))
	// Output: message
}

Ява

package aead;

import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.crypto.tink.Aead;
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.aead.AeadConfig;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * A command-line utility for encrypting small files with AEAD.
 *
 * <p>It loads cleartext keys from disk - this is not recommended!
 *
 * <p>It requires the following arguments:
 *
 * <ul>
 *   <li>mode: Can be "encrypt" or "decrypt" to encrypt/decrypt the input to the output.
 *   <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] associated-data: Associated data used for the encryption or decryption.
 */
public final class AeadExample {
  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 != 4 && args.length != 5) {
      System.err.printf("Expected 4 or 5 parameters, got %d\n", args.length);
      System.err.println(
          "Usage: java AeadExample encrypt/decrypt key-file input-file output-file"
              + " [associated-data]");
      System.exit(1);
    }
    String mode = args[0];
    Path keyFile = Paths.get(args[1]);
    Path inputFile = Paths.get(args[2]);
    Path outputFile = Paths.get(args[3]);
    byte[] associatedData = new byte[0];
    if (args.length == 5) {
      associatedData = args[4].getBytes(UTF_8);
    }
    // Register all AEAD key types with the Tink runtime.
    AeadConfig.register();

    // Read the keyset into a KeysetHandle.
    KeysetHandle handle =
        TinkJsonProtoKeysetFormat.parseKeyset(
            new String(Files.readAllBytes(keyFile), UTF_8), InsecureSecretKeyAccess.get());

    // Get the primitive.
    Aead aead = handle.getPrimitive(RegistryConfiguration.get(), Aead.class);

    // Use the primitive to encrypt/decrypt files.
    if (MODE_ENCRYPT.equals(mode)) {
      byte[] plaintext = Files.readAllBytes(inputFile);
      byte[] ciphertext = aead.encrypt(plaintext, associatedData);
      Files.write(outputFile, ciphertext);
    } else if (MODE_DECRYPT.equals(mode)) {
      byte[] ciphertext = Files.readAllBytes(inputFile);
      byte[] plaintext = aead.decrypt(ciphertext, associatedData);
      Files.write(outputFile, plaintext);
    } else {
      System.err.println("The first argument must be either encrypt or decrypt, got: " + mode);
      System.exit(1);
    }
  }

  private AeadExample() {}
}

Obj-C

КАК

Питон

import tink
from tink import aead
from tink import secret_key_access


def example():
  """Encrypt and decrypt using AEAD."""
  # Register the AEAD key managers. This is needed to create an Aead primitive
  # later.
  aead.register()

  # A keyset created with "tinkey create-keyset --key-template=AES256_GCM". Note
  # that this keyset has the secret key information in cleartext.
  keyset = r"""{
      "key": [{
          "keyData": {
              "keyMaterialType":
                  "SYMMETRIC",
              "typeUrl":
                  "type.googleapis.com/google.crypto.tink.AesGcmKey",
              "value":
                  "GiBWyUfGgYk3RTRhj/LIUzSudIWlyjCftCOypTr0jCNSLg=="
          },
          "keyId": 294406504,
          "outputPrefixType": "TINK",
          "status": "ENABLED"
      }],
      "primaryKeyId": 294406504
  }"""

  # Create a keyset handle from the cleartext keyset in the previous
  # step. The keyset handle provides abstract access to the underlying keyset to
  # limit access of the raw key material. WARNING: In practice, it is unlikely
  # you will want to use a cleartext_keyset_handle, as it implies that your key
  # material is passed in cleartext, which is a security risk.
  keyset_handle = tink.json_proto_keyset_format.parse(
      keyset, secret_key_access.TOKEN
  )

  # Retrieve the Aead primitive we want to use from the keyset handle.
  primitive = keyset_handle.primitive(aead.Aead)

  # Use the 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 = primitive.encrypt(b'msg', b'associated_data')

  # Use the 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.
  output = primitive.decrypt(ciphertext, b'associated_data')

АЭАД

Примитив аутентифицированного шифрования со связанными данными (AEAD) является наиболее распространенным примитивом для шифрования данных и подходит для большинства нужд.

AEAD обладает следующими свойствами:

  • Секретность : об открытом тексте ничего не известно, кроме его длины.
  • Подлинность : невозможно изменить зашифрованный открытый текст, лежащий в основе шифртекста, без обнаружения.
  • Симметричный : шифрование открытого текста и расшифровка зашифрованного текста выполняется одним и тем же ключом.
  • Рандомизация : шифрование рандомизировано. Два сообщения с одинаковым открытым текстом дают разные шифртексты. Злоумышленники не могут знать, какой шифртекст соответствует данному открытому тексту. Чтобы избежать этого, используйте детерминированный AEAD .

Связанные данные

AEAD можно использовать для привязки шифротекста к определённым связанным данным . Предположим, у вас есть база данных с полями user-id и encrypted-medical-history . В этом случае user-id можно использовать в качестве связанных данных при шифровании encrypted-medical-history . Это предотвращает передачу злоумышленником истории болезни от одного пользователя к другому.

Связанные данные необязательны. Если они указаны, расшифровка будет успешной только в том случае, если одни и те же связанные данные передаются как в вызовы шифрования, так и в вызовы дешифрования.

Выберите тип ключа

Хотя мы рекомендуем AES128_GCM для большинства случаев применения, существуют различные типы ключей для разных нужд (для 256-битной защиты замените AES128 на AES256 ниже). Как правило:

  • AES128_CTR_HMAC_SHA256 с 16-байтовым вектором инициализации (IV) является наиболее консервативным режимом с хорошими границами.
  • AES128_EAX немного менее консервативен и немного быстрее, чем AES128_CTR_HMAC_SHA256.
  • AES128_GCM обычно является самым быстрым режимом с самыми строгими ограничениями на количество и размер сообщений. При превышении этих ограничений на длину открытого текста и связанных с ним данных (см. ниже) AES128_GCM выходит из строя, что приводит к утечке ключевого материала.
  • AES128_GCM_SIV почти так же быстр, как AES128_GCM. Он имеет те же ограничения, что и AES128_GCM, по количеству и размеру сообщений, но при превышении этих ограничений сбой происходит менее катастрофично: возможна лишь утечка информации об эквивалентности двух сообщений. Это делает его более безопасным, чем AES128_GCM, но на практике он применяется реже. Для использования в Java необходимо установить Conscrypt .
  • XChaCha20Poly1305 имеет гораздо большее ограничение на количество и размер сообщений, чем AES128_GCM, но в случае сбоя (что крайне маловероятно) происходит утечка ключевого материала. XChaCha20Poly1305 не поддерживает аппаратное ускорение, поэтому может работать медленнее, чем режимы AES, если доступно аппаратное ускорение.

Гарантии безопасности

Реализации AEAD предлагают:

  • Безопасность CCA2.
  • Уровень стойкости аутентификации не менее 80 бит.
  • Возможность шифрования не менее 2 32 сообщений общим размером 2 50 байт. Ни одна атака с использованием до 2 32 выбранных открытых текстов или шифртекстов не имеет вероятности успеха более 2 -32 .