1 /*
2  * Copyright (c) 2008, 2018, 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  */
23 
24 /*
25  * @test
26  * @bug 4898461 6604496
27  * @summary basic test for symmetric ciphers with padding
28  * @author Valerie Peng
29  * @library /test/lib ..
30  * @key randomness
31  * @modules jdk.crypto.cryptoki
32  * @run main/othervm TestSymmCiphers
33  * @run main/othervm TestSymmCiphers sm
34  */
35 
36 import java.io.ByteArrayOutputStream;
37 import java.nio.ByteBuffer;
38 import java.security.AlgorithmParameters;
39 import java.security.NoSuchAlgorithmException;
40 import java.security.Provider;
41 import java.util.Random;
42 import javax.crypto.Cipher;
43 import javax.crypto.KeyGenerator;
44 import javax.crypto.SecretKey;
45 
46 public class TestSymmCiphers extends PKCS11Test {
47 
48     private static class CI { // class for holding Cipher Information
49 
50         String transformation;
51         String keyAlgo;
52         int dataSize;
53 
CI(String transformation, String keyAlgo, int dataSize)54         CI(String transformation, String keyAlgo, int dataSize) {
55             this.transformation = transformation;
56             this.keyAlgo = keyAlgo;
57             this.dataSize = dataSize;
58         }
59     }
60     private static final CI[] TEST_LIST = {
61         new CI("ARCFOUR", "ARCFOUR", 400),
62         new CI("RC4", "RC4", 401),
63         new CI("DES/CBC/NoPadding", "DES", 400),
64         new CI("DESede/CBC/NoPadding", "DESede", 160),
65         new CI("AES/CBC/NoPadding", "AES", 4800),
66         new CI("Blowfish/CBC/NoPadding", "Blowfish", 24),
67         new CI("DES/cbc/PKCS5Padding", "DES", 6401),
68         new CI("DESede/CBC/PKCS5Padding", "DESede", 402),
69         new CI("AES/CBC/PKCS5Padding", "AES", 30),
70         new CI("Blowfish/CBC/PKCS5Padding", "Blowfish", 19),
71         new CI("DES/ECB/NoPadding", "DES", 400),
72         new CI("DESede/ECB/NoPadding", "DESede", 160),
73         new CI("AES/ECB/NoPadding", "AES", 4800),
74         new CI("DES/ECB/PKCS5Padding", "DES", 32),
75         new CI("DES/ECB/PKCS5Padding", "DES", 6400),
76         new CI("DESede/ECB/PKCS5Padding", "DESede", 400),
77         new CI("AES/ECB/PKCS5Padding", "AES", 64),
78 
79         new CI("DES", "DES", 6400),
80         new CI("DESede", "DESede", 408),
81         new CI("AES", "AES", 128),
82 
83         new CI("AES/CTR/NoPadding", "AES", 3200)
84 
85     };
86     private static StringBuffer debugBuf = new StringBuffer();
87 
88     @Override
main(Provider p)89     public void main(Provider p) throws Exception {
90         // NSS reports CKR_DEVICE_ERROR when the data passed to
91         // its EncryptUpdate/DecryptUpdate is not multiple of blocks
92         int firstBlkSize = 16;
93         boolean status = true;
94         Random random = new Random();
95         try {
96             for (int i = 0; i < TEST_LIST.length; i++) {
97                 CI currTest = TEST_LIST[i];
98                 System.out.println("===" + currTest.transformation + "===");
99                 try {
100                     KeyGenerator kg =
101                             KeyGenerator.getInstance(currTest.keyAlgo, p);
102                     SecretKey key = kg.generateKey();
103                     Cipher c1 = Cipher.getInstance(currTest.transformation, p);
104                     Cipher c2 = Cipher.getInstance(currTest.transformation,
105                             "SunJCE");
106 
107                     byte[] plainTxt = new byte[currTest.dataSize];
108                     random.nextBytes(plainTxt);
109                     System.out.println("Testing inLen = " + plainTxt.length);
110 
111                     c2.init(Cipher.ENCRYPT_MODE, key);
112                     AlgorithmParameters params = c2.getParameters();
113                     byte[] answer = c2.doFinal(plainTxt);
114                     System.out.println("Encryption tests: START");
115                     test(c1, Cipher.ENCRYPT_MODE, key, params, firstBlkSize,
116                             plainTxt, answer);
117                     System.out.println("Encryption tests: DONE");
118                     c2.init(Cipher.DECRYPT_MODE, key, params);
119                     byte[] answer2 = c2.doFinal(answer);
120                     System.out.println("Decryption tests: START");
121                     test(c1, Cipher.DECRYPT_MODE, key, params, firstBlkSize,
122                             answer, answer2);
123                     System.out.println("Decryption tests: DONE");
124                 } catch (NoSuchAlgorithmException nsae) {
125                     System.out.println("Skipping unsupported algorithm: " +
126                             nsae);
127                 }
128             }
129         } catch (Exception ex) {
130             // print out debug info when exception is encountered
131             if (debugBuf != null) {
132                 System.out.println(debugBuf.toString());
133                 debugBuf = new StringBuffer();
134             }
135             throw ex;
136         }
137     }
138 
test(Cipher cipher, int mode, SecretKey key, AlgorithmParameters params, int firstBlkSize, byte[] in, byte[] answer)139     private static void test(Cipher cipher, int mode, SecretKey key,
140             AlgorithmParameters params, int firstBlkSize,
141             byte[] in, byte[] answer) throws Exception {
142         // test setup
143         long startTime, endTime;
144         cipher.init(mode, key, params);
145         int outLen = cipher.getOutputSize(in.length);
146         //debugOut("Estimated output size = " + outLen + "\n");
147 
148         // test data preparation
149         ByteBuffer inBuf = ByteBuffer.allocate(in.length);
150         inBuf.put(in);
151         inBuf.position(0);
152         ByteBuffer inDirectBuf = ByteBuffer.allocateDirect(in.length);
153         inDirectBuf.put(in);
154         inDirectBuf.position(0);
155         ByteBuffer outBuf = ByteBuffer.allocate(outLen);
156         ByteBuffer outDirectBuf = ByteBuffer.allocateDirect(outLen);
157 
158         // test#1: byte[] in + byte[] out
159         //debugOut("Test#1:\n");
160 
161         ByteArrayOutputStream baos = new ByteArrayOutputStream();
162 
163         startTime = System.nanoTime();
164         byte[] temp = cipher.update(in, 0, firstBlkSize);
165         if (temp != null && temp.length > 0) {
166             baos.write(temp, 0, temp.length);
167         }
168         temp = cipher.doFinal(in, firstBlkSize, in.length - firstBlkSize);
169         if (temp != null && temp.length > 0) {
170             baos.write(temp, 0, temp.length);
171         }
172         byte[] testOut1 = baos.toByteArray();
173         endTime = System.nanoTime();
174         perfOut("stream InBuf + stream OutBuf: " +
175                 (endTime - startTime));
176         match(testOut1, answer);
177 
178         // test#2: Non-direct Buffer in + non-direct Buffer out
179         //debugOut("Test#2:\n");
180         //debugOut("inputBuf: " + inBuf + "\n");
181         //debugOut("outputBuf: " + outBuf + "\n");
182 
183         startTime = System.nanoTime();
184         cipher.update(inBuf, outBuf);
185         cipher.doFinal(inBuf, outBuf);
186         endTime = System.nanoTime();
187         perfOut("non-direct InBuf + non-direct OutBuf: " +
188                 (endTime - startTime));
189         match(outBuf, answer);
190 
191         // test#3: Direct Buffer in + direc Buffer out
192         //debugOut("Test#3:\n");
193         //debugOut("(pre) inputBuf: " + inDirectBuf + "\n");
194         //debugOut("(pre) outputBuf: " + outDirectBuf + "\n");
195 
196         startTime = System.nanoTime();
197         cipher.update(inDirectBuf, outDirectBuf);
198         cipher.doFinal(inDirectBuf, outDirectBuf);
199         endTime = System.nanoTime();
200         perfOut("direct InBuf + direct OutBuf: " +
201                 (endTime - startTime));
202 
203         //debugOut("(post) inputBuf: " + inDirectBuf + "\n");
204         //debugOut("(post) outputBuf: " + outDirectBuf + "\n");
205         match(outDirectBuf, answer);
206 
207         // test#4: Direct Buffer in + non-direct Buffer out
208         //debugOut("Test#4:\n");
209         inDirectBuf.position(0);
210         outBuf.position(0);
211         //debugOut("inputBuf: " + inDirectBuf + "\n");
212         //debugOut("outputBuf: " + outBuf + "\n");
213 
214         startTime = System.nanoTime();
215         cipher.update(inDirectBuf, outBuf);
216         cipher.doFinal(inDirectBuf, outBuf);
217         endTime = System.nanoTime();
218         perfOut("direct InBuf + non-direct OutBuf: " +
219                 (endTime - startTime));
220         match(outBuf, answer);
221 
222         // test#5: Non-direct Buffer in + direct Buffer out
223         //debugOut("Test#5:\n");
224         inBuf.position(0);
225         outDirectBuf.position(0);
226 
227         //debugOut("(pre) inputBuf: " + inBuf + "\n");
228         //debugOut("(pre) outputBuf: " + outDirectBuf + "\n");
229 
230         startTime = System.nanoTime();
231         cipher.update(inBuf, outDirectBuf);
232         cipher.doFinal(inBuf, outDirectBuf);
233         endTime = System.nanoTime();
234         perfOut("non-direct InBuf + direct OutBuf: " +
235                 (endTime - startTime));
236 
237         //debugOut("(post) inputBuf: " + inBuf + "\n");
238         //debugOut("(post) outputBuf: " + outDirectBuf + "\n");
239         match(outDirectBuf, answer);
240 
241         debugBuf = null;
242     }
243 
perfOut(String msg)244     private static void perfOut(String msg) {
245         if (debugBuf != null) {
246             debugBuf.append("PERF>" + msg);
247         }
248     }
249 
debugOut(String msg)250     private static void debugOut(String msg) {
251         if (debugBuf != null) {
252             debugBuf.append(msg);
253         }
254     }
255 
match(byte[] b1, byte[] b2)256     private static void match(byte[] b1, byte[] b2) throws Exception {
257         if (b1.length != b2.length) {
258             debugOut("got len   : " + b1.length + "\n");
259             debugOut("expect len: " + b2.length + "\n");
260             throw new Exception("mismatch - different length! got: " + b1.length + ", expect: " + b2.length + "\n");
261         } else {
262             for (int i = 0; i < b1.length; i++) {
263                 if (b1[i] != b2[i]) {
264                     debugOut("got   : " + toString(b1) + "\n");
265                     debugOut("expect: " + toString(b2) + "\n");
266                     throw new Exception("mismatch");
267                 }
268             }
269         }
270     }
271 
match(ByteBuffer bb, byte[] answer)272     private static void match(ByteBuffer bb, byte[] answer) throws Exception {
273         byte[] bbTemp = new byte[bb.position()];
274         bb.position(0);
275         bb.get(bbTemp, 0, bbTemp.length);
276         match(bbTemp, answer);
277     }
278 
main(String[] args)279     public static void main(String[] args) throws Exception {
280         main(new TestSymmCiphers(), args);
281     }
282 }
283