|
| 1 | +Pdf Encryption |
| 2 | +============== |
| 3 | + |
| 4 | +Using sample data from: |
| 5 | + * https://github.com/itext/itext7/tree/develop/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfEncryptionTest |
| 6 | + |
| 7 | +Example code demonstating how pdf encryption with certificates works. |
| 8 | + |
| 9 | + python3 decryptpdf.py encryptedWithCertificateAes128.pdf test.p12 kspass |
| 10 | + |
| 11 | +Will output the following decrypted data: |
| 12 | + |
| 13 | + priv b'a2d0faa52fee8453fe20150505050505' |
| 14 | + cert b'37373532393731340808080808080808' |
| 15 | + seed = b'cd532522a3f5943f66479ab8b0aa32d0609a0e18' |
| 16 | + mkey= b'b1ce00167f01fc074d49d6fe18069b942ed9c428' |
| 17 | + b'Author' b'Alexander Chingarev\r\r\r\r\r\r\r\r\r\r\r\r\r' |
| 18 | + b'CreationDate' b"D:20160809103103-03'00'\t\t\t\t\t\t\t\t\t" |
| 19 | + b'Creator' b'iText 6\t\t\t\t\t\t\t\t\t' |
| 20 | + b'ModDate' b"D:20160809103103-03'00'\t\t\t\t\t\t\t\t\t" |
| 21 | + b'Producer' b'iText\xae 7.0.1-SNAPSHOT \xa92000-2016 iText Group NV (AGPL-version)\x02\x02' |
| 22 | + |
| 23 | +The repeating sequences at the end of each decrypted text are the PKCS1.5 padding. |
| 24 | + |
| 25 | + |
| 26 | +Pdf Parser |
| 27 | +========== |
| 28 | + |
| 29 | +As a side project i created a simple PDF parser, which outputs the parsing stack plus a list of objects. |
| 30 | + |
| 31 | + python pdfparser.py encryptedWithCertificateAes128.pdf |
| 32 | + |
| 33 | +producing the following output: |
| 34 | + |
| 35 | + [PdfComment: ascii:'PDF-1.7', PdfComment: hex:'e2e3cfd3', |
| 36 | + PdfOperator: xref, |
| 37 | + PdfNumber: 0, PdfNumber: 9, |
| 38 | + PdfNumber: 0000000000, PdfNumber: 65535, PdfOperator: f, |
| 39 | + PdfNumber: 0000000294, PdfNumber: 00000, PdfOperator: n, |
| 40 | + PdfNumber: 0000000873, PdfNumber: 00000, PdfOperator: n, |
| 41 | + PdfNumber: 0000000354, PdfNumber: 00000, PdfOperator: n, |
| 42 | + PdfNumber: 0000000161, PdfNumber: 00000, PdfOperator: n, |
| 43 | + PdfNumber: 0000000015, PdfNumber: 00000, PdfOperator: n, |
| 44 | + PdfNumber: 0000000785, PdfNumber: 00000, PdfOperator: n, |
| 45 | + PdfNumber: 0000000924, PdfNumber: 00000, PdfOperator: n, |
| 46 | + PdfNumber: 0000003847, PdfNumber: 00000, PdfOperator: n, |
| 47 | + PdfOperator: trailer, PdfDictionary: [ |
| 48 | + PdfName: Encrypt, PdfReference: 00008.0, |
| 49 | + PdfName: ID, PdfArray: [PdfHexdata: eadf305edab34545d11859b727274d71, PdfHexdata: eadf305edab34545d11859b727274d71], |
| 50 | + PdfName: Info, PdfReference: 00003.0, |
| 51 | + PdfName: Root, PdfReference: 00001.0, |
| 52 | + PdfName: Size, PdfNumber: 9], |
| 53 | + PdfComment: ascii:'iText-7.0.1-SNAPSHOT', |
| 54 | + PdfOperator: startxref, PdfNumber: 4893] |
| 55 | + |
| 56 | + 00001: PdfObject: [PdfDictionary: [ |
| 57 | + PdfName: Metadata, PdfReference: 00007.0, |
| 58 | + PdfName: Pages, PdfReference: 00002.0, |
| 59 | + PdfName: Type, |
| 60 | + PdfName: Catalog]] |
| 61 | + 00002: PdfObject: [PdfDictionary: [ |
| 62 | + PdfName: Count, PdfNumber: 1, |
| 63 | + PdfName: Kids, PdfArray: [PdfReference: 00004.0], |
| 64 | + PdfName: Type, |
| 65 | + PdfName: Pages]] |
| 66 | + 00003: PdfObject: [PdfDictionary: [ |
| 67 | + PdfName: Author, PdfString: hex:'5b97d367c7310b9d80761c86e66fa2c71dab01fb150e6fa4c55cb4bf80fac19cda79513966f9d6c1e938080fc8c87800', |
| 68 | + PdfName: CreationDate, PdfString: hex:'5b97d367c7310b9d80761c86e66fa2c710cf138a9608a559cf8aa4e14fe9f97ee6e7ef89029fb1f7399dd9e64b0d7cab', |
| 69 | + PdfName: Creator, PdfString: hex:'5b97d367c7310b9d80761c86e66fa2c7ee23708d7b3f6973b01ff75dae7e0fca', |
| 70 | + PdfName: ModDate, PdfString: hex:'5b97d367c7310b9d80761c86e66fa2c710cf138a9608a559cf8aa4e14fe9f97ee6e7ef89029fb1f7399dd9e64b0d7cab', |
| 71 | + PdfName: Producer, PdfString: hex:'5b97d367c7310b9d80761c86e66fa2c7ba3a4b524f422411b737667f5c50c98f8e864b96999ed6247270483364dd492a28c0a6f50da37bfe8e0ad618f419d4e77f31179bf7502fd8606af1b81e271ae3']] |
| 72 | + 00004: PdfObject: [PdfDictionary: [ |
| 73 | + PdfName: Contents, PdfReference: 00005.0, |
| 74 | + PdfName: MediaBox, PdfArray: [PdfNumber: 0, PdfNumber: 0, PdfNumber: 595, PdfNumber: 842], |
| 75 | + PdfName: Parent, PdfReference: 00002.0, |
| 76 | + PdfName: Resources, PdfDictionary: [ |
| 77 | + PdfName: Font, PdfDictionary: [ |
| 78 | + PdfName: F1, PdfReference: 00006.0]], |
| 79 | + PdfName: TrimBox, PdfArray: [PdfNumber: 0, PdfNumber: 0, PdfNumber: 595, PdfNumber: 842], |
| 80 | + PdfName: Type, |
| 81 | + PdfName: Page]] |
| 82 | + 00005: PdfObject: [PdfStream: PdfDictionary: [ |
| 83 | + PdfName: Filter, |
| 84 | + PdfName: FlateDecode, |
| 85 | + PdfName: Length, PdfNumber: 80]] |
| 86 | + 00006: PdfObject: [PdfDictionary: [ |
| 87 | + PdfName: BaseFont, |
| 88 | + PdfName: Helvetica, |
| 89 | + PdfName: Encoding, |
| 90 | + PdfName: WinAnsiEncoding, |
| 91 | + PdfName: Subtype, |
| 92 | + PdfName: Type1, |
| 93 | + PdfName: Type, |
| 94 | + PdfName: Font]] |
| 95 | + 00007: PdfObject: [PdfStream: PdfDictionary: [ |
| 96 | + PdfName: Length, PdfNumber: 2848, |
| 97 | + PdfName: Subtype, |
| 98 | + PdfName: XML, |
| 99 | + PdfName: Type, |
| 100 | + PdfName: Metadata]] |
| 101 | + 00008: PdfObject: [PdfDictionary: [ |
| 102 | + PdfName: CF, PdfDictionary: [ |
| 103 | + PdfName: DefaultCryptFilter, PdfDictionary: [ |
| 104 | + PdfName: CFM, |
| 105 | + PdfName: AESV2, |
| 106 | + PdfName: Recipients, PdfArray: [PdfString: hex:'308201f706092a'...]]], |
| 107 | + PdfName: Filter, |
| 108 | + PdfName: Adobe.PubSec, |
| 109 | + PdfName: Length, PdfNumber: 128, |
| 110 | + PdfName: R, PdfNumber: 4, |
| 111 | + PdfName: StmF, |
| 112 | + PdfName: DefaultCryptFilter, |
| 113 | + PdfName: StrF, |
| 114 | + PdfName: DefaultCryptFilter, |
| 115 | + PdfName: SubFilter, |
| 116 | + PdfName: adbe.pkcs7.s5, |
| 117 | + PdfName: V, PdfNumber: 4]] |
| 118 | + |
| 119 | + |
| 120 | +Cracking a PKCS12 certificate |
| 121 | +============================= |
| 122 | + |
| 123 | + |
| 124 | +hexdump of the first couple of encrypted and decrypted blocks of the 40-bit RC2 encrypted certificate in test.p12: |
| 125 | + |
| 126 | + 2408c5d658c61cad 43036642daa47c52 9023df09863bd662 28c700fee6c81f86 ac5d3c4debda9148 0ac6535dd9574d06 << cipher text |
| 127 | + 3082____3082____ 060b2a864886f70d 010c0a0103a082__ __3082____060a2a 864886f70d010916 01a082____0482__ << plain text |
| 128 | + |
| 129 | +The length dependent parts have been replaced with '\_\_\_\_'. |
| 130 | +As you can see the 2nd block contains part of the 'pkcs12' OID representation, |
| 131 | +and will be the same for all PKCS12 encoded data. |
| 132 | + |
| 133 | +So we can use this as the known plain + cipher pair target for the brute force encryption. |
| 134 | +Since the cipher is used in CBC mode, we have to XOR the plaintext with the 1st cipher block |
| 135 | + |
| 136 | + 2408c5d658c61cad XOR 060b2a864886f70d = 2203ef501040eba0 |
| 137 | + |
| 138 | +And then do a full 40-bit search for the key: |
| 139 | + |
| 140 | + openssl_rc2_crack -e 43036642daa47c52 -p 2203ef501040eba0 -v |
| 141 | + |
| 142 | +Running on a single core, this will take about 5 days. |
| 143 | +Using the `-f` and `-t` parameters you can run several instances searching different parts |
| 144 | +of the keyspace. |
| 145 | + |
| 146 | + ./openssl_rc2_crack -e 43036642daa47c52 -p 2203ef501040eba0 -f 0x6896000000 -t 0x6896300000 -v |
| 147 | + FOUND key: 689629ff1a |
| 148 | + |
| 149 | +Note that this is the key in reverse byte order. |
| 150 | + |
| 151 | +Now we can search for the passphrase using the following commandline. |
| 152 | + |
| 153 | + cat wordlist.txt | ./openssl_pass_crack -s 68e8f778efe0db98453532b7ede8e0c09830ec81 -k 1aff299668 -i 1 -n 1024 |
| 154 | + FOUND key: kspass |
| 155 | + |
| 156 | +Instead of `cat wordlist.txt` you can use JohnTheRipper for password generation: |
| 157 | + |
| 158 | + john --wordlist=dict.txt --rules --stdout" | ./openssl_pass_crack .... |
| 159 | + |
| 160 | + |
0 commit comments