[Objective-C,Swift]iOSでPDFファイルがパスワード暗号化されているか調べる方法


XCode

iOSでPDFを開くようなプログラムで、開きたいPDFファイルがパスワード暗号化されているものであるかを調べたい機会がありました。

Xcodeに標準で付属しているフレームワークの関数で案外簡単に実装できたので、その方法をメモします。

PDFファイルがパスワード暗号化されているか調べる関数

CoreGraphics.frameworkCGPDFDocumentクラス内の以下の関数を使用します。

CGPDFDocumentIsEncrypted

PDFファイルがパスワード暗号化されているか調べるにはCGPDFDocumentIsEncrypted関数を使用します。

Swift
func CGPDFDocumentIsEncrypted(_ document: CGPDFDocument!) -> Bool

Objective-C
bool CGPDFDocumentIsEncrypted ( CGPDFDocumentRef document );

CGPDFDocumentUnlockWithPassword

PDFファイルがパスワード暗号化されているものだった場合、指定した文字列(パスワード)でPDFファイルをアンロックできるかはCGPDFDocumentUnlockWithPassword関数で調べることができます。

Swift
func CGPDFDocumentUnlockWithPassword(_ document: CGPDFDocument!,
_ password: UnsafePointer) -> Bool

Objective-C
bool CGPDFDocumentUnlockWithPassword ( CGPDFDocumentRef document, const char *password );

使用例

Objective-CとSwiftそれぞれで試してみました。今回はプロジェクト内のPDFファイルで試したため、あらかじめプロジェクト内にパスワード暗号化されたPDF、パスワード暗号化されていないPDFをそれぞれコピーしておきます。

パスワード付きPDF

XcodeプロジェクトへのPDF追加

以下はプロジェクト内にあるPDFファイルを開き、まずPDFファイルがパスワード暗号化されているものであるかを調べ、パスワード暗号化されているものだったらNSStringで指定されたパスワードで開くことができるかを調べるサンプルプログラムです。

Objective-C版です。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //PDFファイルのURLを取得し、PDFドキュメントを生成
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"passwordsample" withExtension:@"pdf"];
    CGPDFDocumentRef pdfDocumentRef = CGPDFDocumentCreateWithURL((CFURLRef)url);
    
    //PDFファイルがパスワード付きか調べる
    BOOL isEncrypted = CGPDFDocumentIsEncrypted(pdfDocumentRef);
    
    if(isEncrypted){
        NSLog(@"パスワード付き");
    }else{
        NSLog(@"パスワード無し");
        return;
    }

    //PDFファイルを指定したパスワードでアンロックできるかチェック
    NSString *password = @"passw0rd";
    BOOL isUnlocked = CGPDFDocumentUnlockWithPassword(pdfDocumentRef, [password UTF8String]);

    CGPDFDocumentRelease(pdfDocumentRef);
    
    if(isUnlocked){
        NSLog(@"アンロックOK");
    }else{
        NSLog(@"アンロックNG");
    }
    
}

Swift版です。

    override func viewDidLoad() {
        super.viewDidLoad()
    
        //PDFファイルのURLを取得し、PDFドキュメントを生成
        var url:NSURL = NSBundle.mainBundle().URLForResource("passwordsample", withExtension: "pdf")!
        var pdfDocumentRef:CGPDFDocumentRef = CGPDFDocumentCreateWithURL(url as CFURLRef)
        
        //PDFファイルがパスワード付きか調べる
        var isEncrypted:Bool = CGPDFDocumentIsEncrypted(pdfDocumentRef);
        
        if(isEncrypted){
            NSLog("パスワード付き");
        }else{
            NSLog("パスワード無し");
            return
        }
    
        //PDFファイルを指定したパスワードでアンロックできるかチェック
        let password:NSString = "passw0rd";
        var isUnlocked = CGPDFDocumentUnlockWithPassword(pdfDocumentRef, password.UTF8String)
        
        if(isUnlocked){
            NSLog("アンロックOK");
        }else{
            NSLog("アンロックNG");
        }
    
    }

調べた結果を出力するだけですが、実行すると以下のような感じになります。
スクリーンショット 2014-12-10 20.06.48

CGPDFDocumentUnlockWithPasswordの第二引数にはパスワード暗号解除用の文字列を指定しますがconst char *型で渡す必要があるためNSStringのままでは渡すことができません。そこでNSStringのインスタンスメソッドUTF8Stringでパスワード暗号解除用の文字列をconst char *型に変換しています。

おわりに

標準フレームワークなので安心して使用できました。思いの外簡単に実装できたのも嬉しい点です。

Swiftはまだほんのさわりかけですが、Objective-Cからはそれほど違和感なく移行できそうです。かの有名な「詳解 Objective-C 2.0 第3版」と同じ著者による書籍「詳解 Swift」も発売されたようなので、勉強していきたいです。