Skip to content

Commit b8d6c63

Browse files
committed
initial commit
1 parent 17e1025 commit b8d6c63

13 files changed

+1510
-0
lines changed

Makefile

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
APPS=openssl_tstpkcs12 mbedtls_tstpkcs12 openssl_rc2_crack openssl_sha1_perftest openssl_pkcs12_perftest openssl_des3_perftest openssl_pass_crack PdfEncryptionTest.class
2+
all: $(APPS)
3+
4+
CXX=clang++
5+
sslflags=-I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib -lcrypto -lssl
6+
mbedflags=-I /usr/local/include/ -L/usr/local/lib -lmbedcrypto
7+
cflags=-g -std=c++1z -Wall -O3
8+
9+
mbedtls_tstpkcs12: mbedtls_tstpkcs12.cpp
10+
$(CXX) $^ -o $@ $(mbedflags) $(cflags)
11+
openssl_tstpkcs12: openssl_tstpkcs12.cpp
12+
$(CXX) $^ -o $@ $(sslflags) $(cflags)
13+
14+
openssl_rc2_crack: openssl_rc2_crack.cpp
15+
$(CXX) $^ -o $@ $(sslflags) $(cflags)
16+
17+
openssl_sha1_perftest: openssl_sha1_perftest.cpp
18+
$(CXX) $^ -o $@ $(sslflags) $(cflags)
19+
20+
openssl_pkcs12_perftest: openssl_pkcs12_perftest.cpp
21+
$(CXX) $^ -o $@ $(sslflags) $(cflags)
22+
23+
openssl_des3_perftest: openssl_des3_perftest.cpp
24+
$(CXX) $^ -o $@ $(sslflags) $(cflags)
25+
26+
openssl_pass_crack: openssl_pass_crack.cpp
27+
$(CXX) $^ -o $@ $(sslflags) $(cflags)
28+
29+
clean:
30+
$(RM) $(APPS)
31+
$(RM) -r $(wildcard *.dSYM)
32+
33+
BC=$(HOME)/.m2/repository/org/bouncycastle/bcprov-jdk15on/1.49/bcprov-jdk15on-1.49.jar:$(HOME)/.m2/repository/org/bouncycastle/bcpkix-jdk15on/1.49/bcpkix-jdk15on-1.49.jar
34+
ITEXT=$(HOME)/gitprj/itext7
35+
PdfEncryptionTest.class: PdfEncryptionTest.java
36+
javac -classpath "$(ITEXT)/target/*:$(BC)" PdfEncryptionTest.java
37+
38+
runjava:
39+
java -classpath ".:$(ITEXT)/target/*:$(BC)" PdfEncryptionTest
40+

PdfEncryptionTest.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* use itext to decrypt the pdf
3+
*/
4+
import com.itextpdf.io.font.FontConstants;
5+
import com.itextpdf.kernel.crypto.CryptoUtil;
6+
import com.itextpdf.kernel.PdfException;
7+
import com.itextpdf.kernel.crypto.BadPasswordException;
8+
import com.itextpdf.kernel.font.PdfFontFactory;
9+
import com.itextpdf.kernel.utils.CompareTool;
10+
import com.itextpdf.kernel.xmp.XMPException;
11+
import com.itextpdf.test.ExtendedITextTest;
12+
import com.itextpdf.test.ITextTest;
13+
import com.itextpdf.test.annotations.type.IntegrationTest;
14+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
15+
import com.itextpdf.kernel.pdf.PdfReader;
16+
import com.itextpdf.kernel.pdf.PdfDocument;
17+
import com.itextpdf.kernel.pdf.PdfPage;
18+
import com.itextpdf.kernel.pdf.ReaderProperties;
19+
import java.io.FileInputStream;
20+
import java.io.IOException;
21+
import java.nio.charset.StandardCharsets;
22+
import java.security.GeneralSecurityException;
23+
import java.security.PrivateKey;
24+
import java.security.Security;
25+
import java.security.cert.Certificate;
26+
import java.security.cert.CertificateException;
27+
28+
public class PdfEncryptionTest {
29+
30+
public static Certificate getPublicCertificate(String path) throws IOException, CertificateException {
31+
FileInputStream is = new FileInputStream(path);
32+
return CryptoUtil.readPublicCertificate(is);
33+
}
34+
35+
public static PrivateKey getPrivateKey(String filename, String password) throws GeneralSecurityException, IOException {
36+
return CryptoUtil.readPrivateKeyFromPKCS12KeyStore(new FileInputStream(filename), "sandbox", password.toCharArray());
37+
}
38+
39+
public static void main(String [] args) throws IOException, CertificateException, GeneralSecurityException
40+
{
41+
Security.addProvider(new BouncyCastleProvider());
42+
String filename = args[0];
43+
Certificate certificate = getPublicCertificate(args[1]);
44+
PrivateKey privkey = getPrivateKey(args[1], args[2]);
45+
46+
PdfReader reader = new PdfReader(filename, new ReaderProperties().setPublicKeySecurityParams(certificate, privkey, "BC", null));
47+
PdfDocument document = new PdfDocument(reader);
48+
PdfPage page = document.getPage(1);
49+
50+
System.out.println("content = " + new String(page.getStreamBytes(0)));
51+
System.out.println("author = " + document.getDocumentInfo().getAuthor());
52+
System.out.println("creator = " + document.getDocumentInfo().getCreator());
53+
54+
document.close();
55+
56+
}
57+
}
58+

README.md

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
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

Comments
 (0)