/*
* Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code 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 code 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 in the LICENSE file that
* accompanied this code).
*
* 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4979126
* @summary Ensure update()/doFinal() matches javadoc description
* when ShortBufferException is thrown.
* @author Valerie Peng
*/
import java.util.Arrays;
import java.security.*;
import java.security.spec.*;
import java.math.BigInteger;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.Provider;
import com.sun.crypto.provider.*;
public class TestShortBuffer {
private static final String ALGO = "AES";
private static final String[] MODES = {
"ECB", "CBC", "PCBC", "CFB16", "OFB8"
};
private static final SecretKey KEY =
new SecretKeySpec(new byte[16], ALGO);
private static byte[] SHORTBUFFER = new byte[1];
private static final byte[] PLAINTEXT = new byte[30];
static {
PLAINTEXT[0] = (byte)0x15;
};
private Cipher ci = null;
private byte[] in = null;
private byte[] expected = null;
private byte[] out = null;
private int outOffset = 0;
private TestShortBuffer(Cipher ci) {
this.ci = ci;
}
private void init(byte[] in, byte[] expected) {
this.in = (byte[]) in.clone();
this.expected = (byte[]) expected.clone();
this.out = new byte[expected.length];
this.outOffset = 0;
}
private static void runTest() throws Exception {
// Initialization
for (int i = 0; i < MODES.length; i++) {
System.out.println("===== TESTING MODE " + MODES[i] + " =====");
Cipher ci = Cipher.getInstance(ALGO+"/"+MODES[i]+"/PKCS5Padding",
"SunJCE");
TestShortBuffer test = null;
int stored = 0;
AlgorithmParameters params = null;
byte[] cipherText = null;
byte[] shortBuffer = new byte[8];
for (int k = 0; k < 2; k++) {
byte[] expected = null;
switch (k) {
case 0: // Encryption
System.out.println("Testing with Cipher.ENCRYPT_MODE");
ci.init(Cipher.ENCRYPT_MODE, KEY);
cipherText = ci.doFinal(PLAINTEXT);
test = new TestShortBuffer(ci);
test.init(PLAINTEXT, cipherText);
params = ci.getParameters();
break;
case 1: // Decryption
System.out.println("Testing with Cipher.DECRYPT_MODE");
ci.init(Cipher.DECRYPT_MODE, KEY, params);
test = new TestShortBuffer(ci);
test.init(cipherText, PLAINTEXT);
break;
}
int offset = 2 + i*5;
test.testUpdate();
test.testUpdateWithUpdate(offset);
test.testDoFinal();
test.testDoFinalWithUpdate(offset);
}
}
}
private void checkOutput() throws Exception {
if (!Arrays.equals(out, expected)) {
System.out.println("got: " + new BigInteger(out));
System.out.println("expect: " + new BigInteger(expected));
throw new Exception("Generated different outputs");
}
}
private void testUpdate() throws Exception {
outOffset = 0;
int stored = 0;
try {
stored = ci.update(in, 0, in.length, SHORTBUFFER);
throw new Exception("Should throw ShortBufferException!");
} catch (ShortBufferException sbe) {
System.out.println("Expected SBE thrown....");
// retry with a large-enough buffer according to javadoc
stored = ci.update(in, 0, in.length, out);
stored = ci.doFinal(out, outOffset += stored);
if (out.length != (stored + outOffset)) {
throw new Exception("Wrong number of output bytes");
}
}
checkOutput();
}
private void testUpdateWithUpdate(int offset) throws Exception {
outOffset = 0;
int stored = 0;
byte[] out1 = ci.update(in, 0, offset);
if (out1 != null) {
System.arraycopy(out1, 0, out, 0, out1.length);
outOffset += out1.length;
}
try {
stored = ci.update(in, offset, in.length-offset, SHORTBUFFER);
throw new Exception("Should throw ShortBufferException!");
} catch (ShortBufferException sbe) {
System.out.println("Expected SBE thrown....");
// retry with a large-enough buffer according to javadoc
stored = ci.update(in, offset, in.length-offset,
out, outOffset);
stored = ci.doFinal(out, outOffset+=stored);
if (out.length != (stored + outOffset)) {
throw new Exception("Wrong number of output bytes");
}
}
checkOutput();
}
private void testDoFinal() throws Exception {
outOffset = 0;
int stored = 0;
try {
stored = ci.doFinal(in, 0, in.length, SHORTBUFFER);
throw new Exception("Should throw ShortBufferException!");
} catch (ShortBufferException sbe) {
System.out.println("Expected SBE thrown....");
// retry with a large-enough buffer according to javadoc
stored = ci.doFinal(in, 0, in.length, out, 0);
if (out.length != stored) {
throw new Exception("Wrong number of output bytes");
}
}
checkOutput();
}
private void testDoFinalWithUpdate(int offset) throws Exception {
outOffset = 0;
int stored = 0;
byte[] out1 = ci.update(in, 0, offset);
if (out1 != null) {
System.arraycopy(out1, 0, out, 0, out1.length);
outOffset += out1.length;
}
try {
stored = ci.doFinal(in, offset, in.length-offset, SHORTBUFFER);
throw new Exception("Should throw ShortBufferException!");
} catch (ShortBufferException sbe) {
System.out.println("Expected SBE thrown....");
// retry with a large-enough buffer according to javadoc
stored = ci.doFinal(in, offset, in.length-offset,
out, outOffset);
if (out.length != (stored + outOffset)) {
throw new Exception("Wrong number of output bytes");
}
}
checkOutput();
}
public static void main(String[] argv) throws Exception {
runTest();
System.out.println("Test Passed");
}
}