/*
 * Syncany, www.syncany.org
 * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com> 
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.syncany.tests.unit.crypto;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;

import javax.crypto.spec.SecretKeySpec;

import org.junit.Test;
import org.syncany.config.Logging;
import org.syncany.crypto.CipherSession;
import org.syncany.crypto.CipherSpec;
import org.syncany.crypto.CipherSpecs;
import org.syncany.crypto.CipherUtil;
import org.syncany.crypto.SaltedSecretKey;
import org.syncany.util.StringUtil;

public class CipherSessionTest {
	static {
		Logging.init();
	}
	
	@Test
	public void testCipherSessionWriteKeyReuseCountOfTwo() throws Exception {
		SaltedSecretKey masterKey = createDummyMasterKey();		
		CipherSession cipherSession = new CipherSession(masterKey, 999, 2);
		
		CipherSpec cipherSpecAes128 = CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM);
		CipherSpec cipherSpecTwofish128 = CipherSpecs.getCipherSpec(CipherSpecs.TWOFISH_128_GCM);
		
		SaltedSecretKey writeSecretKey1Aes128 = cipherSession.getWriteSecretKey(cipherSpecAes128);
		SaltedSecretKey writeSecretKey2Aes128 = cipherSession.getWriteSecretKey(cipherSpecAes128);
		SaltedSecretKey writeSecretKey3Aes128 = cipherSession.getWriteSecretKey(cipherSpecAes128);
		
		SaltedSecretKey writeSecretKey1Twofish128 = cipherSession.getWriteSecretKey(cipherSpecTwofish128);
		SaltedSecretKey writeSecretKey2Twofish128 = cipherSession.getWriteSecretKey(cipherSpecTwofish128);
		SaltedSecretKey writeSecretKey3Twofish128 = cipherSession.getWriteSecretKey(cipherSpecTwofish128);
				
		assertEquals(writeSecretKey1Aes128, writeSecretKey2Aes128);
		assertNotSame(writeSecretKey1Aes128, writeSecretKey3Aes128);
		
		assertEquals(writeSecretKey1Twofish128, writeSecretKey2Twofish128);
		assertNotSame(writeSecretKey1Twofish128, writeSecretKey3Twofish128);
		
		assertNotSame(writeSecretKey1Aes128, writeSecretKey1Twofish128);
	}	
	
	@Test
	public void testCipherSessionReadKeyCacheSizeOfThree() throws Exception {
		SaltedSecretKey masterKey = createDummyMasterKey();		
		CipherSession cipherSession = new CipherSession(masterKey, 2, 999);
		
		CipherSpec cipherSpecAes128 = CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM);
		
		byte[] readKeySalt1 = CipherUtil.createRandomArray(cipherSpecAes128.getKeySize());
		byte[] readKeySalt2 = CipherUtil.createRandomArray(cipherSpecAes128.getKeySize());
		byte[] readKeySalt3 = CipherUtil.createRandomArray(cipherSpecAes128.getKeySize());				
		
		SaltedSecretKey readSecretKey1Aes128 = cipherSession.getReadSecretKey(cipherSpecAes128, readKeySalt1);
		SaltedSecretKey readSecretKey2Aes128 = cipherSession.getReadSecretKey(cipherSpecAes128, readKeySalt2);
		SaltedSecretKey readSecretKey3Aes128 = cipherSession.getReadSecretKey(cipherSpecAes128, readKeySalt3);
		
		assertNotSame(readSecretKey1Aes128, readSecretKey2Aes128);
		assertNotSame(readSecretKey1Aes128, readSecretKey3Aes128);
		assertNotSame(readSecretKey2Aes128, readSecretKey3Aes128);
		
		// TODO [medium] This does NOT TEST the actual read cache. How to test this. The cache is completely hidden/private?!
	}	
	
	private SaltedSecretKey createDummyMasterKey() {
		return new SaltedSecretKey(
			new SecretKeySpec(
				StringUtil.fromHex("44fda24d53b29828b62c362529bd9df5c8a92c2736bcae3a28b3d7b44488e36e246106aa5334813028abb2048eeb5e177df1c702d93cf82aeb7b6d59a8534ff0"),
				"AnyAlgorithm"
			),
			StringUtil.fromHex("157599349e0f1bc713afff442db9d4c3201324073d51cb33407600f305500aa3fdb31136cb1f37bd51a48f183844257d42010a36133b32b424dd02bc63b349bc")			
		);
	}	
}
