Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Una llamada como encrypt($objeto) seguida de decrypt($ciphertext) funciona porque la biblioteca añade una capa de serialización: convierte el valor en JSON antes de cifrarlo y reconstruye el valor después de descifrarlo. Las primitivas de cifrado no hacen eso. openssl_encrypt() en PHP y SubtleCrypto.encrypt() en JavaScript trabajan con datos binarios o de texto, una clave y parámetros; no aceptan objetos. El título no nombra una biblioteca concreta, así que este artículo toma como caso probable un paquete PHP/JavaScript que documente esa conversión automática y explica qué tienes que alinear entre ambos lados para que un mensaje cifrado en uno se pueda descifrar en el otro.

Qué hace realmente la llamada cómoda

El patrón tiene este aspecto en código. La forma exacta de los argumentos depende de la biblioteca, así que trátalo como ilustración y no como firma de una API concreta:

$biblioteca = /* instancia del paquete que documente encrypt() y decrypt() */;

$cifrado = $biblioteca->encrypt([
    'usuario' => 'ana',
    'roles'   => ['lectora', 'editora'],
    'activo'  => true,
]);

$datos = $biblioteca->decrypt($cifrado);
// $datos vuelve a ser un array PHP con la misma estructura

Por dentro ocurre una secuencia de pasos que la llamada oculta. Conocerla es lo que te permite depurar cuando algo no coincide:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Serialización: el valor pasa a texto JSON. En PHP se usa json_encode(); en JavaScript, JSON.stringify().
  2. Cifrado: el texto resultante se convierte en bytes y se cifra con el algoritmo, la clave y el IV o nonce que la biblioteca haya elegido.
  3. Empaquetado: el IV, el salt si existe, la etiqueta de autenticación si existe, un marcador de serializador o de versión y el ciphertext se combinan en una cadena (hexadecimal, base64 u otro formato).
  4. Descifrado: la biblioteca separa el contenedor, descifra, decodifica el JSON con json_decode() o JSON.parse() y devuelve el valor.

La parte que el usuario no ve es la que más fallos causa en integraciones entre lenguajes. Si el paso 1 produce bytes distintos en PHP y en JavaScript, el cifrado en sí puede ser correcto y aun así la autenticación, cuando existe, fallará al otro lado.

Por qué encrypt() no acepta objetos en las APIs básicas

Esta distinción evita la idea equivocada de que cualquier función llamada encrypt() serializa objetos. Las primitivas trabajan a otro nivel:

Aspecto openssl_encrypt() (PHP) SubtleCrypto.encrypt() (JavaScript)
Qué recibe como datos Una cadena de datos (string) Un BufferSource, es decir, un ArrayBuffer o una vista tipada
Cómo se indica el algoritmo Un nombre de método de cifrado, por ejemplo aes-256-cbc Un objeto de algoritmo con su nombre y parámetros, por ejemplo AES-GCM con su iv
Clave Una cadena de clave (passphrase) o la clave que se pase a la función Un objeto CryptoKey
Objetos y arrays No se serializan No se serializan
Etiqueta de autenticación en modos AEAD Se obtiene por separado mediante el parámetro de etiqueta Se añade al final del resultado de encrypt()

Consulta la referencia de PHP: openssl_encrypt y la de MDN: SubtleCrypto encrypt() para los parámetros exactos de tu versión. La conversión JSON es responsabilidad de tu código o de la biblioteca envolvente.

Bibliotecas observadas: dos enfoques distintos

Hay dos casos documentados que ilustran el patrón, y no son intercambiables por defecto.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Aspecto brainfoolong/js-aes-php 1.0.5 InitPHP Encryption
Lenguajes documentados Valores JavaScript que pasen a JSON.stringify y valores PHP que pasen a json_encode; cifrado y descifrado en ambos lenguajes PHP; encrypt() acepta mixed
Algoritmo AES-256-CBC, con salts y IV aleatorios según su ficha en Packagist No indicado en el README consultado
Serialización JSON en ambos lados JSON por defecto, con una marca del serializador embebida en el ciphertext para restaurar el tipo
Autenticación No documentada en la ficha revisada; no la des por supuesta Por defecto: HMAC con OpenSSL o AEAD de Sodium
Formato de salida Hexadecimal; sus notas advierten que no es un reemplazo directo de la biblioteca antecesora Formato versionado; según el README, tras un cambio mayor se rechazan ciphertexts antiguos
Fuente brainfoolong/js-aes-php en Packagist, versión 1.0.5, consultada en 2026 InitPHP Encryption README

La primera opción cubre el caso PHP/JavaScript de forma explícita, pero su ficha no documenta autenticación. La segunda documenta autenticación y versionado, pero su README consultado solo describe PHP. Si necesitas ambos lados, verifica en el código y la documentación de la versión que vas a usar qué garantías existen en cada runtime.

Interoperabilidad PHP y JavaScript: qué debe coincidir

Si un extremo cifra y otro descifra, ambos deben acordar cada una de estas decisiones. Una sola diferencia basta para que el descifrado falle:

  • Algoritmo y modo, incluido el tamaño de clave.
  • Cómo se obtiene la clave: bytes directos, contraseña con derivación, o salt y número de iteraciones si los hay.
  • IV o nonce: su longitud, cómo se genera y cómo se transmite.
  • Padding o etiqueta de autenticación, según el modo.
  • Codificación de entrada y salida: UTF-8, base64 o hexadecimal.
  • La forma exacta del contenedor: orden de los campos, separadores y marcadores de versión.
  • Las reglas JSON que se aceptan al decodificar.

Diferencias de JSON que cambian los bytes

Dos runtimes pueden representar el mismo valor con JSON distinto. Esto no afecta al descifrado si no hay autenticación sobre el texto, pero rompe la verificación cuando la hay:

  • Barras: json_encode() escapa / como / por defecto; JSON.stringify() no lo hace.
  • Unicode: PHP escapa caracteres no ASCII como uXXXX salvo que uses las opciones de la función; JavaScript los deja tal cual.
  • Arrays vacíos y objetos vacíos: en PHP, un array vacío se convierte en [], aunque quisieras {}.
  • Claves: los arrays PHP conservan el orden de inserción; los objetos JavaScript colocan primero las claves enteras en orden ascendente.
  • Números: los enteros por encima de 2^53 pierden precisión en JavaScript.
  • Errores: json_encode() devuelve false si falla, salvo que uses JSON_THROW_ON_ERROR; JSON.stringify() lanza excepción con referencias circulares o valores BigInt.

Prueba cruzada mínima

Antes de integrar datos reales, comprueba la ida y la vuelta con el mismo conjunto de valores:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Prepara valores de prueba: escalares, una lista, un objeto anidado, texto con acentos y emojis, null, una cadena vacía y un valor inválido que deba fallar.
  2. Cifra cada valor en PHP, copia el resultado tal cual a JavaScript y descífralo allí. Compara el valor reconstruido con el original, no solo que no haya error.
  3. Invierte la dirección: cifra en JavaScript y descifra en PHP.
  4. Para el valor inválido, confirma que el descifrado falla de forma explícita y no devuelve texto parcial.
  5. Repite la prueba con una clave incorrecta y con un ciphertext alterado un byte. Si el descifrado no falla en el segundo caso, la biblioteca no autentica el ciphertext en esa configuración.

Esta secuencia es una recomendación de verificación; no equivale a un resultado de pruebas ejecutadas para este artículo.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Seguridad antes de llevarlo a producción

Autenticidad e integridad

Un descifrado que termina sin error no demuestra que el mensaje no haya sido modificado. El cifrado en modo CBC sin etiqueta no detecta alteraciones del ciphertext. Verifica en la documentación de tu versión si existe HMAC, AEAD como AES-GCM o ChaCha20-Poly1305, o una combinación equivalente, y cómo se verifica antes de devolver datos.

Claves

Derivar una clave del tamaño requerido a partir de una cadena no le añade entropía. InitPHP Encryption advierte de esto y recomienda una clave aleatoria de 256 bits en producción, guardada fuera del repositorio. Genera la clave con un generador criptográfico del sistema y almacénala en variables de entorno, un gestor de secretos o un almacén del sistema operativo.

Serialización segura

JSON no instancia clases de PHP al decodificar, a diferencia de lo que puede ocurrir con unserialize(), y eso reduce la superficie de ataque. Tiene, sin embargo, un límite: el JSON de InitPHP no transporta bytes binarios sin procesar. Si tus datos incluyen binario, codifícalos explícitamente en base64 o en otro formato antes de serializar.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Errores y versiones de formato

Un descifrado fallido debe devolver un error, nunca un valor parcial. Si cambias el formato, identifica la versión en el contenedor y decide si migrarás los ciphertexts antiguos o los rechazarás. InitPHP documenta el rechazo de ciphertexts antiguos tras un cambio mayor; si usas otra biblioteca, comprueba su política.

Cifrado en el navegador

Si JavaScript necesita descifrar, la clave debe estar disponible en el cliente, y quien controle ese cliente puede leerla. Antes de cifrar en el navegador, define el modelo de amenaza: si el objetivo es proteger datos frente al propio usuario o frente a un script malicioso, el cifrado en el cliente no lo resuelve por sí solo.

Un ejemplo antiguo que no conviene copiar

Una respuesta de Stack Overflow muestra un patrón de cifrado PHP y descifrado con CryptoJS que usa JSON, pero su propio autor advierte de una vulnerabilidad de chosen-ciphertext attack en el código publicado. Consulta la discusión original como referencia histórica, no como implementación.

Fija la biblioteca y la versión exactas, verifica el modo de autenticación en su código y valida el resultado contra su documentación vigente antes de publicar cualquier fragmento en producción.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Lista de verificación de integración

  • Documenta el algoritmo, el modo, la forma de derivar la clave y el formato del contenedor.
  • Confirma que el descifrado rechaza ciphertexts alterados y claves incorrectas.
  • Decide la codificación de datos binarios antes de serializar.
  • Activa el manejo de errores de JSON en PHP (JSON_THROW_ON_ERROR) y captura las excepciones de JSON.parse() en JavaScript.
  • Guarda las claves fuera del código fuente y planifica la rotación.
  • Incluye un número de versión en el formato desde el primer día.

Solución de problemas frecuentes

Síntoma Causa probable Qué revisar
Descifrado devuelve error sin más detalle Clave, IV, algoritmo o codificación distintos Parámetros en ambos lados, en ese orden
Descifrado funciona en un sentido y no en el otro Codificación de salida o contenedor diferente Formato de salida (hexadecimal frente a base64) y la etiqueta de autenticación en Web Crypto
La verificación falla aunque la clave coincida JSON distinto al serializar (escapes, orden de claves) Opciones de json_encode() y forma de autenticar el texto
El valor vuelve como array en lugar de objeto Ausencia de marca de tipo o decodificación asociativa distinta Opciones de json_decode() y JSON.parse(); si la biblioteca embebe marca de serializador, confírmala
Ciphertexts antiguos dejan de funcionar tras actualizar Cambio de versión de formato Notas de versión de la biblioteca y rechazo de versiones anteriores

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.