HotXLS escribe un bloque dataIntegrity conforme en los paquetes XLSX cifrados en modo Agile y lo verifica al abrir. El HMAC-SHA-512 cubre el flujo EncryptedPackage completo, incluido su prefijo StreamSize de ocho bytes, y se comprueba sobre el texto cifrado antes de descifrar ningún segmento, así que una contraseña incorrecta o un paquete modificado se detecta en lugar de descifrarse como basura
El cifrado sin integridad es media respuesta, y los formatos de fichero de Office hacen fácil pasar por alto esa brecha porque el cifrado parece muy completo desde fuera. Entender lo que promete cada capa es lo que mantiene corta una revisión de seguridad
¿Qué promete realmente un libro cifrado?
El cifrado Agile, definido en [MS-OFFCRYPTO], le da confidencialidad mediante AES en modo CBC con una clave derivada de un hash de contraseña SHA-512 iterado. La confidencialidad es toda la promesa de esa construcción. CBC no es un modo autenticado: no dice nada sobre si el texto cifrado que se está descifrando es el texto cifrado que se escribió
La consecuencia práctica es concreta. Invierta bits en un paquete cifrado y CBC los descifrará encantado en texto plano distinto. Normalmente obtendrá un error de análisis ZIP en algún punto posterior, porque un flujo deflate corrupto raramente sobrevive, pero ese "normalmente" carga con mucho peso en esa frase, y un error de análisis posterior es un lugar terrible para enterarse de que un fichero fue modificado. El elemento dataIntegrity existe para responder la pregunta directamente, antes del descifrado, con un MAC sobre los bytes exactos
Cómo corre la comprobación, y en qué orden
El orden es la parte interesante. HotXLS deriva la clave intermedia a partir de la contraseña, descifra la clave HMAC cifrada y el valor HMAC cifrado de los atributos dataIntegrity usando vectores de inicialización derivados de la clave de bloque, calcula HMAC-SHA-512 sobre el paquete cifrado tal como está almacenado y compara. Solo entonces empieza el descifrado de segmentos
Comprobar el MAC sobre el texto cifrado y no sobre el texto plano es la disciplina estándar de cifrar-luego-MAC, y es lo que hace la comprobación significativa: un paquete manipulado se rechaza sin que ningún byte controlado por el atacante haya pasado por la ruta de descifrado e inflado. Ambas comparaciones en la ruta de apertura, el hash del verificador de contraseña y el valor HMAC, acumulan diferencias con XOR y OR a lo largo de todo el resumen en lugar de devolver antes en el primer byte no coincidente, de modo que ninguna filtra una posición de byte a través del tiempo de ejecución
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
// Funciona con ficheros sin cifrar, cifrados en modo Standard y cifrados en modo Agile
if Book.OpenEncrypted('incoming.xlsx', PasswordFromVault) = 1 then
ProcessWorkbook(Book)
else
// Contraseña incorrecta, o un paquete cuyo HMAC dataIntegrity no coincidió
Quarantine('incoming.xlsx');
except
on E: Exception do
Quarantine('incoming.xlsx: ' + E.Message);
end;
Book.Free;
end;
En el lado de la escritura no cambia nada en su código. SaveAsEncrypted emite el bloque automáticamente, y las sales, la entrada del verificador y la clave HMAC proceden de CryptGenRandom. Si esa llamada falla, HotXLS lanza una excepción en lugar de recurrir a una fuente más débil. Un CSPRNG que falla cerrado no es paranoia; una degradación silenciosa a una fuente aleatoria predecible produce ficheros que parecen cifrados, pasan todas las pruebas funcionales y no valen nada
¿Por qué siguen abriendo los ficheros sin el bloque?
Porque una gran cantidad de libros cifrados en modo Agile en circulación los escribieron productores que omiten dataIntegrity por completo, y rechazarlos rompería muchísimo más trabajo legítimo del que protegería. HotXLS trata la integridad como presente solo cuando ambos atributos, la clave HMAC cifrada y el valor HMAC cifrado, están presentes y bien formados. En caso contrario, la verificación se omite y el fichero se abre como antes
Es una decisión de compatibilidad con una consecuencia de seguridad que conviene nombrar explícitamente en su propio modelo de amenaza: la ausencia del bloque no se puede distinguir de un atacante que lo elimina, porque los atributos quedan fuera del MAC que llevarían. Si controla ambos extremos de una canalización, trate un bloque ausente como un fallo de política a nivel de aplicación. Si acepta ficheros del mundo exterior, trate la comprobación como lo que es, una señal valiosa cuando está presente y ninguna señal cuando no lo está
Contraseña para modificar es una convención, no una barrera
Los libros XLS clásicos admiten un mecanismo aparte que se confunde a menudo con el cifrado: la reserva de escritura, el aviso "contraseña para modificar" de Excel. HotXLS lo expone mediante SetModifyPassword, que toma la contraseña, un indicador de recomendar solo lectura y el nombre del usuario que reserva, e informa el estado a través de IsWriteReserved. Pasar una contraseña vacía elimina la reserva
Lo que se escribe es un par de registros WRITEPROT y FILESHARING que llevan el indicador de recomendar solo lectura, un hash de contraseña heredado de 16 bits y el nombre de usuario como cadena Unicode BIFF8. Ese hash de 16 bits es una suma de verificación, no un resumen criptográfico, y el contenido del documento no está cifrado en absoluto. Cualquiera que abra el fichero con otra herramienta lee todo. La función tiene un propósito real de coordinación: le dice a la siguiente persona que alguien considera este fichero suyo para editar, en la misma categoría que los controles a nivel de hoja tratados en la protección de hoja y las opciones allow de XLSX
var
Book: IXLSWorkbook; // contado por interfaz: no llamar a Free
begin
Book := TXLSWorkbook.Create;
if Book.Open('shared-model.xls') = 1 then
begin
// Recomendar solo lectura, reservado por el servicio de informes
Book.SetModifyPassword('edit-me', True, 'Reporting Service');
if Book.IsWriteReserved then
Book.SaveAs('shared-model.xls', xlExcel97);
end;
end;
Use ambas capas para lo que cada una hace bien. La confidencialidad real viene de SaveAsEncrypted con una contraseña que no tiene nadie fuera de la audiencia prevista, lo que produce la salida AES-256 descrita en la salida XLSX protegida con AES. La reserva de escritura se añade encima cuando el libro es un artefacto de edición compartida y quiere que Excel pregunte antes de que alguien lo sobrescriba
Qué comprobar en una ruta de ingesta no confiable
La verificación de integridad protege la carga cifrada, no el contenedor que la rodea. Un fichero XLSX es un archivo ZIP, y la estructura del archivo se analiza antes de que corra ninguna lógica de cifrado, así que la validación a nivel de contenedor va primero en la cadena; los modos de fallo específicos se cubren en la validación del fin de directorio central ZIP para XLSX no confiable. Después, trate un fallo de integridad y una contraseña incorrecta como el mismo evento operativo, porque desde su lado son indistinguibles por diseño, y ambos significan que el fichero no se puede confiar en que sea lo que el remitente cree que es
Registre qué ficheros llevaban un bloque dataIntegrity en absoluto. A lo largo de unos pocos miles de documentos, esa estadística le dice algo útil sobre las herramientas de sus remitentes, y convierte una comprobación por fichero en una observación a nivel de flota sobre la que puede actuar
HotXLS lee y escribe XLS, XLSX y ODS desde Delphi y C++Builder sin necesidad de instalar Excel, implementando en Pascal las rutas de cifrado Standard y Agile de [MS-OFFCRYPTO]. Las API de cifrado, protección y libro están documentadas en la página de HotXLS para Delphi