blob: 313f665f0757868801411f7c11fb7630660d7083 [file] [log] [blame]
package org.bouncycastle.jce.provider.test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.security.Key;
import java.security.SecureRandom;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
/**
* basic test class for key generation for a DES-EDE block cipher, basically
* this just exercises the provider, and makes sure we are behaving sensibly,
* correctness of the implementation is shown in the lightweight test classes.
*/
public class DESedeTest
extends SimpleTest
{
static String[] cipherTests1 =
{
"112",
"2f4bc6b30c893fa549d82c560d61cf3eb088aed020603de249d82c560d61cf3e529e95ecd8e05394",
"128",
"2f4bc6b30c893fa549d82c560d61cf3eb088aed020603de249d82c560d61cf3e529e95ecd8e05394",
"168",
"50ddb583a25c21e6c9233f8e57a86d40bb034af421c03096c9233f8e57a86d402fce91e8eb639f89",
"192",
"50ddb583a25c21e6c9233f8e57a86d40bb034af421c03096c9233f8e57a86d402fce91e8eb639f89",
};
static byte[] input1 = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f");
/**
* a fake random number generator - we just want to make sure the random numbers
* aren't random so that we get the same output, while still getting to test the
* key generation facilities.
*/
private class FixedSecureRandom
extends SecureRandom
{
byte[] seed = {
(byte)0xaa, (byte)0xfd, (byte)0x12, (byte)0xf6, (byte)0x59,
(byte)0xca, (byte)0xe6, (byte)0x34, (byte)0x89, (byte)0xb4,
(byte)0x79, (byte)0xe5, (byte)0x07, (byte)0x6d, (byte)0xde,
(byte)0xc2, (byte)0xf0, (byte)0x6c, (byte)0xb5, (byte)0x8f
};
public void nextBytes(
byte[] bytes)
{
int offset = 0;
while ((offset + seed.length) < bytes.length)
{
System.arraycopy(seed, 0, bytes, offset, seed.length);
offset += seed.length;
}
System.arraycopy(seed, 0, bytes, offset, bytes.length - offset);
}
}
public String getName()
{
return "DESEDE";
}
private boolean equalArray(
byte[] a,
byte[] b)
{
if (a.length != b.length)
{
return false;
}
for (int i = 0; i != a.length; i++)
{
if (a[i] != b[i])
{
return false;
}
}
return true;
}
private boolean equalArray(
byte[] a,
byte[] b,
int length)
{
if (a.length < length)
{
return false;
}
if (b.length < length)
{
return false;
}
for (int i = 0; i != length; i++)
{
if (a[i] != b[i])
{
return false;
}
}
return true;
}
private void wrapTest(
String alg,
int id,
byte[] kek,
byte[] iv,
byte[] in,
byte[] out)
{
try
{
Cipher wrapper = Cipher.getInstance(alg + "Wrap", "BC");
wrapper.init(Cipher.WRAP_MODE, new SecretKeySpec(kek, alg), new IvParameterSpec(iv));
try
{
byte[] cText = wrapper.wrap(new SecretKeySpec(in, alg));
if (!equalArray(cText, out))
{
fail("failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText)));
}
}
catch (Exception e)
{
fail("failed wrap test exception " + e.toString());
}
wrapper.init(Cipher.UNWRAP_MODE, new SecretKeySpec(kek, alg));
try
{
Key pText = wrapper.unwrap(out, alg, Cipher.SECRET_KEY);
if (!equalArray(pText.getEncoded(), in))
{
fail("failed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText.getEncoded())));
}
}
catch (Exception e)
{
fail("failed unwrap test exception " + e.toString());
}
}
catch (Exception ex)
{
fail("failed exception " + ex.toString());
}
}
public void test(
String alg,
int strength,
byte[] input,
byte[] output)
{
Key key = null;
KeyGenerator keyGen;
SecureRandom rand;
Cipher in = null;
Cipher out = null;
CipherInputStream cIn;
CipherOutputStream cOut;
ByteArrayInputStream bIn;
ByteArrayOutputStream bOut;
rand = new FixedSecureRandom();
try
{
keyGen = KeyGenerator.getInstance(alg, "BC");
keyGen.init(strength, rand);
key = keyGen.generateKey();
in = Cipher.getInstance(alg + "/ECB/PKCS7Padding", "BC");
out = Cipher.getInstance(alg + "/ECB/PKCS7Padding", "BC");
out.init(Cipher.ENCRYPT_MODE, key, rand);
}
catch (Exception e)
{
fail(alg + " failed initialisation - " + e.toString());
}
try
{
in.init(Cipher.DECRYPT_MODE, key);
}
catch (Exception e)
{
fail(alg + " failed initialisation - " + e.toString());
}
//
// encryption pass
//
bOut = new ByteArrayOutputStream();
cOut = new CipherOutputStream(bOut, out);
try
{
for (int i = 0; i != input.length / 2; i++)
{
cOut.write(input[i]);
}
cOut.write(input, input.length / 2, input.length - input.length / 2);
cOut.close();
}
catch (IOException e)
{
fail(alg + " failed encryption - " + e.toString());
}
byte[] bytes;
bytes = bOut.toByteArray();
if (!equalArray(bytes, output))
{
fail(alg + " failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes)));
}
//
// decryption pass
//
bIn = new ByteArrayInputStream(bytes);
cIn = new CipherInputStream(bIn, in);
try
{
DataInputStream dIn = new DataInputStream(cIn);
bytes = new byte[input.length];
for (int i = 0; i != input.length / 2; i++)
{
bytes[i] = (byte)dIn.read();
}
dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2);
}
catch (Exception e)
{
fail(alg + " failed encryption - " + e.toString());
}
if (!equalArray(bytes, input))
{
fail(alg + " failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes)));
}
//
// keyspec test
//
try
{
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(alg, "BC");
DESedeKeySpec keySpec = (DESedeKeySpec)keyFactory.getKeySpec((SecretKey)key, DESedeKeySpec.class);
if (!equalArray(key.getEncoded(), keySpec.getKey(), 16))
{
fail(alg + " KeySpec does not match key.");
}
}
catch (Exception e)
{
fail(alg + " failed keyspec - " + e.toString());
}
}
public void performTest()
{
for (int i = 0; i != cipherTests1.length; i += 2)
{
test("DESEDE", Integer.parseInt(cipherTests1[i]), input1, Hex.decode(cipherTests1[i + 1]));
}
for (int i = 0; i != cipherTests1.length; i += 2)
{
test("TDEA", Integer.parseInt(cipherTests1[i]), input1, Hex.decode(cipherTests1[i + 1]));
}
byte[] kek1 = Hex.decode("255e0d1c07b646dfb3134cc843ba8aa71f025b7c0838251f");
byte[] iv1 = Hex.decode("5dd4cbfc96f5453b");
byte[] in1 = Hex.decode("2923bf85e06dd6ae529149f1f1bae9eab3a7da3d860d3e98");
byte[] out1 = Hex.decode("690107618ef092b3b48ca1796b234ae9fa33ebb4159604037db5d6a84eb3aac2768c632775a467d4");
wrapTest("DESEDE", 1, kek1, iv1, in1, out1);
wrapTest("TDEA", 1, kek1, iv1, in1, out1);
}
public static void main(
String[] args)
{
Security.addProvider(new BouncyCastleProvider());
runTest(new DESedeTest());
}
}