/*
 * Copyright (c) 2010 SURFnet bv
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*****************************************************************************
 DESTests.cpp

 Contains test cases to test the DES implementation
 *****************************************************************************/

#include <stdlib.h>
#include <cppunit/extensions/HelperMacros.h>
#include "DESTests.h"
#include "CryptoFactory.h"
#include "DESKey.h"
#include <stdio.h>

CPPUNIT_TEST_SUITE_REGISTRATION(DESTests);

void DESTests::setUp()
{
	des = NULL;

	des = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::DES);

	// Check the return value
	CPPUNIT_ASSERT(des != NULL);
}

void DESTests::tearDown()
{
	if (des != NULL)
	{
		CryptoFactory::i()->recycleSymmetricAlgorithm(des);
	}

	fflush(stdout);
}

void DESTests::testBlockSize()
{
	CPPUNIT_ASSERT(des->getBlockSize() == 8);
}

void DESTests::testCBC()
{
#ifndef WITH_FIPS
	char testKeys56[][17] =
	{
		"0000000000000000",
		"0102030405060708",
		"4041424344454647",
		"4698436794236871",
		"0940278947239572"
	};

	char testKeys112[][33] =
	{
		"00000000000000000000000000000000",
		"0102030405060708090A0B0C0D0E0F10",
		"404142434445464748494A4B4C4D4E4F",
		"64398647034486943598534703463870",
		"87406984068406984607412103517413"
	};
#endif

	char testKeys168[][49] =
	{
		"000000000000000000000000000000000000000000000000",
		"0102030405060708090A0B0C0D0E0F101112131415161718",
		"404142434445464748494A4B4C4D4E4F5051525354555657",
		"643906874509874309687459084769847562436043696747",
		"430135460496813044639085714376487549490586439575"
	};

	char testData[][256] =
	{
		"4938673409687134684698438657403986439058740935874395813968496846",
		"549813644389670948567490687546098245665626527788",
		"64398769586792586795867965624526",
		"468376458463264536"
	};

	char testResult[5][4][3][256] = {
		{
			{
				"ACC8B1BE444EEA9E016A46EF600E9B3FB2C87DE8CE9BE5394917AABB0A04639A3BFF1E250FE971D7",
				"ACC8B1BE444EEA9E016A46EF600E9B3FB2C87DE8CE9BE5394917AABB0A04639A3BFF1E250FE971D7",
				"ACC8B1BE444EEA9E016A46EF600E9B3FB2C87DE8CE9BE5394917AABB0A04639A3BFF1E250FE971D7"
			},
			{
				"F9A1913AA27A05379506BE00D5F7398F67722076A3439E759BA729A58E8FEE64",
				"F9A1913AA27A05379506BE00D5F7398F67722076A3439E759BA729A58E8FEE64",
				"F9A1913AA27A05379506BE00D5F7398F67722076A3439E759BA729A58E8FEE64"
			},
			{
				"36FD5581BB31F3E27910895DC2F2599CD0F8B8F002220588",
				"36FD5581BB31F3E27910895DC2F2599CD0F8B8F002220588",
				"36FD5581BB31F3E27910895DC2F2599CD0F8B8F002220588"
			},
			{
				"B81DA29972385E55CB453A17B6D88D22",
				"B81DA29972385E55CB453A17B6D88D22",
				"B81DA29972385E55CB453A17B6D88D22"
			}
		},
		{
			{
				"EE16FFE3CC4D4589766FA0957FB728A75D44A00D9BEBE2D43C4D4F3A5AFDB49730CFD4DF46D3AEF6",
				"A070EE9DED89EE198E0E9B3CEB4879BB0244AB7FCD3450ED044BB5EE0AC8F7797383FDB8AAEF77B8",
				"E7C594590C9CA00B376B702CE3B92C3F699B3EEEB2CEA08FA551350C837BF031FCAF4E1E97450327"
			},
			{
				"D4142C47C700069F3E71EA6B1EF301B9B97261543ED75B32242C05A253B077B8",
				"102BBE7D93CD0EF66280D3FA1F2A3976FB9C4D1B155D19E4985ADB86015DDE8C",
				"600C3A75AC6EB4C4609BA6B7ED273ED56E59CD49FC911C33DD8DFCA384BAA462"
			},
			{
				"47452120CD84CC32FC72F3B8600E5C43EEE192A29BC6BCB7",
				"ADCF4292A32E51A7843CC8590E6934083A2CC847082FF2B4",
				"D0FA596AC00BDA870999FD3FA2494C3C8B40B261EB3066F6"
			},
			{
				"6BD20CDBE6E6ECAD6ED829FB43E92751",
				"AE4379E371E295F63423F861B59111F0",
				"2757FC58EDEEB8499EA9B49AB2729BAD"
			}
		},
		{
			{
				"298621D5237F6230067DE7871DDBA6991E85CA14AD661D21357240923604D23A6A4119277B75B331",
				"2C9F4FC0ACE7C8A4847472A0D5DDD42F36D3B2C46144B5A0ECDBB59806472E6257952DFD4DB9EBE5",
				"679A832C630207E76BC1FF8371C61CA2518E37FE97EDED1B171E3E11807250145736949368AC822B"
			},
			{
				"80FFD37B545675BB8C7CD317A73AB48CC0A39D3D9C11474EC3FD1220A066C034",
				"F9228036718792EE86A85626AB1BC05E17F9CE21FF5D1723D0442CE852F004C3",
				"D5F5F1EA7D8C2038FEDCBEDF157A5D2469A941FEC696D74DB8359CA5AECDD4CE"
			},
			{
				"1ABB1CC10F589D993030A978B1B7F44AD52FFFEBF23638CA",
				"D2423F54FA4978C95E4B13EF4DD6AA82DFD772F0FDAF5AD1",
				"8128EC49D71F5711E5304E7C4423C63AD0EFC45453B66583"
			},
			{
				"B9EE976AB97396047510C1DEA5C86A4B",
				"46BA1930042146B31BD8FAF3AE6F3414",
				"46EF3BCCA73E33C03D81BFE0DFFA7ABD"
			}
		},
		{
			{
				"30D1B2556D516F20C2FD117FE0355845FBB0B11ABE5922A7EAA19C3A48E30207218321B3F0F30A6D",
				"CBFA560297901DD691CDFDF98675BD7FF3A64FDCC0EF02F29C81105D3ECAC4E2803E2279F4476B35",
				"4A30EC10433BE3695DC2B064E6240419C7BF81F1EE7640D5E2FFFA106666A2CEBF18DB954A992B5E"
			},
			{
				"61FFB2E5A73170603E48F9823E6DF7105C9A909CC2F5CEDBEA7E60C076355B37",
				"8408BD722B12031D17A1645AA59B05E2A50F7002B19877D6EB1C9BB7107C523F",
				"97EF5791017B10CF07FB8144C19633522CBBE55DC63EF608F8734EE6484C0B0E"
			},
			{
				"7205DC463B3D5EC858C8E7A13844A1A8FF21C0D615CA56AF",
				"D5D08C1DC728A47CD55A2ACBB811294962022E745F4BCDF4",
				"7761189D73039A3F06BDDF00B308D7A43BE7BEA1CE9D042E"
			},
			{
				"1702428661BA4CFE686CFDEDFFAA6A27",
				"9218A89B0A7AEC7E6E2AF1CA493B2829",
				"6EEB9F7DDF66CED3DB74F7E8DE0CB2CD"
			}
		},
		{
			{
				"4FD3A4C759827F6E188E542B83A858026C17FD1DEF21477A964D122B62EE55FA9DB3CCF05A768C83",
				"F2C8B52652970805EE60ECECC8369C98443463F1C3A5A6357DFDFEE6B7F1EF0CF05523B5469E4555",
				"21FCBDC92C07F112D19742F5100F2A995E27CB282D73DF5CFEC802C629A279BD4E498C98D170003E"
			},
			{
				"3FD4C32A44DC0A9605A5A793C57E94826E80FC9E8E9620BBC2E02FE41A62A2D3",
				"4FC88F1E88C3B5A76CF6BE5FA8205BA6F7FA201F7C40E8F0F9CA156E140A4EC5",
				"CCE31260C967F4B9BB3D2D31F82320715E434C1313D911C58CE7E42AA78DA831"
			},
			{
				"714766BE5CB60DA99DC0BD4E7E655ADE7F26E45F372EF1BF",
				"00064542E2B4821B4E9173DA6FD1ABAE45C5E5CF26DB506D",
				"4D88D531C20E63A39372F275329BDBEBE15E7D2C32F2A98F"
			},
			{
				"4933917C9B56124914D2B76DE221BA13",
				"7F2D1CA9D942630FE1E954E4176E84A5",
				"9A46902F3997F0EB121981DAEC6D89C4"
			}
		}
	};

	char testIV[][33] =
	{
		"0000000000000000",
		"0102030405060708",
		"4041424344454647",
		"4693867334098764",
		"6209876098547207"
	};

	for (int i = 0; i < 5; i++)
	{
#ifndef WITH_FIPS
		ByteString keyData56(testKeys56[i]);
		CPPUNIT_ASSERT(keyData56.size() == 8);
		ByteString keyData112(testKeys112[i]);
		CPPUNIT_ASSERT(keyData112.size() == 16);
#endif
		ByteString keyData168(testKeys168[i]);
		CPPUNIT_ASSERT(keyData168.size() == 24);

#ifndef WITH_FIPS
		DESKey desKey56(56);
		CPPUNIT_ASSERT(desKey56.setKeyBits(keyData56));
		DESKey desKey112(112);
		CPPUNIT_ASSERT(desKey112.setKeyBits(keyData112));
#endif
		DESKey desKey168(168);
		CPPUNIT_ASSERT(desKey168.setKeyBits(keyData168));

		ByteString IV(testIV[i]);

		for (int j = 0; j < 4; j++)
		{
			ByteString plainText(testData[j]), shsmPlainText;
			ByteString cipherText;
			ByteString shsmCipherText, OB;

#ifndef WITH_FIPS
			// Test 56-bit key
			cipherText = ByteString(testResult[i][j][0]);

			// Now, do the same thing using our DES implementation
			shsmCipherText.wipe();
			CPPUNIT_ASSERT(des->encryptInit(&desKey56, SymMode::CBC, IV));

			CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(des->encryptFinal(OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(shsmCipherText == cipherText);

			// Check that we can get the plain text
			shsmPlainText.wipe();
			CPPUNIT_ASSERT(des->decryptInit(&desKey56, SymMode::CBC, IV));

			CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(des->decryptFinal(OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(shsmPlainText == plainText);

			// Test 112-bit key
			cipherText = ByteString(testResult[i][j][1]);

			// Now, do the same thing using our DES implementation
			shsmCipherText.wipe();
			CPPUNIT_ASSERT(des->encryptInit(&desKey112, SymMode::CBC, IV));

			CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(des->encryptFinal(OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(shsmCipherText == cipherText);

			// Check that we can get the plain text
			shsmPlainText.wipe();
			CPPUNIT_ASSERT(des->decryptInit(&desKey112, SymMode::CBC, IV));

			CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(des->decryptFinal(OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(shsmPlainText == plainText);
#endif

			// Test 168-bit key
			cipherText = ByteString(testResult[i][j][2]);

			// Now, do the same thing using our DES implementation
			shsmCipherText.wipe();
			CPPUNIT_ASSERT(des->encryptInit(&desKey168, SymMode::CBC, IV));

			CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(des->encryptFinal(OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(shsmCipherText == cipherText);

			// Check that we can get the plain text
			shsmPlainText.wipe();
			CPPUNIT_ASSERT(des->decryptInit(&desKey168, SymMode::CBC, IV));

			CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(des->decryptFinal(OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(shsmPlainText == plainText);
		}
	}
}

void DESTests::testECB()
{
#ifndef WITH_FIPS
	char testKeys56[][17] =
	{
		"0000000000000000",
		"0102030405060708",
		"4041424344454647",
		"4698436794236871",
		"0940278947239572"
	};

	char testKeys112[][33] =
	{
		"00000000000000000000000000000000",
		"0102030405060708090A0B0C0D0E0F10",
		"404142434445464748494A4B4C4D4E4F",
		"64398647034486943598534703463870",
		"87406984068406984607412103517413"
	};
#endif

	char testKeys168[][49] =
	{
		"000000000000000000000000000000000000000000000000",
		"0102030405060708090A0B0C0D0E0F101112131415161718",
		"404142434445464748494A4B4C4D4E4F5051525354555657",
		"643906874509874309687459084769847562436043696747",
		"430135460496813044639085714376487549490586439575"
	};

	char testData[][256] =
	{
		"4938673409687134684698438657403986439058740935874395813968496846",
		"549813644389670948567490687546098245665626527788",
		"64398769586792586795867965624526",
		"468376458463264536"
	};

	char testResult[5][4][3][256] = {
		{
			{
				"ACC8B1BE444EEA9E44404B8595B7667982F1BDF99F419F083249964334F2B15F7E422822773666C0",
				"ACC8B1BE444EEA9E44404B8595B7667982F1BDF99F419F083249964334F2B15F7E422822773666C0",
				"ACC8B1BE444EEA9E44404B8595B7667982F1BDF99F419F083249964334F2B15F7E422822773666C0"
			},
			{
				"F9A1913AA27A0537CA0BB1A6417C4037978BC92CEFCD10BB7E422822773666C0",
				"F9A1913AA27A0537CA0BB1A6417C4037978BC92CEFCD10BB7E422822773666C0",
				"F9A1913AA27A0537CA0BB1A6417C4037978BC92CEFCD10BB7E422822773666C0"
			},
			{
				"36FD5581BB31F3E2ADA81678B64A0F3C7E422822773666C0",
				"36FD5581BB31F3E2ADA81678B64A0F3C7E422822773666C0",
				"36FD5581BB31F3E2ADA81678B64A0F3C7E422822773666C0"
			},
			{
				"B81DA29972385E55EA1F3677CDC02D27",
				"B81DA29972385E55EA1F3677CDC02D27",
				"B81DA29972385E55EA1F3677CDC02D27"
			}
		},
		{
			{
				"278B2CA6259C30E180CCB62E69F0841F235507E2FB3404FC2BC223E37E32B3A78207EA5D3E19A5FD",
				"417579E3ABEF6F0D620B4FF88E2220457466420803140BFEFBA062A2A41D7C15061019377C6BFD8A",
				"A676D0404F0F105B2073B9DD19C8C434428098BFC5AF1292FE12477340395F118F45B5BE23F16C4E"
			},
			{
				"7D004390E5638E54077E2551B01BD52BFA1B98403ECE1AEF8207EA5D3E19A5FD",
				"391B84593FEA836450318A6E943F1C3A4A6BD74E5001EB7A061019377C6BFD8A",
				"DEAF58111ECCCB449F0C2564B52E360E4AACC8672ABBDF1A8F45B5BE23F16C4E"
			},
			{
				"A6947F9EF4159BAE636A70B904059BC38207EA5D3E19A5FD",
				"14ADFE212E27BF7F409395B45577F2C8061019377C6BFD8A",
				"FF87BF761FC159F4442B3B4593233BC48F45B5BE23F16C4E"
			},
			{
				"3A1777DAAAC85389EE0B499A90AE1739",
				"376E61DF2EAFE5B523964A03885AD085",
				"E4D81EE64FE8FB187EB7B5E80E075C73"
			}
		},
		{
			{
				"F105809DF621715F4D3492E1EEC4A7DE0775A0632ECC13429DF0DC695A60882FA47F93E855A1445B",
				"77C85215179312315997B4D0E997DB413176C80A8ED9F5EB9B726200224CE97C20A8A19F543BCCBD",
				"AF1477E32B5BB1CA46D26B6020B3B48DB0A90A97B1BA60F032ADA648296EC92DEE924AA617423FD1"
			},
			{
				"0FB3C3D9D93E0025F87909CD351D0116C0F684A204015E2CA47F93E855A1445B",
				"67A66DB3209C406D2FE31AF6C36D24C7B32D0F8F1EAFA90020A8A19F543BCCBD",
				"F85B1F07D788C59CD3DE6D562A175725DF596847ADEA8764EE924AA617423FD1"
			},
			{
				"243A34CD70CE3819B9510980B6EFF3EAA47F93E855A1445B",
				"997E145467B88D9D4C923797F539AC1620A8A19F543BCCBD",
				"836788D7AD1F879B405438775FFD6D76EE924AA617423FD1"
			},
			{
				"70856D6B67EE353F27EBB96462DACE63",
				"D02F2A92C175A58001D89C4AEC476384",
				"4ED379A40187826CAA90D2D6A05D5A9B"
			}
		},
		{
			{
				"C79F67ABCE6F741CF6D5B7B4870397779AEB89F48805DD1A28305E804A4A2B91114E1CF0C7FA91DA",
				"42956EA3B9415E8FE75B667A7C6B1ADF64D08E53C38DE733A776A97C7A8FC27E32945078552FA3E2",
				"3685365AD0F07609E13CCDE69CEDC8CCA0C37262A87B734286B9119643AC3BABE435BDA25919BE86"
			},
			{
				"09B882774309CC2B117586F5FA8BF7E4A5DA2A65E137665B114E1CF0C7FA91DA",
				"0E52A9ABE753758D3C4F6326A8F689282D1DAB8AF6FC8CFF32945078552FA3E2",
				"8DB6B9D50B5B8CE7DA56546CFF36C16BA3159E0EB7BD649AE435BDA25919BE86"
			},
			{
				"025F9704F6ACD844BCFC6EBA809CD871114E1CF0C7FA91DA",
				"1692C6A1DF9192C6D4125991EA9A9CBE32945078552FA3E2",
				"6B848E67225EDDCCD7E8EC89ACDAA0AFE435BDA25919BE86"
			},
			{
				"9D01CD89916AEE48AFE528A376E07AE9",
				"6FA6A689405048060D65E1B1240B76B7",
				"7EADEB7073D2EA995C5ED613C978817F"
			}
		},
		{
			{
				"A98D0E8E72C589D80D240F192CF65C30FF3A1AB9D8CE54B09AA249C72E395AC3B40F19A649C1B237",
				"33AC43C7A936665859431D18C089EE45F1356C34F5DF462D81BBFA42380A7E4F6732A473091A3673",
				"FD4F2F77CCE20147CD0932B2E2D8D5978523F6A03D59E31E1F678A5DA4C350132E94F199555C371E"
			},
			{
				"39453F3BF3C0CAE54279D96F4592359A5AEE6DD04D5F6162B40F19A649C1B237",
				"E2AFCEEFF2317C520D890D7F2CB91ACD99D5DCAEC9C409016732A473091A3673",
				"CB19BF88B2DEDDE981E048379A47BDF77ED5F815034CB07A2E94F199555C371E"
			},
			{
				"9D466BACFA69266F7CC26D2C8B8CD203B40F19A649C1B237",
				"265FDBCCF5F2325B3C8770ABEEECA4166732A473091A3673",
				"C61E9B86A8A663AE1566CFFCF2046D6B2E94F199555C371E"
			},
			{
				"380091B24160152B63EF067F6C189385",
				"548EB237B455CBA0100A5C52A6F28C2B",
				"066C3B0C5E6AF1E9BDD3DDAE5040F809"
			}
		}
	};

	char testIV[][33] =
	{
		"0000000000000000",
		"0102030405060708",
		"4041424344454647",
		"4693867334098764",
		"6209876098547207"
	};

	for (int i = 0; i < 5; i++)
	{
#ifndef WITH_FIPS
		ByteString keyData56(testKeys56[i]);
		CPPUNIT_ASSERT(keyData56.size() == 8);
		ByteString keyData112(testKeys112[i]);
		CPPUNIT_ASSERT(keyData112.size() == 16);
#endif
		ByteString keyData168(testKeys168[i]);
		CPPUNIT_ASSERT(keyData168.size() == 24);

#ifndef WITH_FIPS
		DESKey desKey56(56);
		CPPUNIT_ASSERT(desKey56.setKeyBits(keyData56));
		DESKey desKey112(112);
		CPPUNIT_ASSERT(desKey112.setKeyBits(keyData112));
#endif
		DESKey desKey168(168);
		CPPUNIT_ASSERT(desKey168.setKeyBits(keyData168));

		ByteString IV(testIV[i]);

		for (int j = 0; j < 4; j++)
		{
			ByteString plainText(testData[j]), shsmPlainText;
			ByteString cipherText;
			ByteString shsmCipherText, OB;

#ifndef WITH_FIPS
			// Test 56-bit key
			cipherText = ByteString(testResult[i][j][0]);

			// Now, do the same thing using our DES implementation
			shsmCipherText.wipe();
			CPPUNIT_ASSERT(des->encryptInit(&desKey56, SymMode::ECB, IV));

			CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(des->encryptFinal(OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(shsmCipherText == cipherText);

			// Check that we can get the plain text
			shsmPlainText.wipe();
			CPPUNIT_ASSERT(des->decryptInit(&desKey56, SymMode::ECB, IV));

			CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(des->decryptFinal(OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(shsmPlainText == plainText);

			// Test 112-bit key
			cipherText = ByteString(testResult[i][j][1]);

			// Now, do the same thing using our DES implementation
			shsmCipherText.wipe();
			CPPUNIT_ASSERT(des->encryptInit(&desKey112, SymMode::ECB, IV));

			CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(des->encryptFinal(OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(shsmCipherText == cipherText);

			// Check that we can get the plain text
			shsmPlainText.wipe();
			CPPUNIT_ASSERT(des->decryptInit(&desKey112, SymMode::ECB, IV));

			CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(des->decryptFinal(OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(shsmPlainText == plainText);
#endif

			// Test 168-bit key
			cipherText = ByteString(testResult[i][j][2]);

			// Now, do the same thing using our DES implementation
			shsmCipherText.wipe();
			CPPUNIT_ASSERT(des->encryptInit(&desKey168, SymMode::ECB, IV));

			CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(des->encryptFinal(OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(shsmCipherText == cipherText);

			// Check that we can get the plain text
			shsmPlainText.wipe();
			CPPUNIT_ASSERT(des->decryptInit(&desKey168, SymMode::ECB, IV));

			CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(des->decryptFinal(OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(shsmPlainText == plainText);
		}
	}
}

void DESTests::testOFB()
{
#ifndef WITH_FIPS
	char testKeys56[][17] =
	{
		"0000000000000000",
		"0102030405060708",
		"4041424344454647",
		"4698436794236871",
		"0940278947239572"
	};

	char testKeys112[][33] =
	{
		"00000000000000000000000000000000",
		"0102030405060708090A0B0C0D0E0F10",
		"404142434445464748494A4B4C4D4E4F",
		"64398647034486943598534703463870",
		"87406984068406984607412103517413"
	};
#endif

	char testKeys168[][49] =
	{
		"000000000000000000000000000000000000000000000000",
		"0102030405060708090A0B0C0D0E0F101112131415161718",
		"404142434445464748494A4B4C4D4E4F5051525354555657",
		"643906874509874309687459084769847562436043696747",
		"430135460496813044639085714376487549490586439575"
	};

	char testData[][256] =
	{
		"4938673409687134684698438657403986439058740935874395813968496846",
		"549813644389670948567490687546098245665626527788",
		"64398769586792586795867965624526",
		"468376458463264536"
	};

	char testResult[5][4][3][256] = {
		{
			{
				"C59E2ADDC8D9529368469843865740390AE5DDB1B5B816204395813968496846",
				"C59E2ADDC8D9529368469843865740390AE5DDB1B5B816204395813968496846",
				"C59E2ADDC8D9529368469843865740390AE5DDB1B5B816204395813968496846"
			},
			{
				"D83E5E8D823844AE48567490687546090EE32BBFE7E3542F",
				"D83E5E8D823844AE48567490687546090EE32BBFE7E3542F",
				"D83E5E8D823844AE48567490687546090EE32BBFE7E3542F"
			},
			{
				"E89FCA8099D6B1FF6795867965624526",
				"E89FCA8099D6B1FF6795867965624526",
				"E89FCA8099D6B1FF6795867965624526"
			},
			{
				"CA253BAC45D205E236",
				"CA253BAC45D205E236",
				"CA253BAC45D205E236"
			}
		},
		{
			{
				"3E9FB188FC11138D05109EA396CA48E1681DF27A857C3C4A9E92D3DC85A5F313",
				"3440BEFCF35DC87716D8440F71BAF9ACD0441E10B9E5B525F0584499620086E2",
				"DDB35281888DF064195C42D45E4E2571AD62113A228B5107D1AC849861C199C0"
			},
			{
				"233FC5D8B6F005B02500727078E84ED16C1B0474D7277E45",
				"29E0CAACB9BCDE4A36C8A8DC9F98FF9CD442E81EEBBEF72A",
				"C01326D1C26CE659394CAE07B06C2341A964E73470D01308"
			},
			{
				"139E51D5AD1EF0E10AC3809975FF4DFE",
				"19415EA1A2522B1B190B5A35928FFCB3",
				"F0B2B2DCD9821308168F5CEEBD7B206E"
			},
			{
				"3124A0F9711A44FC5B",
				"3BFBAF8D7E569F0648",
				"D20843F00586A71547"
			}
		},
		{
			{
				"E376288A10BD52CB7162ADA9A732D24B574B1E7CB4FF5C791FFEA2E481AD3049",
				"FD82CFAE85B8581FFCF489F467D94B1B4FAAAEDDE4EC531ABD30D7EA235896AA",
				"24D9411BA456571900244AEA3EA7159BAA96522B6F891606A8D9A559FE218A9B"
			},
			{
				"FED65CDA5A5C44F65172417A4910D47B534DE872E6A41E76",
				"E022BBFECF594E22DCE4652789FB4D2B4BAC58D3B6B71115",
				"3979354BEEB741242034A639D08513ABAE90A4253DD25409"
			},
			{
				"CE77C8D741B2B1A77EB1B3934407D754",
				"D0832FF3D4B7BB73F32797CE84EC4E04",
				"09D8A146F559B4750FF754D0DD921084"
			},
			{
				"ECCD39FB9DB605BA2F",
				"F239DEDF08B30F6EA2",
				"2B62506A295D00685E"
			}
		},
		{
			{
				"740A4786C73A7C6B52DAF270161895E13B4437C56B9837827C2FE237532F4C19",
				"581B63C58404AEBECFDFD51D74A79836C11514685B47F3B02A2419AF0AA8C625",
				"D5FCB196868673D136D480E0B6EFC33C589131D87A4AC004A6E0DE8ADC8DE611"
			},
			{
				"69AA33D68DDB6A5672CA1EA3F83A93D13F42C1CB39C3758D",
				"45BB1795CEE5B883EFCF39CE9A859E06C513E266091CB1BF",
				"C85CC5C6CC6765EC16C46C3358CDC50C5C97C7D62811820B"
			},
			{
				"590BA7DB96359F075D09EC4AF52D90FE",
				"751A8398D50B4DD2C00CCB2797929D29",
				"F8FD51CBD78990BD39079EDA55DAC623"
			},
			{
				"7BB156F74A312B1A0C",
				"57A072B4090FF9CF91",
				"DA47A0E70B8D24A068"
			}
		},
		{
			{
				"0855A84EAD2176C3F10B9DCFC8D1A379AF616FC5C5CD4E6D434353C52832F9F6",
				"A8420E97462B0215AAC1DB0835D4064C6A8B123327FC396C9520BEA70B59B412",
				"3461DEDF1B4893E16706900E1DDBE351E90C1300B9B01E8A518A01AD56E9AC8C"
			},
			{
				"15F5DC1EE7C060FED11B711C26F3A549AB6799CB97960C62",
				"B5E27AC70CCA14288AD137DBDBF6007C6E8DE43D75A77B63",
				"29C1AA8F51A985DC47167CDDF3F9E561ED0AE50EEBEB5C85"
			},
			{
				"25544813FC2E95AFFED883F52BE4A666",
				"8543EECA1724E179A512C532D6E10353",
				"19603E824A47708D68D58E34FEEEE64E"
			},
			{
				"07EEB93F202A21B2AF",
				"A7F91FE6CB205564F4",
				"3BDACFAE9643C49039"
			}
		}
	};

	char testIV[][33] =
	{
		"0000000000000000",
		"0102030405060708",
		"4041424344454647",
		"4693867334098764",
		"6209876098547207"
	};

	for (int i = 0; i < 5; i++)
	{
#ifndef WITH_FIPS
		ByteString keyData56(testKeys56[i]);
		CPPUNIT_ASSERT(keyData56.size() == 8);
		ByteString keyData112(testKeys112[i]);
		CPPUNIT_ASSERT(keyData112.size() == 16);
#endif
		ByteString keyData168(testKeys168[i]);
		CPPUNIT_ASSERT(keyData168.size() == 24);

#ifndef WITH_FIPS
		DESKey desKey56(56);
		CPPUNIT_ASSERT(desKey56.setKeyBits(keyData56));
		DESKey desKey112(112);
		CPPUNIT_ASSERT(desKey112.setKeyBits(keyData112));
#endif
		DESKey desKey168(168);
		CPPUNIT_ASSERT(desKey168.setKeyBits(keyData168));

		ByteString IV(testIV[i]);

		for (int j = 0; j < 4; j++)
		{
			ByteString plainText(testData[j]), shsmPlainText;
			ByteString cipherText;
			ByteString shsmCipherText, OB;

#ifndef WITH_FIPS
			// Test 56-bit key
			cipherText = ByteString(testResult[i][j][0]);

			// Now, do the same thing using our DES implementation
			shsmCipherText.wipe();
			CPPUNIT_ASSERT(des->encryptInit(&desKey56, SymMode::OFB, IV));

			CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(des->encryptFinal(OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(shsmCipherText == cipherText);

			// Check that we can get the plain text
			shsmPlainText.wipe();
			CPPUNIT_ASSERT(des->decryptInit(&desKey56, SymMode::OFB, IV));

			CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(des->decryptFinal(OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(shsmPlainText == plainText);

			// Test 112-bit key
			cipherText = ByteString(testResult[i][j][1]);

			// Now, do the same thing using our DES implementation
			shsmCipherText.wipe();
			CPPUNIT_ASSERT(des->encryptInit(&desKey112, SymMode::OFB, IV));

			CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(des->encryptFinal(OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(shsmCipherText == cipherText);

			// Check that we can get the plain text
			shsmPlainText.wipe();
			CPPUNIT_ASSERT(des->decryptInit(&desKey112, SymMode::OFB, IV));

			CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(des->decryptFinal(OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(shsmPlainText == plainText);
#endif

			// Test 168-bit key
			cipherText = ByteString(testResult[i][j][2]);

			// Now, do the same thing using our DES implementation
			shsmCipherText.wipe();
			CPPUNIT_ASSERT(des->encryptInit(&desKey168, SymMode::OFB, IV));

			CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(des->encryptFinal(OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(shsmCipherText == cipherText);

			// Check that we can get the plain text
			shsmPlainText.wipe();
			CPPUNIT_ASSERT(des->decryptInit(&desKey168, SymMode::OFB, IV));

			CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(des->decryptFinal(OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(shsmPlainText == plainText);
		}
	}
}

void DESTests::testCFB()
{
#ifndef WITH_FIPS
	char testKeys56[][17] =
	{
		"0000000000000000",
		"0102030405060708",
		"4041424344454647",
		"4698436794236871",
		"0940278947239572"
	};

	char testKeys112[][33] =
	{
		"00000000000000000000000000000000",
		"0102030405060708090A0B0C0D0E0F10",
		"404142434445464748494A4B4C4D4E4F",
		"64398647034486943598534703463870",
		"87406984068406984607412103517413"
	};
#endif

	char testKeys168[][49] =
	{
		"000000000000000000000000000000000000000000000000",
		"0102030405060708090A0B0C0D0E0F101112131415161718",
		"404142434445464748494A4B4C4D4E4F5051525354555657",
		"643906874509874309687459084769847562436043696747",
		"430135460496813044639085714376487549490586439575"
	};

	char testData[][256] =
	{
		"4938673409687134684698438657403986439058740935874395813968496846",
		"549813644389670948567490687546098245665626527788",
		"64398769586792586795867965624526",
		"468376458463264536"
	};

	char testResult[5][4][3][256] = {
		{
			{
				"C59E2ADDC8D95293F8ED346ADAF018111F0B6726349664FF9B02C46C2EC5B96F",
				"C59E2ADDC8D95293F8ED346ADAF018111F0B6726349664FF9B02C46C2EC5B96F",
				"C59E2ADDC8D95293F8ED346ADAF018111F0B6726349664FF9B02C46C2EC5B96F"
			},
			{
				"D83E5E8D823844AE748E369586FA76A2BFD1E668EC78D67B",
				"D83E5E8D823844AE748E369586FA76A2BFD1E668EC78D67B",
				"D83E5E8D823844AE748E369586FA76A2BFD1E668EC78D67B"
			},
			{
				"E89FCA8099D6B1FFB3A24C435B847A73",
				"E89FCA8099D6B1FFB3A24C435B847A73",
				"E89FCA8099D6B1FFB3A24C435B847A73"
			},
			{
				"CA253BAC45D205E270",
				"CA253BAC45D205E270",
				"CA253BAC45D205E270"
			}
		},
		{
			{
				"3E9FB188FC11138D49C438ABB98A3846671A4DB257AA62C7929CD55A43E46D88",
				"3440BEFCF35DC8773DD631A9C8CCF222009D45E301BBF6432A78E99416CE87D8",
				"DDB35281888DF06446772085E3DE849298B4BE0089979260DDC59FACB17AD0BE"
			},
			{
				"233FC5D8B6F005B0966FB313EA0DDFBECF19CBC937445A56",
				"29E0CAACB9BCDE4AB219A19AA77E2C9A407C98A18BD56FDF",
				"C01326D1C26CE6592FA4E9909D93A85BE005431046661C73"
			},
			{
				"139E51D5AD1EF0E1E74DD9919AE65DB6",
				"19415EA1A2522B1B5972F5DCBEEF4E01",
				"F0B2B2DCD9821308815ADB01F0A16B76"
			},
			{
				"3124A0F9711A44FC92",
				"3BFBAF8D7E569F06CF",
				"D20843F00586A715DB"
			}
		},
		{
			{
				"E376288A10BD52CB06B42B4582A425907D2DF490EC14B478507BCDE58CE95B02",
				"FD82CFAE85B8581F1409EB62D06A98E05C401607619DE1235822E2DEB74737E1",
				"24D9411BA4565719BE9FF1A4D91F23B3BF8980A706747077583C8EB84AF63745"
			},
			{
				"FED65CDA5A5C44F619325429C78F464D271807342B10F899",
				"E022BBFECF594E22ABC22FA25024B6FD8F61337CBD1F023D",
				"3979354BEEB741241F0D219B5521A488F870C849275FF8B9"
			},
			{
				"CE77C8D741B2B1A7E488B94EB32C96FD",
				"D0832FF3D4B7BB73AEC7646A3686ABCF",
				"09D8A146F559B475A6258D03BC6F8BD3"
			},
			{
				"ECCD39FB9DB605BAB2",
				"F239DEDF08B30F6EE4",
				"2B62506A295D00687E"
			}
		},
		{
			{
				"740A4786C73A7C6B435071A654DA8FCC75BA3299969E327A2ABC7024378CF3AA",
				"581B63C58404AEBE49FA5FA4032918813075279E836DFE9BAEDF37D9B21ABEE1",
				"D5FCB196868673D1FA9C8A67E6A2449354B292E1A76BA11C416A394116857B29"
			},
			{
				"69AA33D68DDB6A561FB6D6218FAC0E812514782FC6059E46",
				"45BB1795CEE5B883232EBCCB672FC9C4803C6B827825FE94",
				"C85CC5C6CC6765EC466B8F8AC8DFC91CB916F617873AF187"
			},
			{
				"590BA7DB96359F07DB2F2CE68748425C",
				"751A8398D50B4DD24E4681B6D0E880FC",
				"F8FD51CBD78990BD5D088ECA798DA0E6"
			},
			{
				"7BB156F74A312B1A8C",
				"57A072B4090FF9CF1B",
				"DA47A0E70B8D24A043"
			}
		},
		{
			{
				"0855A84EAD2176C3D2C3DE4FB868CA2C1B0DF550E187E29808C45594C070FBF4",
				"A8420E97462B02158D2CABD1574D072F8D83123CED9BA7CEDD7C2799E168F32D",
				"3461DEDF1B4893E182BE36017DEBC6669B15269DFA4435A31EB1A0CE6A845176"
			},
			{
				"15F5DC1EE7C060FEDC9B1B43A20588E7A073A300BEFC4CAD",
				"B5E27AC70CCA142857CB807226DC1EA9B31BE81C0FDCD3FB",
				"29C1AA8F51A985DC7E530E6EB7AEAC246F2ED097D09851CC"
			},
			{
				"25544813FC2E95AF817E0897D4E22ECD",
				"8543EECA1724E179543979F02103C150",
				"19603E824A47708D80E29D3A61BAE5EA"
			},
			{
				"07EEB93F202A21B250",
				"A7F91FE6CB205564F2",
				"3BDACFAE9643C49027"
			}
		}
	};
	char testIV[][33] =
	{
		"0000000000000000",
		"0102030405060708",
		"4041424344454647",
		"4693867334098764",
		"6209876098547207"
	};

	for (int i = 0; i < 5; i++)
	{
#ifndef WITH_FIPS
		ByteString keyData56(testKeys56[i]);
		CPPUNIT_ASSERT(keyData56.size() == 8);
		ByteString keyData112(testKeys112[i]);
		CPPUNIT_ASSERT(keyData112.size() == 16);
#endif
		ByteString keyData168(testKeys168[i]);
		CPPUNIT_ASSERT(keyData168.size() == 24);

#ifndef WITH_FIPS
		DESKey desKey56(56);
		CPPUNIT_ASSERT(desKey56.setKeyBits(keyData56));
		DESKey desKey112(112);
		CPPUNIT_ASSERT(desKey112.setKeyBits(keyData112));
#endif
		DESKey desKey168(168);
		CPPUNIT_ASSERT(desKey168.setKeyBits(keyData168));

		ByteString IV(testIV[i]);

		for (int j = 0; j < 4; j++)
		{
			ByteString plainText(testData[j]), shsmPlainText;
			ByteString cipherText;
			ByteString shsmCipherText, OB;

#ifndef WITH_FIPS
			// Test 56-bit key
			cipherText = ByteString(testResult[i][j][0]);

			// Now, do the same thing using our DES implementation
			shsmCipherText.wipe();
			CPPUNIT_ASSERT(des->encryptInit(&desKey56, SymMode::CFB, IV));

			CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(des->encryptFinal(OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(shsmCipherText == cipherText);

			// Check that we can get the plain text
			shsmPlainText.wipe();
			CPPUNIT_ASSERT(des->decryptInit(&desKey56, SymMode::CFB, IV));

			CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(des->decryptFinal(OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(shsmPlainText == plainText);

			// Test 112-bit key
			cipherText = ByteString(testResult[i][j][1]);

			// Now, do the same thing using our DES implementation
			shsmCipherText.wipe();
			CPPUNIT_ASSERT(des->encryptInit(&desKey112, SymMode::CFB, IV));

			CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(des->encryptFinal(OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(shsmCipherText == cipherText);

			// Check that we can get the plain text
			shsmPlainText.wipe();
			CPPUNIT_ASSERT(des->decryptInit(&desKey112, SymMode::CFB, IV));

			CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(des->decryptFinal(OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(shsmPlainText == plainText);
#endif

			// Test 168-bit key
			cipherText = ByteString(testResult[i][j][2]);

			// Now, do the same thing using our DES implementation
			shsmCipherText.wipe();
			CPPUNIT_ASSERT(des->encryptInit(&desKey168, SymMode::CFB, IV));

			CPPUNIT_ASSERT(des->encryptUpdate(plainText, OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(des->encryptFinal(OB));
			shsmCipherText += OB;

			CPPUNIT_ASSERT(shsmCipherText == cipherText);

			// Check that we can get the plain text
			shsmPlainText.wipe();
			CPPUNIT_ASSERT(des->decryptInit(&desKey168, SymMode::CFB, IV));

			CPPUNIT_ASSERT(des->decryptUpdate(shsmCipherText, OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(des->decryptFinal(OB));
			shsmPlainText += OB;

			CPPUNIT_ASSERT(shsmPlainText == plainText);
		}
	}
}
