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