1 /*
2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
38 import java.lang.RuntimeException;
39 import java.lang.Throwable;
40 import java.security.AlgorithmParameters;
41 import javax.crypto.AEADBadTagException;
42 import javax.crypto.Cipher;
43 import javax.crypto.CipherInputStream;
44 import javax.crypto.IllegalBlockSizeException;
45 import javax.crypto.spec.IvParameterSpec;
46 import javax.crypto.spec.SecretKeySpec;
47 import javax.crypto.spec.GCMParameterSpec;
48
49 public class CipherInputStreamExceptions {
50
51 static SecretKeySpec key = new SecretKeySpec(new byte[16], "AES");
52 static GCMParameterSpec gcmspec = new GCMParameterSpec(128, new byte[16]);
53 static IvParameterSpec iv = new IvParameterSpec(new byte[16]);
54 static boolean failure = false;
55
56 /* Full read stream, check that getMoreData() is throwing an exception
57 * This test
58 * 1) Encrypt 100 bytes with AES/GCM/PKCS5Padding
59 * 2) Changes the last byte to invalidate the authetication tag.
60 * 3) Fully reads CipherInputStream to decrypt the message and closes
61 */
62
63 static void gcm_AEADBadTag() throws Exception {
64 Cipher c;
65 byte[] read = new byte[200];
66
67 System.out.println("Running gcm_AEADBadTag");
68
69 // Encrypt 100 bytes with AES/GCM/PKCS5Padding
70 byte[] ct = encryptedText("GCM", 100);
71 // Corrupt the encrypted message
72 ct = corruptGCM(ct);
73 // Create stream for decryption
74 CipherInputStream in = getStream("GCM", ct);
75
76 try {
77 int size = in.read(read);
78 throw new RuntimeException("Fail: CipherInputStream.read() " +
79 "returned " + size + " and didn't throw an exception.");
80 } catch (IOException e) {
81 Throwable ec = e.getCause();
82 if (ec instanceof AEADBadTagException) {
83 System.out.println(" Pass.");
84 } else {
85 System.out.println(" Fail: " + ec.getMessage());
86 throw new RuntimeException(ec);
87 }
88 } finally {
89 in.close();
90 }
91 }
92
93 /* Short read stream,
94 * This test
95 * 1) Encrypt 100 bytes with AES/GCM/PKCS5Padding
96 * 2) Reads 100 bytes from stream to decrypt the message and closes
97 * 3) Make sure no value is returned by read()
98 * 4) Make sure no exception is thrown
99 */
100
101 static void gcm_shortReadAEAD() throws Exception {
102 Cipher c;
103 byte[] read = new byte[100];
104
105 System.out.println("Running gcm_shortReadAEAD");
106
107 byte[] pt = new byte[600];
108 pt[0] = 1;
109 // Encrypt provided 600 bytes with AES/GCM/PKCS5Padding
110 byte[] ct = encryptedText("GCM", pt);
111 // Create stream for decryption
112 CipherInputStream in = getStream("GCM", ct);
113
114 int size = 0;
115 try {
116 size = in.read(read);
117 in.close();
118 if (read.length != 100) {
119 throw new RuntimeException("Fail: read size = " + read.length +
120 "should be 100.");
121 }
122 if (read[0] != 1) {
123 throw new RuntimeException("Fail: The decrypted text does " +
124 "not match the plaintext: '" + read[0] +"'");
125 }
126 } catch (IOException e) {
127 System.out.println(" Fail: " + e.getMessage());
128 throw new RuntimeException(e.getCause());
129 }
130 System.out.println(" Pass.");
131 }
132
133 /*
134 * Verify doFinal() exception is suppressed when input stream is not
135 * read before it is closed.
136 * This test:
137 * 1) Encrypt 100 bytes with AES/GCM/PKCS5Padding
138 * 2) Changes the last byte to invalidate the authetication tag.
139 * 3) Opens a CipherInputStream and the closes it. Never reads from it.
140 *
141 * There should be no exception thrown.
142 */
143 static void gcm_suppressUnreadCorrupt() throws Exception {
144 Cipher c;
145 byte[] read = new byte[200];
146
147 System.out.println("Running supressUnreadCorrupt test");
148
149 // Encrypt 100 bytes with AES/GCM/PKCS5Padding
150 byte[] ct = encryptedText("GCM", 100);
151 // Corrupt the encrypted message
152 ct = corruptGCM(ct);
153 // Create stream for decryption
154 CipherInputStream in = getStream("GCM", ct);
155
156 try {
157 in.close();
158 System.out.println(" Pass.");
159 } catch (IOException e) {
160 System.out.println(" Fail: " + e.getMessage());
161 throw new RuntimeException(e.getCause());
162 }
163 }
164
165 /*
166 * Verify noexception thrown when 1 byte is read from a GCM stream
167 * and then closed
168 * This test:
169 * 1) Encrypt 100 bytes with AES/GCM/PKCS5Padding
170 * 2) Read one byte from the stream, expect no exception thrown.
171 * 4) Close stream,expect no exception thrown.
172 */
173 static void gcm_oneReadByte() throws Exception {
174
175 System.out.println("Running gcm_oneReadByte test");
176
177 // Encrypt 100 bytes with AES/GCM/PKCS5Padding
178 byte[] ct = encryptedText("GCM", 100);
179 // Create stream for decryption
180 CipherInputStream in = getStream("GCM", ct);
181
182 try {
183 in.read();
184 System.out.println(" Pass.");
185 } catch (Exception e) {
186 System.out.println(" Fail: " + e.getMessage());
187 throw new RuntimeException(e.getCause());
188 }
189 }
190
191 /*
192 * Verify exception thrown when 1 byte is read from a corrupted GCM stream
193 * and then closed
194 * This test:
195 * 1) Encrypt 100 bytes with AES/GCM/PKCS5Padding
196 * 2) Changes the last byte to invalidate the authetication tag.
197 * 3) Read one byte from the stream, expect exception thrown.
198 * 4) Close stream,expect no exception thrown.
199 */
200 static void gcm_oneReadByteCorrupt() throws Exception {
201
202 System.out.println("Running gcm_oneReadByteCorrupt test");
203
204 // Encrypt 100 bytes with AES/GCM/PKCS5Padding
205 byte[] ct = encryptedText("GCM", 100);
206 // Corrupt the encrypted message
207 ct = corruptGCM(ct);
208 // Create stream for decryption
209 CipherInputStream in = getStream("GCM", ct);
210
211 try {
212 in.read();
213 System.out.println(" Fail. No exception thrown.");
214 } catch (IOException e) {
215 Throwable ec = e.getCause();
216 if (ec instanceof AEADBadTagException) {
217 System.out.println(" Pass.");
218 } else {
219 System.out.println(" Fail: " + ec.getMessage());
220 throw new RuntimeException(ec);
221 }
222 }
223 }
224
340 } catch (IOException e) {
341 Throwable ec = e.getCause();
342 if (ec instanceof IllegalBlockSizeException) {
343 System.out.println(" Pass.");
344 } else {
345 System.out.println(" Fail: " + ec.getMessage());
346 throw new RuntimeException(ec);
347 }
348 }
349 }
350
351 /* Generic method to create encrypted text */
352 static byte[] encryptedText(String mode, int length) throws Exception{
353 return encryptedText(mode, new byte[length]);
354 }
355
356 /* Generic method to create encrypted text */
357 static byte[] encryptedText(String mode, byte[] pt) throws Exception{
358 Cipher c;
359 if (mode.compareTo("GCM") == 0) {
360 c = Cipher.getInstance("AES/GCM/PKCS5Padding", "SunJCE");
361 c.init(Cipher.ENCRYPT_MODE, key, gcmspec);
362 } else if (mode.compareTo("CBC") == 0) {
363 c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
364 c.init(Cipher.ENCRYPT_MODE, key, iv);
365 } else {
366 return null;
367 }
368
369 return c.doFinal(pt);
370 }
371
372 /* Generic method to get a properly setup CipherInputStream */
373 static CipherInputStream getStream(String mode, byte[] ct) throws Exception {
374 return getStream(mode, ct, ct.length);
375 }
376
377 /* Generic method to get a properly setup CipherInputStream */
378 static CipherInputStream getStream(String mode, byte[] ct, int length)
379 throws Exception {
380 Cipher c;
381
382 if (mode.compareTo("GCM") == 0) {
383 c = Cipher.getInstance("AES/GCM/PKCS5Padding", "SunJCE");
384 c.init(Cipher.DECRYPT_MODE, key, gcmspec);
385 } else if (mode.compareTo("CBC") == 0) {
386 c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
387 c.init(Cipher.DECRYPT_MODE, key, iv);
388 } else {
389 return null;
390 }
391
392 return new CipherInputStream(new ByteArrayInputStream(ct, 0, length), c);
393
394 }
395
396 /* Generic method for corrupting a GCM message. Change the last
397 * byte on of the authentication tag
398 */
399 static byte[] corruptGCM(byte[] ct) {
400 ct[ct.length - 1] = (byte) (ct[ct.length - 1] + 1);
401 return ct;
402 }
403
|
1 /*
2 * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
38 import java.lang.RuntimeException;
39 import java.lang.Throwable;
40 import java.security.AlgorithmParameters;
41 import javax.crypto.AEADBadTagException;
42 import javax.crypto.Cipher;
43 import javax.crypto.CipherInputStream;
44 import javax.crypto.IllegalBlockSizeException;
45 import javax.crypto.spec.IvParameterSpec;
46 import javax.crypto.spec.SecretKeySpec;
47 import javax.crypto.spec.GCMParameterSpec;
48
49 public class CipherInputStreamExceptions {
50
51 static SecretKeySpec key = new SecretKeySpec(new byte[16], "AES");
52 static GCMParameterSpec gcmspec = new GCMParameterSpec(128, new byte[16]);
53 static IvParameterSpec iv = new IvParameterSpec(new byte[16]);
54 static boolean failure = false;
55
56 /* Full read stream, check that getMoreData() is throwing an exception
57 * This test
58 * 1) Encrypt 100 bytes with AES/GCM/NoPadding
59 * 2) Changes the last byte to invalidate the authetication tag.
60 * 3) Fully reads CipherInputStream to decrypt the message and closes
61 */
62
63 static void gcm_AEADBadTag() throws Exception {
64 Cipher c;
65 byte[] read = new byte[200];
66
67 System.out.println("Running gcm_AEADBadTag");
68
69 // Encrypt 100 bytes with AES/GCM/NoPadding
70 byte[] ct = encryptedText("GCM", 100);
71 // Corrupt the encrypted message
72 ct = corruptGCM(ct);
73 // Create stream for decryption
74 CipherInputStream in = getStream("GCM", ct);
75
76 try {
77 int size = in.read(read);
78 throw new RuntimeException("Fail: CipherInputStream.read() " +
79 "returned " + size + " and didn't throw an exception.");
80 } catch (IOException e) {
81 Throwable ec = e.getCause();
82 if (ec instanceof AEADBadTagException) {
83 System.out.println(" Pass.");
84 } else {
85 System.out.println(" Fail: " + ec.getMessage());
86 throw new RuntimeException(ec);
87 }
88 } finally {
89 in.close();
90 }
91 }
92
93 /* Short read stream,
94 * This test
95 * 1) Encrypt 100 bytes with AES/GCM/NoPadding
96 * 2) Reads 100 bytes from stream to decrypt the message and closes
97 * 3) Make sure no value is returned by read()
98 * 4) Make sure no exception is thrown
99 */
100
101 static void gcm_shortReadAEAD() throws Exception {
102 Cipher c;
103 byte[] read = new byte[100];
104
105 System.out.println("Running gcm_shortReadAEAD");
106
107 byte[] pt = new byte[600];
108 pt[0] = 1;
109 // Encrypt provided 600 bytes with AES/GCM/NoPadding
110 byte[] ct = encryptedText("GCM", pt);
111 // Create stream for decryption
112 CipherInputStream in = getStream("GCM", ct);
113
114 int size = 0;
115 try {
116 size = in.read(read);
117 in.close();
118 if (read.length != 100) {
119 throw new RuntimeException("Fail: read size = " + read.length +
120 "should be 100.");
121 }
122 if (read[0] != 1) {
123 throw new RuntimeException("Fail: The decrypted text does " +
124 "not match the plaintext: '" + read[0] +"'");
125 }
126 } catch (IOException e) {
127 System.out.println(" Fail: " + e.getMessage());
128 throw new RuntimeException(e.getCause());
129 }
130 System.out.println(" Pass.");
131 }
132
133 /*
134 * Verify doFinal() exception is suppressed when input stream is not
135 * read before it is closed.
136 * This test:
137 * 1) Encrypt 100 bytes with AES/GCM/NoPadding
138 * 2) Changes the last byte to invalidate the authetication tag.
139 * 3) Opens a CipherInputStream and the closes it. Never reads from it.
140 *
141 * There should be no exception thrown.
142 */
143 static void gcm_suppressUnreadCorrupt() throws Exception {
144 Cipher c;
145 byte[] read = new byte[200];
146
147 System.out.println("Running supressUnreadCorrupt test");
148
149 // Encrypt 100 bytes with AES/GCM/NoPadding
150 byte[] ct = encryptedText("GCM", 100);
151 // Corrupt the encrypted message
152 ct = corruptGCM(ct);
153 // Create stream for decryption
154 CipherInputStream in = getStream("GCM", ct);
155
156 try {
157 in.close();
158 System.out.println(" Pass.");
159 } catch (IOException e) {
160 System.out.println(" Fail: " + e.getMessage());
161 throw new RuntimeException(e.getCause());
162 }
163 }
164
165 /*
166 * Verify noexception thrown when 1 byte is read from a GCM stream
167 * and then closed
168 * This test:
169 * 1) Encrypt 100 bytes with AES/GCM/NoPadding
170 * 2) Read one byte from the stream, expect no exception thrown.
171 * 4) Close stream,expect no exception thrown.
172 */
173 static void gcm_oneReadByte() throws Exception {
174
175 System.out.println("Running gcm_oneReadByte test");
176
177 // Encrypt 100 bytes with AES/GCM/NoPadding
178 byte[] ct = encryptedText("GCM", 100);
179 // Create stream for decryption
180 CipherInputStream in = getStream("GCM", ct);
181
182 try {
183 in.read();
184 System.out.println(" Pass.");
185 } catch (Exception e) {
186 System.out.println(" Fail: " + e.getMessage());
187 throw new RuntimeException(e.getCause());
188 }
189 }
190
191 /*
192 * Verify exception thrown when 1 byte is read from a corrupted GCM stream
193 * and then closed
194 * This test:
195 * 1) Encrypt 100 bytes with AES/GCM/NoPadding
196 * 2) Changes the last byte to invalidate the authetication tag.
197 * 3) Read one byte from the stream, expect exception thrown.
198 * 4) Close stream,expect no exception thrown.
199 */
200 static void gcm_oneReadByteCorrupt() throws Exception {
201
202 System.out.println("Running gcm_oneReadByteCorrupt test");
203
204 // Encrypt 100 bytes with AES/GCM/NoPadding
205 byte[] ct = encryptedText("GCM", 100);
206 // Corrupt the encrypted message
207 ct = corruptGCM(ct);
208 // Create stream for decryption
209 CipherInputStream in = getStream("GCM", ct);
210
211 try {
212 in.read();
213 System.out.println(" Fail. No exception thrown.");
214 } catch (IOException e) {
215 Throwable ec = e.getCause();
216 if (ec instanceof AEADBadTagException) {
217 System.out.println(" Pass.");
218 } else {
219 System.out.println(" Fail: " + ec.getMessage());
220 throw new RuntimeException(ec);
221 }
222 }
223 }
224
340 } catch (IOException e) {
341 Throwable ec = e.getCause();
342 if (ec instanceof IllegalBlockSizeException) {
343 System.out.println(" Pass.");
344 } else {
345 System.out.println(" Fail: " + ec.getMessage());
346 throw new RuntimeException(ec);
347 }
348 }
349 }
350
351 /* Generic method to create encrypted text */
352 static byte[] encryptedText(String mode, int length) throws Exception{
353 return encryptedText(mode, new byte[length]);
354 }
355
356 /* Generic method to create encrypted text */
357 static byte[] encryptedText(String mode, byte[] pt) throws Exception{
358 Cipher c;
359 if (mode.compareTo("GCM") == 0) {
360 c = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");
361 c.init(Cipher.ENCRYPT_MODE, key, gcmspec);
362 } else if (mode.compareTo("CBC") == 0) {
363 c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
364 c.init(Cipher.ENCRYPT_MODE, key, iv);
365 } else {
366 return null;
367 }
368
369 return c.doFinal(pt);
370 }
371
372 /* Generic method to get a properly setup CipherInputStream */
373 static CipherInputStream getStream(String mode, byte[] ct) throws Exception {
374 return getStream(mode, ct, ct.length);
375 }
376
377 /* Generic method to get a properly setup CipherInputStream */
378 static CipherInputStream getStream(String mode, byte[] ct, int length)
379 throws Exception {
380 Cipher c;
381
382 if (mode.compareTo("GCM") == 0) {
383 c = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");
384 c.init(Cipher.DECRYPT_MODE, key, gcmspec);
385 } else if (mode.compareTo("CBC") == 0) {
386 c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
387 c.init(Cipher.DECRYPT_MODE, key, iv);
388 } else {
389 return null;
390 }
391
392 return new CipherInputStream(new ByteArrayInputStream(ct, 0, length), c);
393
394 }
395
396 /* Generic method for corrupting a GCM message. Change the last
397 * byte on of the authentication tag
398 */
399 static byte[] corruptGCM(byte[] ct) {
400 ct[ct.length - 1] = (byte) (ct[ct.length - 1] + 1);
401 return ct;
402 }
403
|