/* * * Panbox - encryption for cloud storage * Copyright (C) 2014-2015 by Fraunhofer SIT and Sirrix AG * * 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/>. * * Additonally, third party code may be provided with notices and open source * licenses from communities and third parties that govern the use of those * portions, and any licenses granted hereunder do not alter any rights and * obligations you may have under such open source licenses, however, the * disclaimer of warranty and limitation of liability provisions of the GPLv3 * will apply to all the product. * */ package org.panbox.core.keymgmt; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.SignatureException; import java.util.Collection; import java.util.LinkedList; import java.util.Map; import java.util.TreeMap; import javax.crypto.SecretKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.panbox.core.crypto.CryptCore; import org.panbox.core.crypto.SignatureHelper; import org.panbox.core.exception.SerializationException; import org.panbox.core.exception.ShareMetaDataException; import org.panbox.core.exception.SymmetricKeyDecryptionException; import org.panbox.core.exception.SymmetricKeyEncryptionException; import org.panbox.core.keymgmt.VolumeParams.VolumeParamsFactory; public class TestInitVolume { static PrivateKey mKey_sig; static PublicKey mKey_sig_pub; static PrivateKey mKey_enc; static PublicKey mKey_enc_pub; static PublicKey devKey1_enc; static PrivateKey devKey1_enc_priv; static PublicKey devKey2_enc; static PrivateKey devKey2_enc_priv; Map<String, PublicKey> dkList; IVolume volume; @Rule public TemporaryFolder folder = new TemporaryFolder(); private String dbName = null; private static String alias = "Owner"; private static String deviceAlias = "Dev1"; private static String deviceAlias2 = "Dev2"; @BeforeClass public static void setUpClass() { try { KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA", new BouncyCastleProvider()); SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); gen.initialize(1024, random); KeyPair pair = gen.generateKeyPair(); mKey_sig = pair.getPrivate(); mKey_sig_pub = pair.getPublic(); gen.generateKeyPair(); mKey_enc = pair.getPrivate(); mKey_enc_pub = pair.getPublic(); pair = gen.generateKeyPair(); devKey1_enc_priv = pair.getPrivate(); devKey1_enc = pair.getPublic(); pair = gen.generateKeyPair(); devKey2_enc_priv = pair.getPrivate(); devKey2_enc = pair.getPublic(); } catch (NoSuchAlgorithmException e) { fail(e.getMessage()); } } @Before public void setUp() throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException { File newFolder = folder.newFolder(".metadata"); System.out.println("Create temporary folder: " + newFolder.mkdirs()); dbName = newFolder.getAbsolutePath(); File db = new File(dbName + File.separator + Volume.DB_FILE); if (db.exists()) db.delete(); volume = new Volume(dbName); dkList = new TreeMap<String, PublicKey>(); } @After public void tearDown() { volume = null; dkList = null; File db = new File(dbName + Volume.DB_FILE); if (db.exists()) db.delete(); } @SuppressWarnings("unchecked") @Test public void testNewAPI() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { VolumeParamsFactory pf = VolumeParamsFactory.getFactory(); assertNotNull(volume); ShareMetaData smd = null; Volume volume2 = null; ShareMetaData smd2 = null; try { VolumeParams p = pf.createVolumeParams().setOwnerAlias(alias) .setPublicSignatureKey(mKey_sig_pub) .setPrivateSignatureKey(mKey_sig) .setPublicEncryptionKey(mKey_enc_pub) .setPrivateEncryptionKey(mKey_enc) .setDeviceAlias(deviceAlias) .setPublicDeviceKey(devKey1_enc); smd = volume.createShareMetaData(p); assertNotNull(smd); } catch (Exception e) { e.printStackTrace(); fail(e.getMessage()); } try { ObfuscationKeyDB okdb = smd.obfuscationKeys; Field f = ObfuscationKeyDB.class .getDeclaredField("obfuscationKeys"); f.setAccessible(true); int size = ((TreeMap<PublicKey, byte[]>) f.get(okdb)).size(); assertEquals(2, size); } catch (Exception e) { fail(e.getMessage()); } try { volume2 = new Volume(dbName); smd2 = volume2.loadShareMetaData(mKey_sig_pub); assertNotNull(smd2); } catch (Exception e) { fail(e.getMessage()); } assertEquals(smd, smd2); try { volume.addDevice(alias, mKey_sig_pub, mKey_sig, deviceAlias2, devKey2_enc, mKey_enc_pub, mKey_enc); } catch (ShareMetaDataException e) { fail(e.getMessage()); } try { ObfuscationKeyDB okdb = smd.obfuscationKeys; Field f = ObfuscationKeyDB.class .getDeclaredField("obfuscationKeys"); f.setAccessible(true); int size = ((TreeMap<PublicKey, byte[]>) f.get(okdb)).size(); assertEquals(3, size); } catch (Exception e) { fail(e.getMessage()); } // try { // volume.removeDevice(alias, mKey_sig_pub, mKey_sig, deviceAlias); // } catch (Exception e) { // fail(e.getMessage()); // } // // try { // ObfuscationKeyDB okdb = smd.obfuscationKeys; // Field f = ObfuscationKeyDB.class // .getDeclaredField("obfuscationKeys"); // f.setAccessible(true); // int size = ((TreeMap<PublicKey, byte[]>) f.get(okdb)).size(); // assertEquals(2, size); // } catch (Exception e) { // fail(e.getMessage()); // } // // try { // volume.removeDevice(alias, mKey_sig_pub, mKey_sig, deviceAlias); // } catch (Exception e) { // fail(e.getMessage()); // } // // try { // ObfuscationKeyDB okdb = smd.obfuscationKeys; // Field f = ObfuscationKeyDB.class // .getDeclaredField("obfuscationKeys"); // f.setAccessible(true); // int size = ((TreeMap<PublicKey, byte[]>) f.get(okdb)).size(); // assertEquals(2, size); // } catch (Exception e) { // fail(e.getMessage()); // } // // try { // volume.removeDevice(alias, mKey_sig_pub, mKey_sig, deviceAlias2); // } catch (Exception e) { // fail(e.getMessage()); // } // // try { // ObfuscationKeyDB okdb = smd.obfuscationKeys; // Field f = ObfuscationKeyDB.class // .getDeclaredField("obfuscationKeys"); // f.setAccessible(true); // int size = ((TreeMap<PublicKey, byte[]>) f.get(okdb)).size(); // assertEquals(1, size); // } catch (Exception e) { // fail(e.getMessage()); // } // // try { // volume.addDevice(alias, mKey_sig_pub, mKey_sig, deviceAlias2, // devKey2_enc, mKey_enc_pub, mKey_enc); // } catch (ShareMetaDataException e) { // fail(e.getMessage()); // } // // try { // ObfuscationKeyDB okdb = smd.obfuscationKeys; // Field f = ObfuscationKeyDB.class // .getDeclaredField("obfuscationKeys"); // f.setAccessible(true); // int size = ((TreeMap<PublicKey, byte[]>) f.get(okdb)).size(); // assertEquals(2, size); // } catch (Exception e) { // fail(e.getMessage()); // } } @Test public void obfuscationKeys() throws SymmetricKeyEncryptionException, SymmetricKeyDecryptionException { ObfuscationKeyDB ok = new ObfuscationKeyDB(); assertTrue(ok.isEmpty()); SecretKey key = CryptCore.generateSymmetricKey(); byte[] encKey = CryptCore.encryptSymmetricKey(key.getEncoded(), devKey1_enc); assertArrayEquals(key.getEncoded(), CryptCore.decryptSymmertricKey(encKey, devKey1_enc_priv) .getEncoded()); ok.add(devKey1_enc, encKey); assertFalse(ok.isEmpty()); assertNull(ok.get(devKey2_enc)); byte[] fromOK = ok.get(devKey1_enc); assertNotNull(fromOK); assertArrayEquals(encKey, fromOK); SecretKey decryptSymmertricKey = CryptCore.decryptSymmertricKey(fromOK, devKey1_enc_priv); assertArrayEquals(key.getEncoded(), decryptSymmertricKey.getEncoded()); assertFalse(ok.isEmpty()); ok.add(devKey2_enc, CryptCore.encryptSymmetricKey( decryptSymmertricKey.getEncoded(), devKey2_enc)); byte[] encSK2 = ok.get(devKey2_enc); assertNotNull(encSK2); assertArrayEquals(key.getEncoded(), CryptCore.decryptSymmertricKey(encSK2, devKey2_enc_priv) .getEncoded()); assertFalse(ok.isEmpty()); ok.remove(devKey1_enc); assertNull(ok.get(devKey1_enc)); assertNotNull(ok.get(devKey2_enc)); assertFalse(ok.isEmpty()); ok.remove(devKey2_enc); assertNull(ok.get(devKey1_enc)); assertNull(ok.get(devKey2_enc)); assertTrue(ok.isEmpty()); } @Test public void test() throws SymmetricKeyDecryptionException, SymmetricKeyEncryptionException { // Precondition: // Owner has pw-protected MasterKeystore containig MKey_sig and MKey_enc // Owner hat lesser protected DeviceKeystore containing at least one // DeviceKey DevKey_1_enc // Create Empty SharePartList assertNotNull(volume); // ShareMetaData shareMetaData = volume.createShareMetaData(alias, // mKey_sig_pub, mKey_sig, deviceAlias, devKey1_enc); ShareMetaData shareMetaData = null; try { shareMetaData = new ShareMetaData(new JDBCHelperNonRevokeable( "jdbc:sqlite:" + dbName + File.separator), mKey_sig_pub); } catch (Exception e) { e.printStackTrace(); fail(e.getMessage()); } try { Field smdField = Volume.class.getDeclaredField("shareMetaData"); smdField.setAccessible(true); smdField.set(volume, shareMetaData); } catch (Exception e) { fail(e.getMessage()); } assertNotNull(shareMetaData); SharePartList spl = shareMetaData.initSharePartList(); assertEquals("SharePartList is not empty, although it should be", 0, spl.size()); // Sign SharePartList try { spl.sign(mKey_sig); assertTrue(CryptCore.verifySignature(spl, spl.getSignature(), mKey_sig_pub)); } catch (SignatureException e2) { fail(e2.getMessage()); } spl.add(mKey_sig_pub, alias); assertEquals("SharePartList is not empty, although it should be", 1, spl.size()); try { spl.sign(mKey_sig); assertTrue(CryptCore.verifySignature(spl, spl.getSignature(), mKey_sig_pub)); } catch (SignatureException e2) { fail(e2.getMessage()); } // get DevKeys for the Devices that the owner wants to enable for this // Volume // Put keys in dkList dkList.put(deviceAlias, devKey1_enc); assertEquals("DeviceKeyList should have 1 element", 1, dkList.size()); // Create and sign devicelist DeviceList dl = shareMetaData.createDeviceList(mKey_sig_pub, dkList); assertEquals("ShareMetaData should have 1 DeviceList", 1, shareMetaData .getDeviceLists().values().size()); // Create symmetric ShareKey SecretKey sk = CryptCore.generateSymmetricKey(); assertNotNull(sk); // Encrypt sk for all deviceLists Collection<DeviceList> deviceLists = shareMetaData.getDeviceLists() .values(); Collection<PublicKey> pubKeys = new LinkedList<PublicKey>(); for (DeviceList devList : deviceLists) { pubKeys.addAll(devList.getPublicKeys()); } assertEquals(1, pubKeys.size()); // fetch ShareKeyDB ShareKeyDB db = shareMetaData.getShareKeys(); assertNotNull(db); // add Encrypted Keys to db try { db.add(sk, pubKeys); } catch (SymmetricKeyEncryptionException e1) { fail(e1.getMessage()); } assertEquals(1, db.size()); try { db.sign(mKey_sig, alias); } catch (SignatureException e1) { fail(e1.getMessage()); } // Encrypt skOb for all deviceLists shareMetaData.addObfuscationKey(devKey1_enc, null, null); System.out.println("Making ShareMetaData persistent..."); try { dl.sign(mKey_sig, shareMetaData.shareKeys, shareMetaData.obfuscationKeys); assertTrue(SignatureHelper.verify(dl.getSignature(), mKey_sig_pub, dl, shareMetaData.shareKeys.get(dl.getPublicKeys()), shareMetaData.obfuscationKeys.get(dl.getPublicKeys()))); } catch (SignatureException | InvalidKeyException | NoSuchAlgorithmException | SerializationException e2) { fail(e2.getMessage()); } // make sharemetadata persistent try { shareMetaData.persist(); shareMetaData.persist(dl); } catch (Exception e) { fail(e.getMessage()); } System.out.println("Loading Volume..."); // load volume with sharemetadata try { Volume loadedVol = new Volume(dbName); ShareMetaData loadedSMD = loadedVol.loadShareMetaData(mKey_sig_pub); assertArrayEquals(shareMetaData.getSignature(), loadedSMD.getSignature()); System.out.println("DONE"); } catch (Exception e) { e.printStackTrace(System.err); fail(e.getMessage()); } } }