パッケージJava製品開発担当の大です。こんにちは。
今回は、シーオーリポーツ for Java Ver.2で実装された、PDFのAES暗号化機能について書こうと思います。

以前のバージョンのシーオーリポーツ for Javaでは、PDFの暗号化アルゴリズムはRC4(40bit および 128bit)しか対応していませんでした。PDFの仕様としては、RC4に加え、PDF 1.6(AdobeReader 7)以降で128bit AESが、PDF 1.7 Adobe Extension Level 3(AdobeReader 9)以降で256bit AESが使用可能になっていたため、今回のバージョンアップでこれらに対応したという形になります。

256bit AESで暗号化されたPDF

256bit AESで暗号化されたPDF(クリックで拡大)

AES暗号化対応の必要性

私も詳しく知らないのですが、平成15年に発表された電子政府推奨暗号リストでは、40bit RC4は対象外、128bit RC4も「条件つきで許可」ぐらいの扱いで、あまり積極的に推奨されていないようです。条件とは以下のようなものです(リンク先PDFより引用)。

128-bit RC4は、SSL3.0/TLS1.0以上に限定して利用することを想定している。なお、リストに掲載されている別の暗号が利用できるのであれば、そちらを使用することが望ましい。

一方、AESはこのリストでも推奨されていますし、もともとアメリカの次世代の暗号化標準(Advanced Encryption Standard)として公募されたという経緯もあり、欧州連合の暗号規格(NESSIE)でも、AES(Rijndael)が採用されているそうです。

電子政府推奨暗号リストは、現在改訂のため新しい暗号が公募されているようですが、さしあたって公的な文書の暗号化はRC4よりAESを使用しておくのが無難なようですね。

シーオーリポーツ for Java Ver.2でAES暗号化を使用する

シーオーリポーツ for Java Ver.2でAES暗号化を使用するには、暗号化の種類をAES_128またはAES_256で指定します。

// ドキュメントタイプとファイル名を指定してジョブを作成します
CrFileOutJob job = new CrFileOutJob(CorDocumentType.PDF, "sample.pdf");
// ドキュメントを取得します
CrPdfDocument doc = job.getDocument();
// セキュリティパスワードを設定して暗号化します
doc.setSecurityPassword("password1");
// オープンパスワードを設定します
doc.setOpenPassword("password2");
// 暗号化の種類を設定します
doc.setCryptoType(CorPdfCryptoType.AES_128);
// 権限を設定します
doc.setAccessFlags(EnumSet.of(CorPdfAccessFlags.ALLOW_PRINTING,
                              CorPdfAccessFlags.ALLOW_COPYING,
                              CorPdfAccessFlags.ALLOW_SCREEN_READERS));
// ジョブを開始します
job.start(draw);

ただし、このまま実行すると、(たぶん)例外が発生します。日本国内でダウンロードしたJDK/JREには、米国の輸出規制により制限がかけられているからです。

制限を解除するには、JDKのダウンロードページに行って「無制限強度の管轄ポリシーファイル」をダウンロードして設定します。

無制限強度の管轄ポリシーファイルをダウンロード

無制限強度の管轄ポリシーファイルをダウンロード(クリックで拡大)

ダウンロードしたファイルを解凍すると、「local_policy.jar」「US_export_policy.jar」という二つのjarファイルが入っていますので、これらを%JAVA_HOME%/jre/lib/security 以下の同名のファイルと置き換えてください。

ユニコードパスワード

暗号化の種類で256bit AESを選択した場合、パスワード文字列にユニコード文字列が使用できます。たとえば、「あいうえお」などの日本語の文字列もパスワードとして使用することができます。使用する場合は事前にSASLprep処理しておく必要があります。

例えば、オープンソースのICU4Jライブラリを使用してSASLprep処理を行う場合、以下のように記述します。

String securityPassword = "ABC";
String openPassword = "あいうえお";
// SASLprepのインスタンスを取得します
StringPrep sasl = StringPrep.getInstance(StringPrep.RFC4013_SASLPREP);
// セキュリティパスワードをSASLprep処理します
securityPassword = sasl.prepare(securityPassword, StringPrep.DEFAULT);
// オープンパスワードをSASLprep処理します
openPassword = sasl.prepare(openPassword, StringPrep.DEFAULT);
// セキュリティパスワードに半角の「ABC」が設定されます
doc.setSecurityPassword(securityPassword);
// オープンパスワードに「あいうえお」が設定されます
doc.setOpenPassword(openPassword);

SASLprep処理後、全角「ABC」が半角「ABC」に変換されていることに注意してください。

このPDFは、AdobeReader等のビュアーのパスワードダイアログに「ABC」「ABC」「あいうえお」のいずれかを入力することで開くことができます。ただし、AdobeReaderの現在の最新のバージョンでも、パスワードダイアログでIMEが有効にならないため、ひらがなを入力する場合は他のエディタ等で書いてコピー&ペーストする必要がありますが。。。

注意事項

256bit AESで暗号化されたPDFは、まだ対応していないPDFビュアーも多いため、採用には注意が必要です。想定される帳票の利用シーンに合わせて、128bit AESと256bit AESを適宜使い分けていただくと良いと思います。