1/*
2 * Copyright (c) 2012, 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
24import java.io.PrintStream;
25import java.security.NoSuchAlgorithmException;
26import java.security.spec.AlgorithmParameterSpec;
27import java.util.Arrays;
28import java.util.Random;
29
30import javax.crypto.Cipher;
31import javax.crypto.KeyGenerator;
32import javax.crypto.SecretKey;
33import javax.crypto.spec.IvParameterSpec;
34
35public class Dynamic {
36
37    static final String ALGORITHM = "AES";
38    static final String[] MODE = {
39        "ECb", "CbC", "CTR", "PCBC", "OFB", "OFB150", "cFB", "CFB7",
40        "cFB8", "cFB16", "cFB24", "cFB32", "Cfb40", "cfB48", "cfB56",
41        "cfB64", "cfB72", "cfB80", "cfB88", "cfB96", "cfb104", "cfB112",
42        "cfB120", "cfB128", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40",
43        "OFB48", "OFB56", "OFB64", "OFB72", "OFB80", "OFB88", "OFB96",
44        "OFB104", "OFB112", "OFB120", "OFB128", "GCM"
45    };
46    static final String[] PADDING = {
47        "NoPadding", "PKCS5Padding", "ISO10126Padding"
48    };
49    static final String SUNJCE = "SunJCE";
50
51    Cipher ci = null;
52    byte[] iv = null;
53    AlgorithmParameterSpec aps = null;
54    SecretKey key = null;
55    int keyStrength;
56    static int DefaultSize = 128;
57
58    public void run(String[] argv) throws Exception {
59        if (!runAllTest(argv, System.out)) {
60            throw new Exception("Test Failed");
61        }
62    }
63
64    protected boolean runAllTest(String argv[], PrintStream out) {
65        boolean result = true;
66        StringBuilder failedList = new StringBuilder();
67        int failedCnt = 0;
68        int testCount = 0;
69        int padKinds; // how many kinds of padding mode such as PKCS5padding and
70        // NoPadding.
71
72        try {
73            for (int i = 0; i < 3; i++) {
74                keyStrength = DefaultSize + i * 64; // obtain the key size 128,
75                // 192, 256
76
77                for (int j = 0; j < MODE.length; j++) {
78                    if (MODE[j].equalsIgnoreCase("ECB")
79                            || MODE[j].equalsIgnoreCase("PCBC")
80                            || MODE[j].equalsIgnoreCase("CBC")) {
81                        padKinds = PADDING.length;
82                    } else {
83                        padKinds = 1;
84                    }
85
86                    for (int k = 0; k < padKinds; k++) {
87                        testCount++;
88                        try {
89                            if (!runTest(ALGORITHM, MODE[j], PADDING[k])) {
90                                result = false;
91                                failedCnt++;
92                                failedList.append(ALGORITHM + "/" + MODE[j]
93                                        + "/" + PADDING[k] + " ");
94                            }
95                        } catch (Exception e) {
96                            e.printStackTrace();
97                            result = false;
98                            failedCnt++;
99                            failedList.append(ALGORITHM + "/" + MODE[j] + "/"
100                                    + PADDING[k] + " ");
101                        }
102
103                    }
104                }
105            }
106
107            if (result) {
108                out.println("STATUS:Passed. Test " + testCount
109                        + " cases, All Passed");
110                return true;
111            }
112            out.println("STATUS:Failed. " + failedCnt + " Failed: "
113                    + failedList);
114            return false;
115
116        } catch (Exception ex) {
117            ex.printStackTrace();
118            out.println("STATUS:Failed. Unexpected Exception: " + ex);
119            return false;
120        }
121    }
122
123    protected boolean runTest(String algo, String mo, String pad)
124            throws Exception {
125        boolean result = true;
126        try {
127            byte[] plainText = new byte[160000];
128            new Random().nextBytes(plainText);
129
130            String transformation = algo + "/" + mo + "/" + pad;
131            ci = Cipher.getInstance(transformation, SUNJCE);
132            KeyGenerator kg = KeyGenerator.getInstance(algo, SUNJCE);
133            if (keyStrength > Cipher.getMaxAllowedKeyLength(transformation)) {
134                // skip if this key length is larger than what's
135                // configured in the jce jurisdiction policy files
136                System.out.println(keyStrength
137                        + " is larger than what's configured "
138                        + "in the jce jurisdiction policy files");
139                return result;
140            }
141            kg.init(keyStrength);
142            key = kg.generateKey();
143
144            if (!mo.equalsIgnoreCase("GCM")) {
145                ci.init(Cipher.ENCRYPT_MODE, key, aps);
146            } else {
147                ci.init(Cipher.ENCRYPT_MODE, key);
148            }
149            byte[] cipherText = new byte[ci.getOutputSize(plainText.length)];
150            int offset = ci.update(plainText, 0, plainText.length, cipherText,
151                    0);
152            ci.doFinal(cipherText, offset);
153            ci.init(Cipher.DECRYPT_MODE, key, ci.getParameters());
154
155            byte[] recoveredText = new byte[ci.getOutputSize(cipherText.length)];
156            int len = ci.doFinal(cipherText, 0, cipherText.length,
157                    recoveredText);
158
159            byte[] tmp = new byte[len];
160            for (int i = 0; i < len; i++) {
161                tmp[i] = recoveredText[i];
162            }
163
164            result = Arrays.equals(plainText, tmp);
165        } catch (NoSuchAlgorithmException nsaEx) {
166            // CFB7 and OFB150 are negative test,SunJCE not support this
167            // algorithm
168            result = mo.equalsIgnoreCase("CFB7")
169                    || mo.equalsIgnoreCase("OFB150");
170            if (!result) {
171                // only report unexpected exception
172                nsaEx.printStackTrace();
173            }
174        }
175        return result;
176    }
177}
178