Formato de hilo tink

En esta página, se describe el formato de cable de Tink para las claves y el resultado de los elementos primitivos. La documentación está dirigida a criptógrafos que deseen agregar idiomas adicionales a Tink y a mantenedores de otras bibliotecas criptográficas de alto nivel que deseen un modo compatible con el cable. No está dirigido al público en general.

Serialización del conjunto de claves

Tink usa protobuf de Google para serializar sus conjuntos de claves.

  • Un conjunto de claves serializado binario es un proto de Keyset serializado definido en tink.proto. La propiedad de valor KeyData de una clave es un proto serializado del tipo de clave correspondiente.
  • Un conjunto de claves serializado en JSON es un proto de Keyset serializado en formato JSON. Ten en cuenta que el valor de KeyData sigue siendo un proto serializado binario.
  • Un conjunto de claves encriptado es un proto de EncryptedKeyset serializado que se define en tink.proto. Contiene un conjunto de claves serializado binario encriptado y, de manera opcional, algunos metadatos de KeysetInfo sin encriptar.

Prefijo de salida de Tink

La mayoría de las primitivas de Tink admiten un prefijo de salida de 5 bytes que consta de lo siguiente:

  • Versión de 1 byte: 0x01
  • Sugerencia de clave de 4 bytes: Es el ID de la clave que se usó.

Es posible que algunas claves heredadas también admitan el byte de versión 0x00.

Ten en cuenta que este prefijo no está autenticado y no se puede usar con fines de seguridad. Tink lo usa como sugerencia para acelerar el proceso de desencriptación o verificación.

AEAD

En general, Tink formatea los textos cifrados de AEAD de la siguiente manera:

prefix || IV || ciphertext || tag

a menos que se especifique lo contrario en el RFC correspondiente. prefix está vacío o es un prefijo de salida de Tink de 5 bytes.

AES-CTR-HMAC

En el caso de AES-CTR-HMAC, Tink calcula el MAC con datos asociados (AD) de la siguiente manera:

AD || IV || ciphertext || bitlen(AD)

donde bitlen(AD) es la longitud del anuncio en bits, representada como un número entero sin signo de 64 bits big-endian. Este esquema de HMAC sigue el borrador de AES-CBC-HMAC de McGrew.

AEAD determinístico

Tink implementa el RFC 5297 para AES-SIV, lo que coloca el vector de inicialización sintética (SIV) al comienzo del texto cifrado. El elemento primitivo puede agregar un prefijo de salida de Tink de 5 bytes.

Si bien el RFC 5297 admite una lista de datos asociados, Tink solo admite exactamente un dato asociado, que corresponde a una lista con un elemento en el RFC 5297. Los datos asociados vacíos son una lista con un elemento vacío, no una lista vacía.

AEAD de transmisión

Consulta HMAC de AES-CTR y HKDF de AES-GCM.

Encriptación de sobre

La encriptación de sobre encripta los datos con una clave de encriptación de datos DEK usando las primitivas AEAD de Tink. La encriptación funciona de la siguiente manera:

  • Se genera un nuevo DEK con una plantilla de clave (o parámetros de clave) determinada.
  • El DEK se serializa en una cadena de bytes. Es el formato de serialización del búfer de protocolo serializado del proto del tipo de clave. Por ejemplo, este es un mensaje de búfer de protocolo AesGcmKey serializado definido en aes_gcm.proto para la DEK del tipo de clave AES GCM. Consulta serialización de búfer de protocolo para obtener información sobre cómo serializar un búfer de protocolo.
  • Un proveedor externo (por ejemplo, GCP) encripta el DEK serializado en un encrypted DEK.
  • El DEK se usa para encriptar el texto simple con los datos asociados en ciphertext. Por lo tanto, ciphertext tiene exactamente el mismo formato que la primitiva AEAD correspondiente a DEK.

El formato de salida de la encriptación de sobre es el siguiente:

encrypted DEK length || encrypted DEK || ciphertext

El encrypted DEK length tiene 4 bytes y almacena la longitud del encrypted DEK como un número entero big-endian de 32 bits.

MAC

Tink sigue los RFC correspondientes. Los elementos primitivos pueden agregar un prefijo de salida de Tink de 5 bytes a la etiqueta.

Conjunto de PRF

Tink sigue los RFC correspondientes. Ten en cuenta que, para PRF, el tipo de clave difiere del tipo de clave MAC del mismo algoritmo, ya que no incluye la longitud de salida. Las claves de PRF Set nunca agregan un prefijo de salida de Tink. Esto garantiza que el resultado sea una PRF.

Encriptación híbrida

El formato de cable general para la encriptación híbrida de Tink es el siguiente:

prefix || encapsulated_key || encrypted_data

prefix está vacío o es un prefijo de salida de Tink de 5 bytes. Cada tipo de clave contiene la información sobre cuántos bytes se deben analizar y cómo analizarlos desde encapsulated_key.

HPKE (Hybrid Public Key Encryption)

Tink sigue el estándar de HPKE definido en RFC 9180. Un conjunto de algoritmos de HPKE incluye las siguientes tres primitivas.

  • Mecanismo de encapsulamiento de claves (KEM)
  • Función de derivación de claves (KDF)
  • Encriptación autenticada con datos asociados (AEAD)

El estándar HPKE no define un formato general de transmisión en RFC 9180, sección 10. La implementación de HPKE de Tink usa los siguientes valores de encapsulated_key y encrypted_data.

  • encapsulated_key
    • Clave pública serializada del remitente
    • Se define como enc en RFC 9180, sección 4.1
    • El formato está determinado por el KEM de HPKE específico que se usa.
  • encrypted_data
    • Texto cifrado y etiqueta (es decir, ciphertext || tag sin el IV)
    • Se define como ct en la sección 4 del RFC 9180.
    • El formato está determinado por el AEAD de HPKE específico que se usa.
KEM basado en Diffie-Hellman X25519

Para los DHKEM de X25519, el valor enc es la clave pública de Diffie-Hellman de 32 bytes del remitente.

ECIES-AEAD-HKDF

En la implementación de ECIES-AEAD-HKDF de Tink, encapsulated_key es el resultado del mecanismo de encapsulación de claves (KEM) y encrypted_data es el resultado del mecanismo de encapsulación de datos (DEM).

KEM

Según el tipo de clave, Tink usa puntos de curva elíptica comprimidos y sin comprimir, según los estándares de codificación RFC 8422/ANSI.X9-62.2005. En el caso de los puntos sin comprimir, el byte 0x04 está seguido de la coordenada x y la coordenada y como números enteros de tamaño fijo. Para las coordenadas comprimidas, se usan el byte 0x02 o 0x03 y la coordenada x como un número entero de tamaño fijo. Para X25519, se usa la definición de RFC 7748 (coordenada x como número entero de tamaño fijo).

DEM

Para encrypted_data, Tink usa el mismo formato que el AEAD. Esto incluye especificar un IV.

Derivación de claves

Primero, se calcula la coordenada X x_ss del punto compartido. Luego, la clave del AEAD se establece de la siguiente manera:

HKDF(ikm = encapsulated_key || x_ss, salt = salt_of_key, info = context_info, length = dem_key_size)

donde encapsulated_key es el resultado completo del KEM en bytes.

Firmas digitales

Tink sigue los RFC correspondientes. Las primitivas pueden agregar un prefijo de salida de Tink de 5 bytes a la etiqueta que se genera.

ECDSA

Según el campo EcdsaSignatureEncoding de la clave, el formato de una firma ECDSA es IEEE P1363 o ASN.1 DER.

El formato de la firma IEEE P1363 es r || s, en el que r y s se completan con ceros y tienen el mismo tamaño en bytes que el orden de la curva. Por ejemplo, para la curva NIST P-256, r y s se completan con ceros hasta alcanzar los 32 bytes.

La firma DER se codifica con ASN.1:

ECDSA-Sig-Value :: = SEQUENCE { r INTEGER, s INTEGER }

En particular, la codificación es la siguiente:

0x30 || totalLength || 0x02 || r's length || r || 0x02 || s's length || s

Tink sigue las prácticas recomendadas para la verificación de firmas, ya que solo acepta firmas ECDSA codificadas en DER (las firmas codificadas en BER alternativas no son válidas).

Esto ayuda a prevenir ataques de maleabilidad de firmas, que a menudo afectan a los sistemas de criptomonedas.

Valores de prehash de ML-DSA de Mu externo

La primitiva Prehash convierte un mensaje en un valor de prehash, que luego firma la primitiva SignPrehash. Para ML-DSA en el modo External Mu, como se describe en el RFC 9881, el valor previo al hash es de 69 bytes con el siguiente diseño:

0xff || key_id (4 bytes, big-endian) || mu (64 bytes)
  • mu es el representante del mensaje de ML-DSA, que se calcula como SHAKE256(tr || 0x00 || 0x00 || message, 64), donde tr es el hash de 64 bytes de la clave pública, el primer 0x00 es el separador de dominio de FIPS 204 para ML-DSA puro y el segundo 0x00 es la longitud de la cadena de contexto (vacía). Dado que tr se deriva de la clave pública, mu está vinculado criptográficamente a esa clave, aunque la verificación de la vinculación requiere el mensaje original.
  • El prefijo de 5 bytes es el encuadre de Tink y no forma parte de mu. Asocia el valor previo al hash con una clave específica, de modo que SignPrehash sepa con qué clave firmar y pueda rechazar un valor previo al hash para el que no tiene una clave. El prefijo son metadatos simples y no vincula nada de forma criptográfica: cualquiera puede reescribirlo.

La firma rechaza cualquier entrada que no tenga exactamente 69 bytes, que no comience con 0xff o cuyo ID de clave no coincida con una clave habilitada en su conjunto de claves.