Skip to content

Commit

Permalink
Merge pull request #2 from mbabker/JCryptCipherCrypto
Browse files Browse the repository at this point in the history
Add an implementation of JCryptCipher using the Crypto class
  • Loading branch information
paragonie-scott committed Nov 13, 2015
2 parents 78619fb + b501c89 commit be3e3d2
Show file tree
Hide file tree
Showing 2 changed files with 224 additions and 0 deletions.
125 changes: 125 additions & 0 deletions libraries/joomla/crypt/cipher/crypto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php
/**
* @package Joomla.Platform
* @subpackage Crypt
*
* @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/

defined('JPATH_PLATFORM') or die;

/**
* JCrypt cipher for encryption, decryption and key generation via the php-encryption library.
*
* @since 3.5
*/
class JCryptCipherCrypto implements JCryptCipher
{
/**
* Method to decrypt a data string.
*
* @param string $data The encrypted string to decrypt.
* @param JCryptKey $key The key object to use for decryption.
*
* @return string The decrypted data string.
*
* @since 3.5
* @throws RuntimeException
*/
public function decrypt($data, JCryptKey $key)
{
// Validate key.
if ($key->type != 'crypto')
{
throw new InvalidArgumentException('Invalid key of type: ' . $key->type . '. Expected crypto.');
}

// Decrypt the data.
try
{
return Crypto::Decrypt($data, $key->public);
}
catch (InvalidCiphertextException $ex)
{
throw new RuntimeException('DANGER! DANGER! The ciphertext has been tampered with!', $ex->getCode(), $ex);
}
catch (CryptoTestFailedException $ex)
{
throw new RuntimeException('Cannot safely perform decryption', $ex->getCode(), $ex);
}
catch (CannotPerformOperationException $ex)
{
throw new RuntimeException('Cannot safely perform decryption', $ex->getCode(), $ex);
}
}

/**
* Method to encrypt a data string.
*
* @param string $data The data string to encrypt.
* @param JCryptKey $key The key object to use for encryption.
*
* @return string The encrypted data string.
*
* @since 3.5
* @throws RuntimeException
*/
public function encrypt($data, JCryptKey $key)
{
// Validate key.
if ($key->type != 'crypto')
{
throw new InvalidArgumentException('Invalid key of type: ' . $key->type . '. Expected crypto.');
}

// Encrypt the data.
try
{
return Crypto::Encrypt($data, $key->public);
}
catch (CryptoTestFailedException $ex)
{
throw new RuntimeException('Cannot safely perform encryption', $ex->getCode(), $ex);
}
catch (CannotPerformOperationException $ex)
{
throw new RuntimeException('Cannot safely perform encryption', $ex->getCode(), $ex);
}
}

/**
* Method to generate a new encryption key object.
*
* @param array $options Key generation options.
*
* @return JCryptKey
*
* @since 3.5
* @throws RuntimeException
*/
public function generateKey(array $options = array())
{
// Create the new encryption key object.
$key = new JCryptKey('crypto');

// Generate the encryption key.
try
{
$key->public = Crypto::CreateNewRandomKey();
}
catch (CryptoTestFailedException $ex)
{
throw new RuntimeException('Cannot safely create a key', $ex->getCode(), $ex);
}
catch (CannotPerformOperationException $ex)
{
throw new RuntimeException('Cannot safely create a key', $ex->getCode(), $ex);
}

// Explicitly flag the private as unused in this cipher.
$key->private = 'unused';

return $key;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php
/**
* @package Joomla.UnitTest
* @subpackage Crypt
*
* @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/

/**
* Test class for JCryptCipherCrypto.
*/
class JCryptCipherCryptoTest extends TestCase
{
/**
* This method is called before the first test of this test class is run.
*
* @return void
*/
public static function setUpBeforeClass()
{
// Only run the test if the environment supports it.
try
{
Crypto::RuntimeTest();
}
catch (CryptoTestFailedException $e)
{
self::markTestSkipped('The environment cannot safely perform encryption with this cipher.');
}
}

/**
* Test data for processing
*
* @return array
*/
public function dataStrings()
{
return array(
array('c-;3-(Is>{DJzOHMCv_<#yKuN/G`/Us{GkgicWG$M|HW;kI0BVZ^|FY/"Obt53?PNaWwhmRtH;lWkWE4vlG5CIFA!abu&F=Xo#Qw}gAp3;GL\'k])%D}C+W&ne6_F$3P5'),
array('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ' .
'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor ' .
'in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt ' .
'in culpa qui officia deserunt mollit anim id est laborum.'),
array('لا أحد يحب الألم بذاته، يسعى ورائه أو يبتغيه، ببساطة لأنه الألم...'),
array('Широкая электрификация южных губерний даст мощный толчок подъёму сельского хозяйства'),
array('The quick brown fox jumps over the lazy dog.')
);
}

/**
* @testdox Validates data is encrypted and decrypted correctly
*
* @param string $data The decrypted data to validate
*
* @covers JCryptCipherCrypto::decrypt
* @covers JCryptCipherCrypto::encrypt
* @dataProvider dataStrings
*/
public function testDataEncryptionAndDecryption($data)
{
$cipher = new JCryptCipherCrypto;
$key = $cipher->generateKey();

$encrypted = $cipher->encrypt($data, $key);

// Assert that the encrypted value is not the same as the clear text value.
$this->assertNotSame($data, $encrypted);

$decrypted = $cipher->decrypt($encrypted, $key);

// Assert the decrypted string is the same value we started with
$this->assertSame($data, $decrypted);
}

/**
* @testdox Validates keys are correctly generated
*
* @covers JCryptCipherCrypto::generateKey
*/
public function testGenerateKey()
{
$cipher = new JCryptCipherCrypto;
$key = $cipher->generateKey();

// Assert that the key is the correct type.
$this->assertInstanceOf('JCryptKey', $key);

// Assert the private key is our expected value.
$this->assertSame('unused', $key->private);

// Assert the public key is the expected length
$this->assertSame(Crypto::KEY_BYTE_SIZE, JCrypt::safeStrlen($key->public));

// Assert the key is of the correct type.
$this->assertAttributeEquals('crypto', 'type', $key);
}
}

0 comments on commit be3e3d2

Please sign in to comment.