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