Forum > FPSpreadsheet

Help with decrypting OpenDocument files

(1/4) > >>

wp:
Motivated by a recent post whether FPSpreadsheet can read pass-word protected ods files I began to investigate how decryption of such files could be achieved. Found this nice article: https://ringlord.com/dl/Decrypting%20ODF%20Files.pdf, slowly got the idea and began coding...

The attached project tries to decrypt the file "content.xml" extracted from an ods file which had been encrypted with the password "123". All the required decryption parameters such as salt, initialization vector, algorithms used, were extracted from the META-INF/manifest.xml file contained in the ods file. But it does not work - I cannot restore the original file content, something is wrong...

Since I myself am quite inexperienced with encryption/decryption I am asking: Is there anybody out there who could give me a hint on what might be wrong, or who could even fix the test application?

P.S.
The attached project depends on the DCPCrypt package (available in OPM, installation not required).
The original, encrypted ods file is contained in the archive.

rvk:
I can remember I looked into this. I'm not sure how far I got.

I will try to see what you missed later on this evening (if I get some time).


--- Quote from: rvk on January 17, 2022, 06:05:59 pm ---You would need to unzip the content of the ods yourself (not protected) and look in the META-INF/manifest.xml. It will show how the files are encrypted (probably aes256-cbc). The initialisation-vector (IV) is also in there. With that you could try to decrypt all the files mentioned in that manifest.xml  (a recent post here shows some code to decrypt AES-256-CBC with TDCP_rijndael). After that you can rezip the contents back to an unprotected ods-file and read it with fpspreadsheet. (Don't forget to remove the encryption-data parts in the manifest.xml)

Maybe you also need to do something (PBKDF2) with the password. See https://askubuntu.com/a/223183/926892 for more details.

--- End quote ---


--- Quote from: rvk on January 07, 2022, 11:16:36 pm ---At the moment this problem is solved.
https://www.nldelphi.com/showthread.php?43955-Decrypt-string-from-PHP-met-DCPCrypt&p=367627&viewfull=1#post367627

Because openssl_encrypt() in PHP was used without OPENSSL_RAW_DATA as option, openssl_encrypt() gives the result as a base64 encoded string. When you in turn want to use that data in DecryptCBC() you need to first base64decode it. So, together with padding the decoded key back to 32 characters, this was sufficient to make it work.

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---DataString := DecodeStringBase64(datarr[0]); // nu is de lengte wel goed
Complete function:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---function my_decrypt(Data: string; key: string): string;var  datarr: TArrayOfString;  Cipher: TDCP_rijndael;  DataString, encryption_key, IV: ansistring;begin  datarr := SplitString('::', DecodeStringBase64(Data), 2);  encryption_key := DecodeStringBase64(key);  if (Length(encryption_key) < 32) then    while Length(encryption_key) < 32 do encryption_key := encryption_key + ansichar(0);  encryption_key := Copy(encryption_key, 1, 32);  IV := datarr[1];  DataString := DecodeStringBase64(datarr[0]); // nu is de lengte wel goed  Cipher := TDCP_rijndael.Create(nil);  Cipher.CipherMode := cmCBC;  Cipher.Init(encryption_key[1], Length(encryption_key) * 8, @IV[1]);  Cipher.DecryptCBC(DataString[1], DataString[1], Length(DataString));  my_decrypt := DataString;  Cipher.Free;end;
--- End quote ---

Thaddy:
Base64 is NOT a crypt. That is just about efficient storage. I suspect the necessary step to decode the SHA is left out.

rvk:

--- Quote from: wp on July 26, 2023, 06:44:33 pm ---Since I myself am quite inexperienced with encryption/decryption I am asking: Is there anybody out there who could give me a hint on what might be wrong, or who could even fix the test application?
--- End quote ---

I don't see very much wrong with your method.

But... didn't you forget point 2 from the encryption stage?
So when doing stuff in reverse you should deflate (decompress) the result before showing it.

(I tried to implement it but didn't have much success.)


--- Quote ---2. Data Compression and Encryption
a) Each sensitive document component is deflated (compressed) with the algorithm implemented
by zlib (and used by gzip and similar zip tools); header and footer components part of the gzip
file format are not stored4,

b) Each such deflated component is then encrypted using a random initialization vector to seed the
engine, followed by the cryptographic key from step 1 above, using either Bruce Schneier's
128-bit Blowfish cipher in CFB (Cyclic Feedback) mode, or the United States government's
256-bit AES (Advanced Encryption Standard) in CBC (Cipher-block chaining) mode.

c) The name of the key strengthening algorithm and cryptographic cipher, as well as the value of
the salt, initialization vector, and the SHA1/1K or SHA256/1K (SHA1/SHA256 of the first 1024
bytes of encrypted data) is stored into the META-INF/manifest.xml file for the sensitive document component.
The code listed in this document reverses these steps.
--- End quote ---

BTW. The result of DataString is different each time. I can't imagine that's correct.


--- Quote from: Thaddy on July 26, 2023, 10:16:33 pm ---Base64 is NOT a crypt. That is just about efficient storage. I suspect the necessary step to decode the SHA is left out.

--- End quote ---
Yeah, reading only half the post is your trademark. SHA was done.
The topic I mentioned was about something else but I added it for the TDCP_rijndael with key and IV. wp already implemented that, almost exactly, as I had it in the other topic.

wp:

--- Quote from: rvk on July 26, 2023, 10:18:47 pm ---But... didn't you forget point 2 from the encryption stage?
So when doing stuff in reverse you should deflate (decompress) the result before showing it.

--- End quote ---
Yes I read that, and I did not understand it. Because in order to get the xml file I already must have extracted it from the ods which is a zip. Or do you want to say that an encrypted xml file is compressed twice: once as one step of the encryption sequence, and once again when all files are compressed into a single zip?

Navigation

[0] Message Index

[#] Next page

Go to full version