/* * * * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package javax.crypto; import gnu.testlet.TestHarness; import gnu.testlet.Testlet; import javax.crypto.*; import javax.crypto.spec.SecretKeySpec; import java.security.NoSuchAlgorithmException; import java.security.InvalidKeyException; /** * This test case tests ARCFOUR (RC4) cipher */ public class TestRC4 implements Testlet { public int getExpectedPass() { return 66; } public int getExpectedFail() { return 0; } public int getExpectedKnownFail() { return 0; } private static final byte[] SECRET_KEY = { 0x73, 0x65, 0x63, 0x72, 0x65, 0x74 // "secret" }; private static final byte[] PLAIN_TEXT = { 0x70, 0x6C, 0x61, 0x69, 0x6E, 0x74, 0x65, 0x78, 0x74 // "plaintext" }; // cipher text corresponded to the plain text "plaintextplaintext" private static final byte[] CIPHER_TEXT_PART_1 = { (byte) 0x9D, 0x5A, (byte) 0xB3, 0x75, (byte) 0xEC, (byte) 0xD0, (byte) 0xB3, (byte) 0xDE, 0x46 }; private static final byte[] CIPHER_TEXT_PART_2 = { (byte) 0xBB, (byte) 0xD7, (byte) 0xBD, (byte) 0x9A, (byte) 0x88, (byte) 0x81, 0x52, (byte) 0xD5, 0x43 }; private static final String ALGORITHM = "arcfour"; private static final String MODE = "/none"; private static final String PADDING = "/nopadding"; private byte[] outBuf1 = null; private byte[] outBuf2 = null; private Cipher cipher = null; private SecretKeySpec key = null; /** * Test all primitive operations. */ private void testOne(TestHarness th) { // preparation boolean noSuchAlg = false; boolean noSuchPad = false; boolean invKey = false; boolean illState = false; boolean shortBuf = false; boolean illBlSize = false; boolean badPad = false; int outLen = 0; outBuf1 = new byte[PLAIN_TEXT.length]; outBuf2 = new byte[PLAIN_TEXT.length]; th.check(outBuf1 != null); th.check(outBuf2 != null); cipher = null; key = null; // create cipher for not supported algorithm/mode // -> NoSuchAlgorithmException should be thrown try { cipher = Cipher.getInstance(null); } catch (NoSuchAlgorithmException e) { noSuchAlg = true; } catch (NoSuchPaddingException e) { noSuchPad = true; } th.check(!noSuchPad); th.check(noSuchAlg); th.check(cipher == null); noSuchAlg = false; try { cipher = Cipher.getInstance(""); } catch (NoSuchAlgorithmException e) { noSuchAlg = true; } catch (NoSuchPaddingException e) { noSuchPad = true; } th.check(!noSuchPad); th.check(noSuchAlg); th.check(cipher == null); noSuchAlg = false; try { cipher = Cipher.getInstance("///"); } catch (NoSuchAlgorithmException e) { noSuchAlg = true; } catch (NoSuchPaddingException e) { noSuchPad = true; } th.check(!noSuchPad); th.check(noSuchAlg); th.check(cipher == null); noSuchAlg = false; try { cipher = Cipher.getInstance("a/b/c"); } catch (NoSuchAlgorithmException e) { noSuchAlg = true; } catch (NoSuchPaddingException e) { noSuchPad = true; } th.check(!noSuchPad); th.check(noSuchAlg); th.check(cipher == null); noSuchAlg = false; try { cipher = Cipher.getInstance("a/d/f/t/y"); } catch (NoSuchAlgorithmException e) { noSuchAlg = true; } catch (NoSuchPaddingException e) { noSuchPad = true; } th.check(!noSuchPad); th.check(noSuchAlg); th.check(cipher == null); noSuchAlg = false; try { cipher = Cipher.getInstance(ALGORITHM + "/zzz"); } catch (NoSuchAlgorithmException e) { noSuchAlg = true; } catch (NoSuchPaddingException e) { noSuchPad = true; } th.check(!noSuchPad); th.check(noSuchAlg); th.check(cipher == null); noSuchAlg = false; try { cipher = Cipher.getInstance(ALGORITHM + MODE + PADDING + "/xxx"); } catch (NoSuchAlgorithmException e) { noSuchAlg = true; } catch (NoSuchPaddingException e) { noSuchPad = true; } th.check(!noSuchPad); th.check(noSuchAlg); th.check(cipher == null); noSuchAlg = false; // create cipher with not supported padding // -> NoSuchPaddingException should be thrown try { cipher = Cipher.getInstance(ALGORITHM + MODE + "/yyy"); } catch (NoSuchAlgorithmException e) { noSuchAlg = true; } catch (NoSuchPaddingException e) { noSuchPad = true; } th.check(!noSuchAlg); th.check(noSuchPad); th.check(cipher == null); noSuchPad = false; // create cipher try { cipher = Cipher.getInstance(ALGORITHM + MODE + PADDING); } catch (NoSuchAlgorithmException e) { noSuchAlg = true; } catch (NoSuchPaddingException e) { noSuchPad = true; } th.check(!noSuchAlg); th.check(!noSuchPad); th.check(cipher != null); // create key key = new SecretKeySpec(SECRET_KEY, 0, SECRET_KEY.length, ALGORITHM); th.check(key != null); th.check(ALGORITHM.toUpperCase(), key.getAlgorithm().toUpperCase()); th.check(cmpArr(SECRET_KEY, key.getEncoded())); // update() before init() -> IllegalStateException should be thrown try { outLen = cipher.update(PLAIN_TEXT, 0, PLAIN_TEXT.length, outBuf1, 0); } catch (IllegalStateException e) { illState = true; } catch (ShortBufferException e) { shortBuf = true; } th.check(!shortBuf); th.check(illState); illState = false; // doFinal() before init() -> IllegalStateException should be thrown try { outLen = cipher.doFinal(PLAIN_TEXT, 0, PLAIN_TEXT.length, outBuf2, 0); } catch (IllegalStateException e) { illState = true; } catch (ShortBufferException e) { shortBuf = true; } catch (IllegalBlockSizeException e) { illBlSize = true; } catch (BadPaddingException e) { badPad = true; } th.check(!shortBuf); th.check(!illBlSize); th.check(!badPad); th.check(illState); illState = false; // init cipher for encryption try { cipher.init(Cipher.ENCRYPT_MODE, key); } catch (InvalidKeyException e) { invKey = true; } th.check(!invKey); // encrypt using update() try { outLen = cipher.update(PLAIN_TEXT, 0, PLAIN_TEXT.length, outBuf1, 0); } catch (IllegalStateException e) { illState = true; } catch (ShortBufferException e) { shortBuf = true; } th.check(!shortBuf); th.check(!illState); th.check(PLAIN_TEXT.length, outLen); // encrypt using doFinal() try { outLen = cipher.doFinal(PLAIN_TEXT, 0, PLAIN_TEXT.length, outBuf2, 0); } catch (IllegalStateException e) { illState = true; } catch (ShortBufferException e) { shortBuf = true; } catch (IllegalBlockSizeException e) { illBlSize = true; } catch (BadPaddingException e) { badPad = true; } th.check(!shortBuf); th.check(!illBlSize); th.check(!badPad); th.check(!illState); th.check(PLAIN_TEXT.length, outLen); // check encryption results th.check(cmpArr(CIPHER_TEXT_PART_1, outBuf1)); th.check(cmpArr(CIPHER_TEXT_PART_2, outBuf2)); // init cipher for decryption try { cipher.init(Cipher.DECRYPT_MODE, key); } catch (InvalidKeyException e) { invKey = true; } th.check(!invKey); // decrypt using update() try { outLen = cipher.update(CIPHER_TEXT_PART_1, 0, CIPHER_TEXT_PART_1.length, outBuf1, 0); } catch (IllegalStateException e) { illState = true; } catch (ShortBufferException e) { shortBuf = true; } th.check(!shortBuf); th.check(!illState); th.check(PLAIN_TEXT.length, outLen); // decrypt using doFinal() try { outLen = cipher.doFinal(CIPHER_TEXT_PART_2, 0, CIPHER_TEXT_PART_2.length, outBuf2, 0); } catch (IllegalStateException e) { illState = true; } catch (ShortBufferException e) { shortBuf = true; } catch (IllegalBlockSizeException e) { illBlSize = true; } catch (BadPaddingException e) { badPad = true; } th.check(!shortBuf); th.check(!illBlSize); th.check(!badPad); th.check(!illState); th.check(PLAIN_TEXT.length, outLen); // check decryption results th.check(cmpArr(PLAIN_TEXT, outBuf1)); th.check(cmpArr(PLAIN_TEXT, outBuf2)); // incorrect outBuf size -> ShortBufferException should be thrown try { outLen = cipher.update(PLAIN_TEXT, 0, PLAIN_TEXT.length, outBuf1, 1); } catch (IllegalStateException e) { illState = true; } catch (ShortBufferException e) { shortBuf = true; } th.check(!illState); th.check(shortBuf); shortBuf = false; try { outLen = cipher.doFinal(PLAIN_TEXT, 0, PLAIN_TEXT.length, outBuf2, 1); } catch (IllegalStateException e) { illState = true; } catch (ShortBufferException e) { shortBuf = true; } catch (IllegalBlockSizeException e) { illBlSize = true; } catch (BadPaddingException e) { badPad = true; } th.check(!illState); th.check(!illBlSize); th.check(!badPad); th.check(shortBuf); shortBuf = false; } /** * Run tests. */ public void test(TestHarness th) { try { testOne(th); } catch (Throwable t) { th.fail("" + t); } } /** * Compare two byte arrays. */ private boolean cmpArr(byte[] one, byte[] two) { if (one.length != two.length) { return false; } for (int i = 0; i < one.length; i++) { if (one[i] != two[i]) { return false; } } return true; } }