Page 1 of 1

Using CTDocProtect to protect a word file

PostPosted: Thu Dec 22, 2011 3:30 am
by nicolas
Hi

I need to protect a generated word file. user should only be able to edit it if they know the password to unlock it. I tried it with the following code:

Code: Select all
    DocumentSettingsPart dsp = doc.getDocumentSettingsPart();
    ObjectFactory factory = new ObjectFactory();
    CTDocProtect protection = factory.createCTDocProtect();
    protection.setEdit(STDocProtect.COMMENTS);
    protection.setEnforcement(true);
    protection.setCryptProviderType(STCryptProv.RSA_FULL);
    protection.setCryptAlgorithmClass(STAlgClass.HASH);
    protection.setCryptAlgorithmType(STAlgType.TYPE_ANY);
    protection.setCryptAlgorithmSid(BigInteger.valueOf(4));
    protection.setCryptSpinCount(BigInteger.valueOf(100000));
    protection.setHash(???);
    protection.setSalt(???);
    dsp.getJaxbElement().setDocumentProtection(protection);


how can I evaluate the hash and the salt value for a given password and document?

greetings, nick

Re: Using CTDocProtect to protect a word file

PostPosted: Sat Dec 24, 2011 11:31 pm
by jason
Have you seen the relevant part of the spec, which is based on http://blogs.msdn.com/b/brian_jones/arc ... shing.aspx

http://www.lyquidity.com/devblog/?p=35 contains material which looks helpful (even though it is presented in the context of encrypting documents, not making them read-only):

Code: Select all
The first step is to hash the salt and password. In this case it's a 16 byte salt and 16 bytes of password (the unicode representation of "password"). The result is the following 20 (0x14) byte hash:

00000000 A1 21 9D 6D 2D 77 A1 92 EA 2F A2 E6 E3 7B C8 60
00000010 CF EF 5F DE

The algorithm then has to iterate from 0..49999 concatenating the iteration number (4 bytes) and the previous hash result to generate a new hash. After the zeroth iteration (i==0) this is what I see:

00000000 8B 33 F7 48 FA 35 AF BB 34 22 E8 AC D7 C6 DA E1
00000010 8A F1 81 78

At the end of the iteration (after hashing with i==49999) I see:

00000000 7D C5 97 D9 01 2A A3 E0 B8 56 3B 56 69 00 06 10
00000010 CC C3 A6 D4

Next the last hash generated by the iterator has to be hashed with four zero byte (what the documentation calls "block 0"). In the iterator the hash is appended to the iterator count then hashed. Here the four zero bytes are appended to the hash. Anyway here's my result.

00000000 A6 65 59 03 FD 23 94 C8 83 1E 71 62 D7 8B 42 55
00000010 51 B9 14 E4

One of the clues given above is to include step 4(a) of the key derivation algorithm in all cases. After this step I see:

00000000 AC 7C 92 51 7C 31 2F B0 9F E9 32 E9 C0 62 D9 12
00000010 38 29 30 35

Re: Using CTDocProtect to protect a word file

PostPosted: Tue Jan 03, 2012 10:19 pm
by nicolas
hi jason

thank you for the links.

i'd like to narrow down the problem and tried it with a simple example. i'd like to recreate the following with docx4j:
Code: Select all
<w:documentProtection w:edit="comments" w:enforcement="1"/>

if i add this code manually in the settings.xml file, the document is set to read-only and i can remove the protection without password in word.

but if i use the following code:
Code: Select all
DocumentSettingsPart dsp = doc.getDocumentSettingsPart();
ObjectFactory factory = new ObjectFactory();
CTDocProtect protection = factory.createCTDocProtect();
protection.setEdit(STDocProtect.COMMENTS);
protection.setEnforcement(true);
dsp.getJaxbElement().setDocumentProtection(protection);


and open the file afterwards, it looks like this:
Code: Select all
<w:documentProtection w:edit="comments" w:enforcement="0"/>


what am i doing wrong?

Re: Using CTDocProtect to protect a word file

PostPosted: Tue Jan 03, 2012 10:54 pm
by nicolas
nevermind - it works when i'm using a docx file instead of a dotx file.

if i have a dotx template and want to generate a docx file, replace some values and save it with docx4j. what's the correct way to do this and to work with dotx templates in general?

Re: Using CTDocProtect to protect a word file

PostPosted: Wed Jan 04, 2012 3:25 am
by vgunaselan
HI Guys,
have you done protecting certain sections as read only within the document? can you guys shed me more light on this same topic.

Guna

Re: Using CTDocProtect to protect a word file

PostPosted: Wed Jan 04, 2012 3:31 am
by nicolas
hi guna
no, i only protected the whole document from unintended changes (read-only protection that the user can disable without password).
greetings, nick

Re: Using CTDocProtect to protect a word file

PostPosted: Mon Jan 09, 2012 10:50 am
by vgunaselan
Hi all,
i think I figured out how to make certain sections as editable in a read only document.

1) first we need add security in the document properties, as nick described above.
2) after that in document.xml under word, we need to wrap the editable are with "<w:permStart w:id="0" w:edGrp="everyone"/>" .....<w:permEnd w:id="0"/>

i have done the step 2 manually. i am wondering is there are an api that can insert this xml changes to the code.,

Thanks
Guna

Re: Using CTDocProtect to protect a word file

PostPosted: Tue Jan 10, 2012 8:27 am
by vgunaselan
here is the code for step 2, forum guide me if there is a better way in coding this method

Code: Select all
public  void startEditableContent(WordprocessingMLPackage wordMLPackage) throws SAXException{
      try{
         ObjectFactory factory = Context.getWmlObjectFactory();
         permStart = factory.createRangePermissionStart();
         permStart.setEdGrp("everyone");
         permStart.setId(String.valueOf(readonlyContentCounter ++));
         JAXBElement<RangePermissionStart> mr = factory.createBodyPermStart(permStart);


         //get index to start
         org.docx4j.wml.ObjectFactory fac = new org.docx4j.wml.ObjectFactory();
         org.docx4j.wml.P  para = fac.createP();


         org.docx4j.wml.Text  t = fac.createText();
         t.setValue(" ");

         org.docx4j.wml.R  run = fac.createR();
         run.getRunContent().add(t);      
         wordMLPackage.getMainDocumentPart().addObject(para);
         para.getParagraphContent().add(run);

         int index = para.getParagraphContent().indexOf(run);
         para.getParagraphContent().add(index, mr);

      }catch(Exception e){
         throw new SAXException(e);
      }
   }


   public  void endEditableContent(WordprocessingMLPackage wordMLPackage) throws SAXException{
      try{
         ObjectFactory factory = Context.getWmlObjectFactory();
         JAXBElement<CTPerm> mr  = factory.createBodyPermEnd(permStart);

         //get index to start
         org.docx4j.wml.ObjectFactory fac = new org.docx4j.wml.ObjectFactory();
         org.docx4j.wml.P  para = fac.createP();


         org.docx4j.wml.Text  t = fac.createText();
         t.setValue("  ");

         org.docx4j.wml.R  run = fac.createR();
         run.getRunContent().add(t);      
         wordMLPackage.getMainDocumentPart().addObject(para);
         para.getParagraphContent().add(run);

         int index = para.getParagraphContent().indexOf(run);
         para.getParagraphContent().add(index, mr);
      }catch(Exception e){
         throw new SAXException(e);
      }

   }