Skip to content

Commit 98d896c

Browse files
Refactor PdfEncryption, fix document encryption in append mode, improve encryption tests
Encryption logic is now separated in number of classes which represent different security handlers DEVSIX-475
1 parent 447c919 commit 98d896c

File tree

47 files changed

+2109
-1274
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2109
-1274
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.itextpdf.kernel.crypto;
2+
3+
public class AesDecryptor implements Decryptor {
4+
private AESCipher cipher;
5+
private byte[] key;
6+
private boolean initiated;
7+
private byte[] iv = new byte[16];
8+
private int ivptr;
9+
10+
/**
11+
* Creates a new instance of AesDecryption
12+
*/
13+
public AesDecryptor(byte key[], int off, int len) {
14+
this.key = new byte[len];
15+
System.arraycopy(key, off, this.key, 0, len);
16+
}
17+
18+
public byte[] update(byte[] b, int off, int len) {
19+
if (initiated) {
20+
return cipher.update(b, off, len);
21+
} else {
22+
int left = Math.min(iv.length - ivptr, len);
23+
System.arraycopy(b, off, iv, ivptr, left);
24+
off += left;
25+
len -= left;
26+
ivptr += left;
27+
if (ivptr == iv.length) {
28+
cipher = new AESCipher(false, key, iv);
29+
initiated = true;
30+
if (len > 0)
31+
return cipher.update(b, off, len);
32+
}
33+
return null;
34+
}
35+
}
36+
37+
public byte[] finish() {
38+
if (cipher != null) {
39+
return cipher.doFinal();
40+
} else {
41+
return null;
42+
}
43+
}
44+
}

kernel/src/main/java/com/itextpdf/kernel/crypto/BadPasswordException.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
public class BadPasswordException extends PdfException {
66

7+
public static final String PdfReaderNotOpenedWithOwnerPassword = "PdfReader is not opened with owner password";
8+
79
public BadPasswordException(String message, Throwable cause) {
810
super(message, cause);
911
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.itextpdf.kernel.crypto;
2+
3+
public interface Decryptor {
4+
byte[] update(byte[] b, int off, int len);
5+
byte[] finish();
6+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.itextpdf.kernel.crypto;
2+
3+
import com.itextpdf.kernel.PdfException;
4+
import java.io.IOException;
5+
6+
public class OutputStreamAesEncryption extends OutputStreamEncryption {
7+
protected AESCipher cipher;
8+
private boolean finished;
9+
10+
/**
11+
* Creates a new instance of OutputStreamCounter
12+
*/
13+
public OutputStreamAesEncryption(java.io.OutputStream out, byte key[], int off, int len) {
14+
super(out);
15+
byte[] iv = IVGenerator.getIV();
16+
byte[] nkey = new byte[len];
17+
System.arraycopy(key, off, nkey, 0, len);
18+
cipher = new AESCipher(true, nkey, iv);
19+
try {
20+
write(iv);
21+
} catch (IOException e) {
22+
throw new PdfException(PdfException.PdfEncryption, e);
23+
}
24+
}
25+
26+
public OutputStreamAesEncryption(java.io.OutputStream out, byte key[]) {
27+
this(out, key, 0, key.length);
28+
}
29+
30+
/**
31+
* Writes {@code len} bytes from the specified byte array
32+
* starting at offset {@code off} to this output stream.
33+
* The general contract for {@code write(b, off, len)} is that
34+
* some of the bytes in the array {@code b} are written to the
35+
* output stream in order; element {@code b[off]} is the first
36+
* byte written and {@code b[off+len-1]} is the last byte written
37+
* by this operation.
38+
* <p/>
39+
* The {@code write} method of {@code OutputStream} calls
40+
* the write method of one argument on each of the bytes to be
41+
* written out. Subclasses are encouraged to override this method and
42+
* provide a more efficient implementation.
43+
* <p/>
44+
* If {@code b} is {@code null}, a
45+
* {@code NullPointerException} is thrown.
46+
* <p/>
47+
* If {@code off} is negative, or {@code len} is negative, or
48+
* {@code off+len} is greater than the length of the array
49+
* {@code b}, then an <tt>IndexOutOfBoundsException</tt> is thrown.
50+
*
51+
* @param b the data.
52+
* @param off the start offset in the data.
53+
* @param len the number of bytes to write.
54+
* @throws IOException if an I/O error occurs. In particular,
55+
* an {@code IOException} is thrown if the output
56+
* stream is closed.
57+
*/
58+
public void write(byte[] b, int off, int len) throws IOException {
59+
byte[] b2 = cipher.update(b, off, len);
60+
if (b2 == null || b2.length == 0)
61+
return;
62+
out.write(b2, 0, b2.length);
63+
}
64+
65+
public void finish() {
66+
if (!finished) {
67+
finished = true;
68+
69+
byte[] b = cipher.doFinal();
70+
try {
71+
out.write(b, 0, b.length);
72+
} catch (IOException e) {
73+
throw new PdfException(PdfException.PdfEncryption, e);
74+
}
75+
}
76+
}
77+
}

kernel/src/main/java/com/itextpdf/kernel/crypto/OutputStreamEncryption.java

Lines changed: 4 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,17 @@
11
package com.itextpdf.kernel.crypto;
22

3-
import com.itextpdf.kernel.PdfException;
43
import java.io.IOException;
54

6-
public class OutputStreamEncryption extends java.io.OutputStream {
5+
public abstract class OutputStreamEncryption extends java.io.OutputStream {
76

87
protected java.io.OutputStream out;
9-
protected ARCFOUREncryption arcfour;
10-
protected AESCipher cipher;
118
private byte[] sb = new byte[1];
12-
private static final int AES_128 = 4;
13-
private static final int AES_256 = 5;
14-
private boolean aes;
15-
private boolean finished;
169

1710
/**
1811
* Creates a new instance of OutputStreamCounter
1912
*/
20-
public OutputStreamEncryption(java.io.OutputStream out, byte key[], int off, int len, int revision) {
13+
public OutputStreamEncryption(java.io.OutputStream out) {
2114
this.out = out;
22-
aes = (revision == AES_128 || revision == AES_256);
23-
if (aes) {
24-
byte[] iv = IVGenerator.getIV();
25-
byte[] nkey = new byte[len];
26-
System.arraycopy(key, off, nkey, 0, len);
27-
cipher = new AESCipher(true, nkey, iv);
28-
try {
29-
write(iv);
30-
} catch (IOException e) {
31-
throw new PdfException(PdfException.PdfEncryption, e);
32-
}
33-
} else {
34-
arcfour = new ARCFOUREncryption();
35-
arcfour.prepareARCFOURKey(key, off, len);
36-
}
37-
}
38-
39-
public OutputStreamEncryption(java.io.OutputStream out, byte key[], int revision) {
40-
this(out, key, 0, key.length, revision);
4115
}
4216

4317
/**
@@ -132,35 +106,7 @@ public void write(int b) throws IOException {
132106
* an {@code IOException} is thrown if the output
133107
* stream is closed.
134108
*/
135-
public void write(byte[] b, int off, int len) throws IOException {
136-
if (aes) {
137-
byte[] b2 = cipher.update(b, off, len);
138-
if (b2 == null || b2.length == 0)
139-
return;
140-
out.write(b2, 0, b2.length);
141-
} else {
142-
byte[] b2 = new byte[Math.min(len, 4192)];
143-
while (len > 0) {
144-
int sz = Math.min(len, b2.length);
145-
arcfour.encryptARCFOUR(b, off, sz, b2, 0);
146-
out.write(b2, 0, sz);
147-
len -= sz;
148-
off += sz;
149-
}
150-
}
151-
}
109+
public abstract void write(byte[] b, int off, int len) throws IOException;
152110

153-
public void finish() {
154-
if (!finished) {
155-
finished = true;
156-
if (aes) {
157-
byte[] b = cipher.doFinal();
158-
try {
159-
out.write(b, 0, b.length);
160-
} catch (IOException e) {
161-
throw new PdfException(PdfException.PdfEncryption, e);
162-
}
163-
}
164-
}
165-
}
111+
public abstract void finish();
166112
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.itextpdf.kernel.crypto;
2+
3+
import java.io.IOException;
4+
5+
public class OutputStreamStandardEncryption extends OutputStreamEncryption {
6+
protected ARCFOUREncryption arcfour;
7+
8+
/**
9+
* Creates a new instance of OutputStreamStandardEncryption
10+
*/
11+
public OutputStreamStandardEncryption(java.io.OutputStream out, byte key[], int off, int len) {
12+
super(out);
13+
arcfour = new ARCFOUREncryption();
14+
arcfour.prepareARCFOURKey(key, off, len);
15+
}
16+
17+
public OutputStreamStandardEncryption(java.io.OutputStream out, byte key[]) {
18+
this(out, key, 0, key.length);
19+
}
20+
21+
/**
22+
* Writes {@code len} bytes from the specified byte array
23+
* starting at offset {@code off} to this output stream.
24+
* The general contract for {@code write(b, off, len)} is that
25+
* some of the bytes in the array {@code b} are written to the
26+
* output stream in order; element {@code b[off]} is the first
27+
* byte written and {@code b[off+len-1]} is the last byte written
28+
* by this operation.
29+
* <p/>
30+
* The {@code write} method of {@code OutputStream} calls
31+
* the write method of one argument on each of the bytes to be
32+
* written out. Subclasses are encouraged to override this method and
33+
* provide a more efficient implementation.
34+
* <p/>
35+
* If {@code b} is {@code null}, a
36+
* {@code NullPointerException} is thrown.
37+
* <p/>
38+
* If {@code off} is negative, or {@code len} is negative, or
39+
* {@code off+len} is greater than the length of the array
40+
* {@code b}, then an <tt>IndexOutOfBoundsException</tt> is thrown.
41+
*
42+
* @param b the data.
43+
* @param off the start offset in the data.
44+
* @param len the number of bytes to write.
45+
* @throws IOException if an I/O error occurs. In particular,
46+
* an {@code IOException} is thrown if the output
47+
* stream is closed.
48+
*/
49+
public void write(byte[] b, int off, int len) throws IOException {
50+
byte[] b2 = new byte[Math.min(len, 4192)];
51+
while (len > 0) {
52+
int sz = Math.min(len, b2.length);
53+
arcfour.encryptARCFOUR(b, off, sz, b2, 0);
54+
out.write(b2, 0, sz);
55+
len -= sz;
56+
off += sz;
57+
}
58+
}
59+
60+
public void finish() { }
61+
}

kernel/src/main/java/com/itextpdf/kernel/crypto/StandardDecryption.java

Lines changed: 0 additions & 61 deletions
This file was deleted.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.itextpdf.kernel.crypto;
2+
3+
public class StandardDecryptor implements Decryptor {
4+
5+
protected ARCFOUREncryption arcfour;
6+
7+
/**
8+
* Creates a new instance of StandardDecryption
9+
*/
10+
public StandardDecryptor(byte key[], int off, int len) {
11+
arcfour = new ARCFOUREncryption();
12+
arcfour.prepareARCFOURKey(key, off, len);
13+
}
14+
15+
public byte[] update(byte[] b, int off, int len) {
16+
byte[] b2 = new byte[len];
17+
arcfour.encryptARCFOUR(b, off, len, b2, 0);
18+
return b2;
19+
}
20+
21+
public byte[] finish() {
22+
return null;
23+
}
24+
}

0 commit comments

Comments
 (0)