Package org.syncany.tests.crypto

Source Code of org.syncany.tests.crypto.CipherUtilTest

/*
* Syncany, www.syncany.org
* Copyright (C) 2011-2014 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.crypto;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.RandomAccessFile;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.crypto.spec.SecretKeySpec;

import org.junit.Test;
import org.syncany.config.Logging;
import org.syncany.crypto.CipherException;
import org.syncany.crypto.CipherSpec;
import org.syncany.crypto.CipherSpecs;
import org.syncany.crypto.CipherUtil;
import org.syncany.crypto.MultiCipherOutputStream;
import org.syncany.crypto.SaltedSecretKey;
import org.syncany.tests.util.TestFileUtil;
import org.syncany.util.StringUtil;

public class CipherUtilTest {
  private static final Logger logger = Logger.getLogger(CipherUtilTest.class.getSimpleName());
   
  static {
    Logging.init();
  }
   
  @Test
  public void testCreateDerivedKeys() throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException {
    SaltedSecretKey masterKey = createDummyMasterKey();   
    CipherSpec cipherSpec = CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM);
   
    byte[] derivedKeySalt1 = new byte[] { 1, 2, 3 };
    byte[] derivedKeySalt2 = new byte[] { 1, 2, 3, 4 };

    SaltedSecretKey derivedKey1 = CipherUtil.createDerivedKey(masterKey, derivedKeySalt1, cipherSpec);
    SaltedSecretKey derivedKey2 = CipherUtil.createDerivedKey(masterKey, derivedKeySalt2, cipherSpec);
   
    logger.log(Level.INFO, "- Derived key 1: "+StringUtil.toHex(derivedKey1.getEncoded()));
    logger.log(Level.INFO, "      with salt: "+StringUtil.toHex(derivedKey1.getSalt()));
    logger.log(Level.INFO, "- Derived key 2: "+StringUtil.toHex(derivedKey2.getEncoded()));
    logger.log(Level.INFO, "      with salt: "+StringUtil.toHex(derivedKey2.getSalt()));
   
    assertEquals(128/8, derivedKey1.getEncoded().length);
    assertEquals(128/8, derivedKey2.getEncoded().length);
    assertFalse(Arrays.equals(derivedKey1.getSalt(), derivedKey2.getSalt()));
    assertFalse(Arrays.equals(derivedKey1.getEncoded(), derivedKey2.getEncoded()));       
  }
 
  @Test
  public void testCreateRandomArray() throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException {
    byte[] randomArray1 = CipherUtil.createRandomArray(10);
    byte[] randomArray2 = CipherUtil.createRandomArray(10);
   
    assertEquals(10, randomArray1.length);
    assertEquals(10, randomArray2.length);
    assertFalse(Arrays.equals(randomArray1, randomArray2));
  }
 
  @Test
  public void testIsEncryptedFileFalse() throws Exception {
    File tempDirectory = TestFileUtil.createTempDirectoryInSystemTemp();
    File testFile = new File(tempDirectory+"/somefile");
   
    TestFileUtil.writeToFile(new byte[] { 12, 3 }, testFile);
    assertFalse(CipherUtil.isEncrypted(testFile));
   
    TestFileUtil.deleteDirectory(tempDirectory);
  }
 
  @Test
  public void testIsEncryptedFileTrue() throws Exception {
    File tempDirectory = TestFileUtil.createTempDirectoryInSystemTemp();
    File testFile = new File(tempDirectory+"/somefile");
   
    RandomAccessFile testFileRaf = new RandomAccessFile(testFile, "rw");
   
    testFileRaf.write(MultiCipherOutputStream.STREAM_MAGIC);
    testFileRaf.write(MultiCipherOutputStream.STREAM_VERSION);
    testFileRaf.close();
   
    assertTrue(CipherUtil.isEncrypted(testFile));
   
    TestFileUtil.deleteDirectory(tempDirectory);
  }
 
  @Test
  public void testEncryptShortArrayAes128Gcm() throws Exception {
    testEncrypt(
      new byte[] { 123, 4 },
      Arrays.asList(new CipherSpec[] { CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM) })
    );   
  }
 
  @Test
  public void testEncryptLongArrayAes128Gcm() throws Exception {
    testEncrypt(
      TestFileUtil.createRandomArray(1024*1024),
      Arrays.asList(new CipherSpec[] { CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM) })
    );       
 
 
  @Test
  public void testEncryptShortArrayAes128Twofish128() throws Exception {
    testEncrypt(
      new byte[] { 123, 4 },
      Arrays.asList(new CipherSpec[] {
        CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM),
        CipherSpecs.getCipherSpec(CipherSpecs.TWOFISH_128_GCM)
      })
    );   
  }
 
  @Test
  public void testEncryptLongArrayAes128Twofish128() throws Exception {
    testEncrypt(
      TestFileUtil.createRandomArray(1024*1024),
      Arrays.asList(new CipherSpec[] {
        CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM),
        CipherSpecs.getCipherSpec(CipherSpecs.TWOFISH_128_GCM)
      })
    );   
  }
 
  @Test
  public void testEncryptLongArrayAes258Twofish256UnlimitedStrength() throws Exception {
    testEncrypt(
      TestFileUtil.createRandomArray(1024*1024),
      Arrays.asList(new CipherSpec[] {
        CipherSpecs.getCipherSpec(CipherSpecs.AES_256_GCM),
        CipherSpecs.getCipherSpec(CipherSpecs.TWOFISH_256_GCM)
      })
    );   
 
 
  private void testEncrypt(byte[] originalData, List<CipherSpec> cipherSpecs) throws CipherException {
    SaltedSecretKey masterKey = createDummyMasterKey();
   
    byte[] ciphertext = CipherUtil.encrypt(
      new ByteArrayInputStream(originalData),
      cipherSpecs,
      masterKey
    );
   
    byte[] plaintext = CipherUtil.decrypt(new ByteArrayInputStream(ciphertext), masterKey);
   
    assertFalse(Arrays.equals(originalData, ciphertext));
    assertTrue(Arrays.equals(originalData, plaintext))
  }
 
  @Test(expected = Exception.class)
  public void testIntegrityHeaderMagic() throws Exception {
    SaltedSecretKey masterKey = createDummyMasterKey();
   
    byte[] originalPlaintext = TestFileUtil.createRandomArray(50);
   
    byte[] ciphertext = CipherUtil.encrypt(
      new ByteArrayInputStream(originalPlaintext),
      Arrays.asList(CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM)),
      masterKey
    );
   
    // Alter header MAGIC BYTES
    ciphertext[0] = 0x12;
    ciphertext[1] = 0x34;
   
    byte[] plaintext = CipherUtil.decrypt(new ByteArrayInputStream(ciphertext), masterKey);
   
    System.out.println(StringUtil.toHex(originalPlaintext));
    System.out.println(StringUtil.toHex(plaintext));
   
    fail("TEST FAILED: Ciphertext was altered without exception.");
 
 
  @Test(expected = Exception.class)
  public void testIntegrityHeaderVersion() throws Exception {
    SaltedSecretKey masterKey = createDummyMasterKey();
   
    byte[] originalPlaintext = TestFileUtil.createRandomArray(50);
   
    byte[] ciphertext = CipherUtil.encrypt(
      new ByteArrayInputStream(originalPlaintext),
      Arrays.asList(CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM)),
      masterKey
    );
   
    // Alter header VERSION
    ciphertext[4] = (byte) 0xff;
   
    byte[] plaintext = CipherUtil.decrypt(new ByteArrayInputStream(ciphertext), masterKey);
   
    System.out.println(StringUtil.toHex(originalPlaintext));
    System.out.println(StringUtil.toHex(plaintext));
   
    fail("TEST FAILED: Ciphertext was altered without exception.");
 
 
  @Test(expected = Exception.class)
  public void testIntegrityHeaderCipherSpecId() throws Exception {
    SaltedSecretKey masterKey = createDummyMasterKey();
   
    byte[] originalPlaintext = TestFileUtil.createRandomArray(50);
   
    byte[] ciphertext = CipherUtil.encrypt(
      new ByteArrayInputStream(originalPlaintext),
      Arrays.asList(CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM)),
      masterKey
    );
   
    assertEquals(CipherSpecs.AES_128_GCM, ciphertext[18]); // If this fails, fix test!

    // Alter header CIPHER SPEC ID    
    ciphertext[18] = (byte) 0xff;
   
    byte[] plaintext = CipherUtil.decrypt(new ByteArrayInputStream(ciphertext), masterKey);
   
    System.out.println(StringUtil.toHex(originalPlaintext));
    System.out.println(StringUtil.toHex(plaintext));
   
    fail("TEST FAILED: Ciphertext was altered without exception.");
 
 
  @Test(expected = Exception.class)
  public void testIntegrityHeaderCipherSalt() throws Exception {
    SaltedSecretKey masterKey = createDummyMasterKey();
    
    byte[] originalPlaintext = TestFileUtil.createRandomArray(50);
   
    byte[] ciphertext = CipherUtil.encrypt(
      new ByteArrayInputStream(originalPlaintext),
      Arrays.asList(CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM)),
      masterKey
    );
   
    // Alter header CIPHER SALT    
    ciphertext[19] = (byte) 0xff;
    ciphertext[20] = (byte) 0xff;
    ciphertext[21] = (byte) 0xff;
   
    byte[] plaintext = CipherUtil.decrypt(new ByteArrayInputStream(ciphertext), masterKey);
   
    System.out.println(StringUtil.toHex(originalPlaintext));
    System.out.println(StringUtil.toHex(plaintext));
   
    fail("TEST FAILED: Ciphertext was altered without exception.");
 
 
  @Test(expected = Exception.class)
  public void testIntegrityHeaderCipherIV() throws Exception {
    SaltedSecretKey masterKey = createDummyMasterKey();
   
    byte[] originalPlaintext = TestFileUtil.createRandomArray(50);
   
    byte[] ciphertext = CipherUtil.encrypt(
      new ByteArrayInputStream(originalPlaintext),
      Arrays.asList(CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM)),
      masterKey
    );
   
    // Alter header CIPHER SALT    
    ciphertext[32] = (byte) 0xff;
    ciphertext[33] = (byte) 0xff;
    ciphertext[34] = (byte) 0xff;
   
    byte[] plaintext = CipherUtil.decrypt(new ByteArrayInputStream(ciphertext), masterKey);
   
    System.out.println(StringUtil.toHex(originalPlaintext));
    System.out.println(StringUtil.toHex(plaintext));
   
    fail("TEST FAILED: Ciphertext was altered without exception.");
 
 
  @Test(expected = CipherException.class)
  public void testIntegrityAesGcmCiphertext() throws Exception {
    SaltedSecretKey masterKey = createDummyMasterKey();
   
    byte[] originalPlaintext = TestFileUtil.createRandomArray(50);
   
    byte[] ciphertext = CipherUtil.encrypt(
      new ByteArrayInputStream(originalPlaintext),
      Arrays.asList(CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM)),
      masterKey
    );
   
    // Alter ciphertext (after header!); ciphertext starts after 75 bytes
    ciphertext[80] = (byte) (ciphertext[80] ^ 0x01);
    ciphertext[81] = (byte) (ciphertext[81] ^ 0x02);
    ciphertext[82] = (byte) (ciphertext[82] ^ 0x03);
   
    CipherUtil.decrypt(new ByteArrayInputStream(ciphertext), masterKey);
   
    fail("TEST FAILED: Ciphertext was altered without exception.");
 
 
  @Test(expected = Exception.class)
  public void testIntegrityTwofishGcmCiphertext() throws Exception {
    SaltedSecretKey masterKey = createDummyMasterKey();
   
    byte[] originalPlaintext = TestFileUtil.createRandomArray(50);
   
    byte[] ciphertext = CipherUtil.encrypt(
      new ByteArrayInputStream(originalPlaintext),
      Arrays.asList(CipherSpecs.getCipherSpec(CipherSpecs.TWOFISH_128_GCM)),
      masterKey
    );
   
    // Alter ciphertext (after header!); ciphertext starts after 75 bytes
    ciphertext[80] = (byte) (ciphertext[80] ^ 0x01);
   
    byte[] plaintext = CipherUtil.decrypt(new ByteArrayInputStream(ciphertext), masterKey);
   
    System.out.println(StringUtil.toHex(originalPlaintext));
    System.out.println(StringUtil.toHex(plaintext));
   
    fail("TEST FAILED: Ciphertext was altered without exception.");
 

  private SaltedSecretKey createDummyMasterKey() {
    return new SaltedSecretKey(
      new SecretKeySpec(
        StringUtil.fromHex("44fda24d53b29828b62c362529bd9df5c8a92c2736bcae3a28b3d7b44488e36e246106aa5334813028abb2048eeb5e177df1c702d93cf82aeb7b6d59a8534ff0"),
        "AnyAlgorithm"
      ),
      StringUtil.fromHex("157599349e0f1bc713afff442db9d4c3201324073d51cb33407600f305500aa3fdb31136cb1f37bd51a48f183844257d42010a36133b32b424dd02bc63b349bc")     
    );
 
}
TOP

Related Classes of org.syncany.tests.crypto.CipherUtilTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.