Secure DjVu Handling

Secure DjVu on Viewer Application

To support Secure DjVu on your viewer application, you should do the following four tasks:

Authentication support

When you're implementing a viewer application, which also support Secure DjVu files, the first thing you have to do is to implement authentication mechanism, which typicaly shows some dialog to prompt user to input his user-ID and password. It's mandatory process and without the authentication support, SDK could not open any Secure DjVu files.

The easiest way to implement authentication is to use CredentialProvider::createFromStrings :

AutoPtr<CredentialProvider> cp = CredentialProvider::createFromStrings(userId, password);
AutoPtr<Document> doc = Document::create(filePath, cp);
Note
If the file is Secure DjVu and Document::create is missing a valid CredentialProvider instance, decoding process throws errAuthRequired.

The code above is anyway not complete; if the userId/password pair is not correct, SDK will throw certain exception on actual decoding process; it's not always in Document::create but sometimes in Page methods.

AutoPtr<CredentialProvider> cp = CredentialProvider::createFromStrings(userId, password);
try
{
// The following code possibly throws one of the following security
// related exceptions or, of course other generic exceptions:
// errNotPermitted, errAuthFailed
AutoPtr<Document> doc = Document::create(filePath, cp);
// just a sample to decode image of the first page
AutoPtr<Page> page = doc->getPages()[0];
size_t width = page->getWidth();
size_t height = page->getHeight();
page->render(...);
}
catch(std::exception& ex)
{
// process the exception
// if some of Document/Page methods throws some exception, you can still
// retry that method after processing the exception.
showError(ex.what());
...
}
Note
By implementing CredentialProvider and CredentialInfo, you can realize more flexible and complex authentication process.

Restriction on file operations

Your application should enforce appropriate permissions. Secure DjVu file may disallow certain kind of operations on the file. The following operations should be under control of Secure DjVu:

So your viewer application should at least enable/disable menu items, shortcuts and/or buttons which enables users to execute the operations above.

bool isPermitted(PredefinedPrivilegesAndProperties inPriPro)
{
// const Document* doc = ...;
const SecurityProvider* sp = doc->getSecurityProvider();
if(!sp)
{
// it's not Secure DjVu;
return true;
}
if(sp->isExpired())
{
// it's expired; we should not open the document...
return false;
}
// it's Secure DjVu and we should obey the permission by SecurityProvider
return sp->isPermitted(inPriPro);
}
...
// for copy (text or image region)
menu.copy.enabled = isPermitted(p3Copy);
// for printing
menu.print.enabled = isPermitted(p3Print);
// for save
menu.save.enabled = isPermitted(p3Export);

And, you had better add more security fences on functions executing Secure DjVu operations:

// security check helper
// It's good practice to add call to such security check function on
// every Secure DjVu operation function such as Save, Copy and Print.
void securityCheck(PredefinedPrivilegesAndProperties inPriPro)
{
if(inPriPro > p3EditProp)
return;
static const char* privs[] = {
NULL, "owner", "edit", "print", "export", "copy", "editprop"};
};
if(!isPermitted(inPriPro))
"Operation not permitted: %s", privs[inPriPro]));
}
...
// your DjVu save function
void your_djvu_save_function(...)
{
securityCheck(p3Export);
...
}

Expiry support

Your application also support expiry of the Secure DjVu document. It's also implemented on the Secure DjVu decoder (the decoder sometimes throws exception for such security and expiry checks) but you should explicitly show the expiry information to the users.

The following code explains the flow:

AutoPtr<Document> doc = Document::create(secureDjVuFile);
...
const SecurityProvider* sp = doc->getSecurityProvider();
if(sp && sp->isExpired())
{
// show expiry info to user
Celartem::Time expiry = sp->getExpiry(); // NOTE: expiry.t is time_t
showError("The document is expired on %s!", t.getRFC822timeString(true).c_str());
// exit on appropriate way; I believe exit is not.
exit(0);
}

License script for Secure DjVu decode

After implementing them correctly, you should obtain appropriate license script (which contains SecureDjVuDecode) from Cuminas and embed the obtained license script on your code:

LicenseManager& lm = LicenseManager::getLicenseManager();
lm.setLicenseScript(".....");

Without any license script, the program runs under development license and stops working after 2 weeks from its built time. For more information about license system, see License System.

DjVu Encoder application

If your application encodes Secure DjVu files, your application should set appropriate SecurityProvider instance when calling Document::save or IFF::serialize method. The following sub-sections explains about two typical Secure DjVu encoding(saveing) processes.

Securing DjVu file

// Any Document instance either from encoding or decoding
AutoPtr<Document> doc = ...
// Use PWD1 security scheme
AutoPtr<SecurityProvider> secProv = SecurityProvider::createPWD1(utf8s("admin"));
// users
PropertySet* ps = secProv->getEditableUserPropSet(utf8s("admin"));
ps->set(utf8s("Password"), utf8s("admin"));
ps->set(utf8s("AllPriv"), utf8s("Yes"));
ps = secProv->getEditableUserPropSet(utf8s("ito"));
ps->set(utf8s("Password"), utf8s("ito"));
ps->set(utf8s("Print"), utf8s("Yes"));
ps = secProv->getEditableUserPropSet(utf8s("kawasaki"));
ps->set(utf8s("Password"), utf8s("kawasaki"));
ps->set(utf8s("Save"), utf8s("Yes"));
// save
AutoPtr<DiskStorageWithRollback> storageW = DiskStorageWithRollback::create(outFilePath);
doc->save(storageW, secProv);
storageW->commit();

Re-saving modified Secure DjVu

If your application simply load and save the Secure DjVu file without modifying Secure DjVu users/permissions, use the SecurityProvider instance obtained by the Document instance:

// open Secure DjVu
AutoPtr<CredentialProvider> cp = CredentialProvider::createFromStrings(userId, password);
AutoPtr<Document> doc = Document::create(filePath, cp);
// Modifying your secure DjVu here
...
AutoPtr<DiskStorageWithRollback> storageW = DiskStorageWithRollback::create(outFilePath);
doc->save(storageW, doc->getSecurityProvider());
storageW->commit();
Warning
If you don't pass any SecurityProvider instance on saving the document, the saved file will not be scrambled; it will be in plain DjVu file (descrambled DjVu file). And if the user does not have p3Export privilege, Document::save throws errNotPermitted.

Updating user access control

You can also add/remove/edit users/permissions by updating SecurityProvider instance. Please note that the SecurityProvider instance obtained from Document::getSecurityProvider is not be modified.

// Create a modifiable copy of SecurityProvider
const SecurityProvider* secProvOriginal = doc->getSecurityProvider();
AutoPtr<SecurityProvider> secProv = secProvOriginal->duplicate();
// edit other users; it requires p3EditProp privilege
// set current user's password
PropertySet* ps = secProv->getEditableUserPropSet();
ps->set(utf8s("Password"), utf8s("current-user's-new-password"));
// add other user
ps = secProv->getEditableUserPropSet(utf8s("ito"));
ps->set(utf8s("Password"), utf8s("ito"));
ps->set(utf8s("Print"), utf8s("Yes"));
// save
AutoPtr<DiskStorageWithRollback> storageW = DiskStorageWithRollback::create(outFilePath);
doc->save(storageW, secProv);
storageW->commit();

License script for Secure DjVu encode

After implementing them correctly, you should obtain appropriate license script (which contains SecureDjVuEncode) from Cuminas and embed the obtained license script on your code. For more information about license system, see License System.


Cuminas DjVu SDK 3.0.33103
This document is made with doxygen 1.8.5 at Sun Dec 15 2013 19:38:06.
Cuminas Logo