TestCrypto.java

// 
// Lapetus Ltd Java Class.  Copyright (c) Lapetus Systems Ltd, 2009, 2010. 
// ----------------------------------------------------------------------- 
// This is the intellectual property of Lapetus Systems Ltd, Artemis, Greece. 
// -------------------------------------------------------------------------- 
// www.lapetus-ltd.com, www.lapetus.com.gr, www.lapetus.eu 
// ------------------------------------------------------- 
// $LastChangedRevision: 1168 $ 
// $LastChangedDate:: 2010-11-06 16:41:19#$ 
// ---------------------------------------- 
// 
 
 
import com.lapetus_ltd.api.TLptsMainJut; 
import com.lapetus_ltd.api.common.TLptsBytesUtil; 
import com.lapetus_ltd.api.common.TLptsCryptoUtil; 
import com.lapetus_ltd.api.common.TLptsFileUtil; 
import com.lapetus_ltd.api.common.logger.TLptsLog; 
import com.lapetus_ltd.api.common.logger.TLptsLogger; 
import junit.framework.TestCase; 
 
 
 
// ###################################################################################################### 
// ####    Test code for the JUT build process.  This code will stop the build process on ERROR      #### 
// ###################################################################################################### 
 
 
// Class Description : Test class for all capabilities of the Crypto Module. 
// 
// These tests include verification of the RSA and AES cipher types that are available in the crypto module. 
// The foreign RSA encryption capability, which is normally used for transporting data, is also tested. 
// 
// Due to the many tests run below, we have commented every function as to its aim and purpose. 
// 
 
 
public class TestCrypto extends TestCase 
{ 
  public static void main(String[] args) 
  { 
    TestCrypto test = new TestCrypto(); 
    test.runAllTests(false); 
  } 
 
  public void runAllTests(boolean isExit) 
  { 
    testRSADefault(); 
    testAESDefault(); 
    testRSADefaultDynamic(); 
    testAESDefaultDynamic(); 
    testRSAInstance(); 
    testAESInstance(); 
    testRSA2Files(); 
    testAES2File(); 
    testRSADefaultForeign(); 
    testCredentials(); 
    if (isExit) 
      System.exit(0); 
  } 
 
 
//  This is the simplest of tests, where we just check the default RSA for correct functionality. 
//  The RSA key pair (private and public) is 1024 bits by default and is stored in two files in the user home lapetus directory. 
 
   
  public void testRSADefault() 
  { 
    TLptsMainJut.init(); 
 
    System.out.println("\nTesting Default RSA Encryption..."); 
 
    byte[] data = generateDataToEncrypt(512); 
    byte[] encryptedData = TLptsCryptoUtil.defaultEncryptRSA(data); 
    byte[] decryptedData = TLptsCryptoUtil.defaultDecryptRSA(encryptedData); 
 
    System.out.println("Original Bytes: " + TLptsBytesUtil.getHexString(data)); 
    System.out.println("Encrypted Bytes: " + TLptsBytesUtil.getHexString(encryptedData)); 
    System.out.println("Decrypted Bytes: " + TLptsBytesUtil.getHexString(decryptedData)); 
 
    if (!compareBytes(data, decryptedData)) 
      failure(); 
  } 
 
//  Now we do the same test as above, but with an increasing length of data (2-16384 bytes). 
 
  public void testRSADefaultDynamic() 
  { 
    TLptsMainJut.init(); 
 
    System.out.println("\nTesting Default RSA Encryption with varying data sizes..."); 
 
    for (int dataSize = 2; dataSize <= 16384; dataSize *= 2) 
    { 
      System.out.print(" " + dataSize + " : "); 
      byte[] data = generateDataToEncrypt(dataSize); 
      byte[] encryptedData = TLptsCryptoUtil.defaultEncryptRSA(data); 
      byte[] decryptedData = TLptsCryptoUtil.defaultDecryptRSA(encryptedData); 
 
      if (!compareBytes(data, decryptedData)) 
        failure(); 
 
      System.out.print(" " + (dataSize + 1) + " : "); 
      data = generateDataToEncrypt(dataSize + 1); 
      encryptedData = TLptsCryptoUtil.defaultEncryptRSA(data); 
      decryptedData = TLptsCryptoUtil.defaultDecryptRSA(encryptedData); 
 
      if (!compareBytes(data, decryptedData)) 
        failure(); 
    } 
  } 
 
//  This is the simplest of tests, where we just check the default AES for correct functionality. 
//  The AES key is 128 bits by default and is stored in a file in the user home lapetus directory. 
 
  public void testAESDefault() 
  { 
    TLptsMainJut.init(); 
 
    System.out.println("\nTesting Default AES Encryption..."); 
 
    byte[] data = generateDataToEncrypt(512); 
    byte[] encryptedData = TLptsCryptoUtil.defaultEncryptAES(data); 
    byte[] decryptedData = TLptsCryptoUtil.defaultDecryptAES(encryptedData); 
 
    System.out.println("Original Bytes: " + TLptsBytesUtil.getHexString(data)); 
    System.out.println("Encrypted Bytes: " + TLptsBytesUtil.getHexString(encryptedData)); 
    System.out.println("Decrypted Bytes: " + TLptsBytesUtil.getHexString(decryptedData)); 
 
    if (!compareBytes(data, decryptedData)) 
      failure(); 
  } 
 
 
//  Now we do the same test as above, but with an increasing length of data (2-16384 bytes). 
 
  public void testAESDefaultDynamic() 
  { 
    TLptsMainJut.init(); 
 
    System.out.println("\nTesting Default AES Encryption with varying data sizes..."); 
 
    for (int dataSize = 2; dataSize <= 16384; dataSize *= 2) 
    { 
      System.out.print(" " + dataSize + " : "); 
      byte[] data = generateDataToEncrypt(dataSize); 
      byte[] encryptedData = TLptsCryptoUtil.defaultEncryptAES(data); 
      byte[] decryptedData = TLptsCryptoUtil.defaultDecryptAES(encryptedData); 
 
      if (!compareBytes(data, decryptedData)) 
        failure(); 
 
      System.out.print(" " + (dataSize + 1) + " : "); 
      data = generateDataToEncrypt(dataSize + 1); 
      encryptedData = TLptsCryptoUtil.defaultEncryptAES(data); 
      decryptedData = TLptsCryptoUtil.defaultDecryptAES(encryptedData); 
 
      if (!compareBytes(data, decryptedData)) 
        failure(); 
    } 
  } 
 
 
//  In the test below we verify the ability to create a new RSA key from the application, with the requested size (1024 bits). 
 
  public void testRSAInstance() 
  { 
    TLptsMainJut.init(); 
 
    System.out.println("\nTesting Instance RSA Encryption..."); 
 
    TLptsCryptoUtil cryptoModule = new TLptsCryptoUtil(); 
    if (!cryptoModule.initCipherRSA(1024)) 
    { 
      failure("Could not initiate 1024 bit RSA key pair."); 
      return; 
    } 
 
    byte[] data = generateDataToEncrypt(512); 
    byte[] encryptedData = cryptoModule.encryptRSA(data); 
    byte[] decryptedData = cryptoModule.decryptRSA(encryptedData); 
 
    System.out.println("Original Bytes: " + TLptsBytesUtil.getHexString(data)); 
    System.out.println("Encrypted Bytes: " + TLptsBytesUtil.getHexString(encryptedData)); 
    System.out.println("Decrypted Bytes: " + TLptsBytesUtil.getHexString(decryptedData)); 
 
    if (!compareBytes(data, decryptedData)) 
      failure(); 
  } 
 
 
//  Now we will try to initiate an AES cipher starting with a 256 bit and going down to 128. 
//  Depending on whether JCE is Enhanced or not, the 256 bit cipher may initiate. 
//  The minimum requirement is the 128 bit cipher. 
 
  public void testAESInstance() 
  { 
    TLptsMainJut.init(); 
 
    System.out.println("\nTesting Instance AES Encryption..."); 
 
    TLptsCryptoUtil cryptoModule = new TLptsCryptoUtil(); 
 
    if (!cryptoModule.initCipherAES(cryptoModule.generateKey4AES(256)))       // may not be able to do this 
      if (!cryptoModule.initCipherAES(cryptoModule.generateKey4AES(192)))     // may not be able to do this 
        if (!cryptoModule.initCipherAES(cryptoModule.generateKey4AES(128)))   // should be able to do this 
        { 
          failure("Could not generate at least a 128 bit key for AES"); 
          return; 
        } 
 
    byte[] data = generateDataToEncrypt(512); 
    byte[] encryptedData = cryptoModule.encryptAES(data); 
    byte[] decryptedData = cryptoModule.decryptAES(encryptedData); 
 
    System.out.println("Original Bytes: " + TLptsBytesUtil.getHexString(data)); 
    System.out.println("Encrypted Bytes: " + TLptsBytesUtil.getHexString(encryptedData)); 
    System.out.println("Decrypted Bytes: " + TLptsBytesUtil.getHexString(decryptedData)); 
 
    if (!compareBytes(data, decryptedData)) 
      failure(); 
  } 
 
//  This test is basically to verify that the key pair can be written to files, read and utilised with success. 
//  We use both instance and the default keys. 
 
  public void testRSA2Files() 
  { 
    TLptsMainJut.init(); 
 
    System.out.println("\nTesting Instance RSA Encryption using files..."); 
 
    // we create a new key of 1024 bits, store it in files and use it to encrypt. 
    TLptsCryptoUtil cryptoModule = new TLptsCryptoUtil(); 
    if (!cryptoModule.initCipherRSA(1024)) 
    { 
      failure("Could not initiate 1024 bit RSA key pair."); 
      return; 
    } 
    cryptoModule.writeRSA2Files(TLptsFileUtil.getUserHomeLapetusDirectory() + "my.rsa.1024.private.key.xml", 
                                TLptsFileUtil.getUserHomeLapetusDirectory() + "my.rsa.1024.public.key.xml"); 
 
    TLptsCryptoUtil.defaultWriteRSA2Files(TLptsFileUtil.getUserHomeLapetusDirectory() + "rsa.test.default.private.key.xml", 
                                            TLptsFileUtil.getUserHomeLapetusDirectory() + "rsa.test.default.public.key.xml"); 
 
    byte[] data = generateDataToEncrypt(512); 
    byte[] encryptedData1 = cryptoModule.encryptRSA(data); 
    byte[] encryptedData2 = TLptsCryptoUtil.defaultEncryptRSA(data); 
 
    // now we generate a new cryptos using the key files and then decrypt 
    TLptsCryptoUtil cryptoModule1 = new TLptsCryptoUtil(); 
    if (!cryptoModule1.initCipherRSA(TLptsFileUtil.getUserHomeLapetusDirectory() + "my.rsa.1024.private.key.xml", 
                                     TLptsFileUtil.getUserHomeLapetusDirectory() + "my.rsa.1024.public.key.xml")) 
    { 
      failure("Could not instantiate RSA 1024 bit from file!"); 
      return; 
    } 
    TLptsCryptoUtil cryptoModule2 = new TLptsCryptoUtil(); 
    if (!cryptoModule2.initCipherRSA(TLptsFileUtil.getUserHomeLapetusDirectory() + "rsa.test.default.private.key.xml", 
                                     TLptsFileUtil.getUserHomeLapetusDirectory() + "rsa.test.default.public.key.xml")) 
    { 
      failure("Could not instantiate RSA 1024 bit from file!"); 
      return; 
    } 
 
    byte[] decryptedData1 = cryptoModule1.decryptRSA(encryptedData1); 
    byte[] decryptedData2 = cryptoModule2.decryptRSA(encryptedData2); 
 
    System.out.println("Original Bytes: " + TLptsBytesUtil.getHexString(data)); 
    System.out.println("Encrypted Bytes(1): " + TLptsBytesUtil.getHexString(encryptedData1)); 
    System.out.println("Decrypted Bytes(1): " + TLptsBytesUtil.getHexString(decryptedData1)); 
    System.out.println("Encrypted Bytes(2): " + TLptsBytesUtil.getHexString(encryptedData2)); 
    System.out.println("Decrypted Bytes(2): " + TLptsBytesUtil.getHexString(decryptedData2)); 
 
    if (!compareBytes(data, decryptedData1)) 
      failure(); 
 
    if (!compareBytes(data, decryptedData2)) 
      failure(); 
  } 
 
//  This is a test scenario which is an everyday situation. We have a foreign public key, which will be used to encrypt data. 
//  Then the encrypted data is decrypted by the foreign private key holder. 
//  We will test both an instantiated instance and the default static instance of the crypto module. 
 
  public void testRSADefaultForeign() 
  { 
    TLptsMainJut.init(); 
 
    System.out.println("\nTesting Foreign RSA Encryption (default and instantiated) ..."); 
 
    TLptsCryptoUtil foreignCrypto = new TLptsCryptoUtil(); 
    TLptsCryptoUtil localCrypto = new TLptsCryptoUtil(); 
 
    // the default string are not really required here, nor below. It is here for demonstration and test purposes. 
    if (!foreignCrypto.initCipherRSA(2048, TLptsCryptoUtil.DEFAULT_RSA_INSTANCE_STRING, TLptsCryptoUtil.DEFAULT_RSA_KEY_STRING)) 
    { 
      failure("Could not initiate Foreign 2048 bit RSA."); 
      return; 
    } 
 
    byte[] data = generateDataToEncrypt(512); 
 
    // the RSA Instance string below is TLptsCryptoUtil.DEFAULT_RSA_INSTANCE_STRING, and the key string is also default. 
    TLptsCryptoUtil.defaultInitForeignPublicCipherRSA(foreignCrypto.getPublicRSAModulus(), foreignCrypto.getPublicRSAExponent(), foreignCrypto.getRSAKeyBitSize(), 
                                                        TLptsCryptoUtil.DEFAULT_RSA_INSTANCE_STRING, TLptsCryptoUtil.DEFAULT_RSA_KEY_STRING); 
    localCrypto.initForeignPublicCipherRSA(foreignCrypto.getPublicRSAModulus(), foreignCrypto.getPublicRSAExponent(), foreignCrypto.getRSAKeyBitSize(), 
                                           foreignCrypto.getRSAInstanceString(), foreignCrypto.getRSAKeyString()); 
 
    byte[] encryptedData1 = TLptsCryptoUtil.defaultForeignEncryptRSA(data); 
    byte[] encryptedData2 = localCrypto.foreignEncryptRSA(data); 
 
    byte[] decryptedData1 = foreignCrypto.decryptRSA(encryptedData1); 
    byte[] decryptedData2 = foreignCrypto.decryptRSA(encryptedData2); 
 
    System.out.println("Original Bytes: " + TLptsBytesUtil.getHexString(data)); 
    System.out.println("Encrypted Bytes(1): " + TLptsBytesUtil.getHexString(encryptedData1)); 
    System.out.println("Encrypted Bytes(2): " + TLptsBytesUtil.getHexString(encryptedData1)); 
    System.out.println("Decrypted Bytes(1): " + TLptsBytesUtil.getHexString(decryptedData1)); 
    System.out.println("Decrypted Bytes(2): " + TLptsBytesUtil.getHexString(decryptedData2)); 
 
    if (!compareBytes(data, decryptedData1)) 
      failure(); 
    if (!compareBytes(data, decryptedData2)) 
      failure(); 
  } 
 
 
//  This test is basically to verify that the AES key can be written, read and utilised with success from a file. 
//  We use both instance and the default keys. 
 
  public void testAES2File() 
  { 
    TLptsMainJut.init(); 
 
    System.out.println("\nTesting Instance AES Encryption using a file..."); 
 
    TLptsCryptoUtil cryptoModule = new TLptsCryptoUtil(); 
    if (!cryptoModule.initCipherAES(cryptoModule.generateKey4AES(128))) 
    { 
      failure("Could not generate 128 bit key for AES"); 
      return; 
    } 
 
    cryptoModule.writeAES2File(TLptsFileUtil.getUserHomeLapetusDirectory() + "my.aes.key.xml"); 
    TLptsCryptoUtil.defaultWriteAES2File(TLptsFileUtil.getUserHomeLapetusDirectory() + "aes.test.default.key.xml"); 
 
    byte[] data = generateDataToEncrypt(512); 
    byte[] encryptedData1 = cryptoModule.encryptAES(data); 
    byte[] encryptedData2 = TLptsCryptoUtil.defaultEncryptAES(data); 
 
    // now we generate a new crypto using the key file and then decrypt 
    TLptsCryptoUtil cryptoModule1 = new TLptsCryptoUtil(); 
    if (!cryptoModule1.initCipherAES(TLptsFileUtil.getUserHomeLapetusDirectory() + "my.aes.key.xml")) 
    { 
      failure("Could not initiate AES cipher from file."); 
      return; 
    } 
    TLptsCryptoUtil cryptoModule2 = new TLptsCryptoUtil(); 
    if (!cryptoModule2.initCipherAES(TLptsFileUtil.getUserHomeLapetusDirectory() + "aes.test.default.key.xml")) 
    { 
      failure("Could not initiate AES cipher from file."); 
      return; 
    } 
    byte[] decryptedData1 = cryptoModule1.decryptAES(encryptedData1); 
    byte[] decryptedData2 = cryptoModule2.decryptAES(encryptedData2); 
 
    System.out.println("Original Bytes: " + TLptsBytesUtil.getHexString(data)); 
    System.out.println("Encrypted Bytes(1): " + TLptsBytesUtil.getHexString(encryptedData1)); 
    System.out.println("Decrypted Bytes(1): " + TLptsBytesUtil.getHexString(decryptedData1)); 
    System.out.println("Encrypted Bytes(2): " + TLptsBytesUtil.getHexString(encryptedData2)); 
    System.out.println("Decrypted Bytes(2): " + TLptsBytesUtil.getHexString(decryptedData2)); 
 
    if (!compareBytes(data, decryptedData1)) 
      failure(); 
    if (!compareBytes(data, decryptedData2)) 
      failure(); 
  } 
 
//  We have the ability to store credentials (user name and password) in one byte array, encrypted either with AES or RSA. 
//  In this test we will verify both RSA ans AES, for both the default and instance of TLptsCryptoUtil. 
 
  public void testCredentials() 
  { 
    TLptsMainJut.init(); 
 
    System.out.println("\nTesting Credential encryption/decryption (instance and default)..."); 
 
    String userName = "This Is a Really Long User Name"; // even has spaces 
    String password = "With such a long user name, we need a very long and difficult password like !@#$%^&&*()09876543210 - Cool!"; 
 
    TLptsCryptoUtil cryptoModule = new TLptsCryptoUtil(); 
    // initiate 3 ciphers, 1024, 2048 and 128 bit. The 1024 and 128 are default. 
    if (!cryptoModule.initCipherRSA(2048) || 
        !cryptoModule.initCipherAES(cryptoModule.generateKey4AES(128))) 
    { 
      failure("Could not create RSA and AES Cipher instances.(2048 & 128)"); 
      return; 
    } 
    byte[] rsaDefault = TLptsCryptoUtil.defaultEncryptCredentialsRSA(userName, password); 
    byte[] rsaInstance = cryptoModule.encryptCredentialsRSA(userName, password); 
    byte[] aesDefault = TLptsCryptoUtil.defaultEncryptCredentialsAES(userName, password); 
    byte[] aesInstance = cryptoModule.encryptCredentialsAES(userName, password); 
 
    if (rsaDefault == null || rsaInstance == null || aesDefault == null || aesInstance == null) 
    { 
      failure("Could not encrypt credentials"); 
      return; 
    } 
    TLptsCryptoUtil.Credentials rsaDefaultCredentials = TLptsCryptoUtil.defaultDecryptCredentialsRSA(rsaDefault); 
    TLptsCryptoUtil.Credentials rsaInstanceCredentials = cryptoModule.decryptCredentialsRSA(rsaInstance); 
    TLptsCryptoUtil.Credentials aesDefaultCredentials = TLptsCryptoUtil.defaultDecryptCredentialsAES(aesDefault); 
    TLptsCryptoUtil.Credentials aesInstanceCredentials = cryptoModule.decryptCredentialsAES(aesInstance); 
 
    if (!userName.equals(rsaDefaultCredentials.userName) || 
        !userName.equals(rsaInstanceCredentials.userName) || 
        !userName.equals(aesDefaultCredentials.userName) || 
        !userName.equals(aesInstanceCredentials.userName)) 
    { 
      failure("User Name is not the same after encryption and decryption."); 
      return; 
    } 
    if (!password.equals(rsaDefaultCredentials.password) || 
        !password.equals(rsaInstanceCredentials.password) || 
        !password.equals(aesDefaultCredentials.password) || 
        !password.equals(aesInstanceCredentials.password)) 
    { 
      failure("Password is not the same after encryption and decryption."); 
      return; 
    } 
    System.out.println("Credentials successfully verified for AES and RSA."); 
  } 
 
//  Compares two streams of bytes for exact matching. 
 
  private boolean compareBytes(byte[] data, byte[] decryptedData) 
  { 
    if (data == null || decryptedData == null) 
    { 
      System.out.println("Comparing to null value. Failed !"); 
      return false; 
    } 
 
    if (data.length != decryptedData.length) 
    { 
      System.out.println("Data is not the same length as the decrypted bytes!"); 
      return false; 
    } 
 
    for (int i = 0; i < data.length; i++) 
      if (data[i] != decryptedData[i]) 
      { 
        System.out.println("Byte comparison is not equal: Byte index " + i + " is not the same : " + 
                           data[i] + " <> " + decryptedData[i]); 
        return false; 
      } 
 
    System.out.println("Byte comparison successful : data and decrypted bytes are identical."); 
    return true; 
  } 
 
 
//  This just generates bytes in an incremental fashion (0-255). 
 
  private byte[] generateDataToEncrypt(int length) 
  { 
    byte[] data = new byte[length]; 
    for (int i = 0; i < length; i++) 
      data[i] = TLptsBytesUtil.initByteFromInteger(i % 256); 
    return data; 
  } 
 
  private void failure(String error) 
  { 
    System.out.println(); 
    System.out.println("\n!@#$%^&*() Failed Test : " + error); 
    failure(); 
  } 
 
  private void failure() 
  { 
    for (TLptsLog log : TLptsLogger.getLogList(false)) 
      System.out.println(log.getMessage() + " : " + log.getSupportingText() + " : " + log.getExceptionMessage()); 
    fail(); 
//    System.exit(0); 
  } 
}