Skip to content

Commit

Permalink
Merge pull request #50 from Tiqr/feature/remove-mcrypt
Browse files Browse the repository at this point in the history
Replace mcrypt by openssl
  • Loading branch information
pmeulen authored Aug 31, 2023
2 parents 8984a15 + 9eee7a3 commit fa7884b
Show file tree
Hide file tree
Showing 15 changed files with 925 additions and 141 deletions.
127 changes: 103 additions & 24 deletions library/tiqr/Tiqr/UserSecretStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,31 +30,108 @@ class Tiqr_UserSecretStorage
* Get a secret storage of a certain type
*
* @param String $type The type of storage to create. Supported
* types are 'file', 'pdo' or 'oathservice'.
* @param array $options The options to pass to the storage
* instance. See the documentation
* in the UserSecretStorage/ subdirectory for
* options per type.
* types are 'file', 'pdo' or 'oathserviceclient'.
* @param LoggerInterface $logger The logger to use.
* @param array $options The options to pass to the storage instance.
* This contains the configuration options for the UserSecretStorage
* specified in the $type parameter.
* See the documentation in the UserSecretStorage subdirectory for options
* per type.
*
* For the file and pdo UserSecretStorage types the encryption and decryption options
* are used to encrypt the secrets. These are ignored when the oathserviceclient
* is used.
*
* encryption:
* The $options array can contain an 'encryption' key that specifies
* the encryption method and configuration to use for encrypting the secrets.
* The encryption method is specified in the 'type' key. Available types are:
* - 'plain' : (default) no encryption
* - 'dummy' : alias for 'plain'
* - 'openssl: Uses the openssl extension to encrypt the secrets.
* - A custom encryption class can be used by specifying the class name. The custom encryption
* class must implement the Tiqr_UserSecretStorage_Encryption_Interface
* The encryption options are documented in the UserSecretStorage/Encryption/
* subdirectory.
*
* decryption:
* The $options array can contain a 'decryption' kay that lists additional
* encryption methods and their configuration to use for decrypting the secrets only.
* The format is slightly different from the encryption configuration to allow
* multiple decryption methods to be specified.
* The decryption configuration is optional. If not specified it defaults to the
* 'plain' encryption method.
* Note that all decryption methods specified in the 'decryption' configuration
* must have a unique type as returned by the encryption method's
* Tiqr_UserSecretStorage_Encryption_Interface::get_type() implementation
*
* The $options array has the following structure:
* array(
* // UserSecretStorage configuration
* '<option_1_for_usersecretstorage>' => '<value>',
* '<option_2_for_usersecretstorage>' => '<value>',
*
* // Encryption configuration
* // This configuration is used for both encryption and decryption
* // If not provided in config, we fall back to dummy/plain (no) encryption
* // <encryption_type> is the type of encryption or a custom encryption class name
* 'encryption' => array(
* 'type' => '<encryption_type>',
* '<option_1_for_encryption>' => '<value>',
* '<option_2_for_encryption>' => '<value>',
* ),
*
* // Additional decryption method configuration
* // This configuration is only used for decryption, the encryption
* // configuration is also used for decryption and does not need to be repeated here.
* // <encryption_type_1> and <encryption_type_2> is the type of encryption or a custom encryption
* // class name.
* 'decryption' => array(
* '<encryption_type_1>' => array(
* '<option_1_for_encryption_1>' => '<value>',
* '<option_2_for_encryption_1>' => '<value>',
* ),
* '<encryption_type_2>' => array(
* '<option_1_for_encryption_2>' => '<value>',
* '<option_2_for_encryption_2>' => '<value>',
* ),
* )
* );
*
*
* @return Tiqr_UserSecretStorage_Interface
* @throws RuntimeException If an unknown type is requested.
* @throws RuntimeException When the options configuration array misses a required parameter
*/
public static function getSecretStorage(string $type, LoggerInterface $logger, array $options): Tiqr_UserSecretStorage_Interface
{
// If not provided in config, we fall back to dummy (no) encryption
$encryptionType = $config['encryption']['type'] ?? 'dummy';
if ($type == 'oathserviceclient') {
return (new Tiqr_UserSecretStorage)->_create_oauth_service_client($logger, $options);
}

// Create encryption instance
// If not provided in config, we fall back to dummy/plain (no) encryption
$encryptionType = $options['encryption']['type'] ?? 'plain';
// If the encryption configuration is not configured, we fall back to an empty encryption configuration
$encryptionOptions = $config['encryption'] ?? [];
$encryption = Tiqr_UserStorage_Encryption::getEncryption($logger, $encryptionType, $encryptionOptions);
$encryptionOptions = $options['encryption'] ?? [];
$encryption = Tiqr_UserSecretStorage_Encryption::getEncryption($logger, $encryptionType, $encryptionOptions);

// Create decryption instance(s)
// If not provided in config, we fall back to dummy/plain (no) encryption
$decryptionOptions = $options['decryption'] ?? ['plain' => []];
$decryption = [];
foreach ($decryptionOptions as $decryptionType => $decryptionConfig) {
$decryption[$decryptionType] = Tiqr_UserSecretStorage_Encryption::getEncryption($logger, $decryptionType, $decryptionConfig);
}

switch ($type) {
case "file":
if (!array_key_exists('path', $options)) {
throw new RuntimeException('The path is missing in the UserSecretStorage configuration');
}
$path = $options['path'];
return new Tiqr_UserSecretStorage_File($encryption, $path, $logger);
return new Tiqr_UserSecretStorage_File($encryption, $path, $logger, $decryption);

case "pdo":
// Input validation on the required configuration options
if (!array_key_exists('dsn', $options)) {
Expand All @@ -80,21 +157,23 @@ public static function getSecretStorage(string $type, LoggerInterface $logger, a
);
throw ReadWriteException::fromOriginalException($e);
}
return new Tiqr_UserSecretStorage_Pdo($encryption, $logger, $handle, $tableName);

case "oathserviceclient":
if (!array_key_exists('apiURL', $options)) {
throw new RuntimeException('The apiURL is missing in the UserSecretStorage configuration');
}
if (!array_key_exists('consumerKey', $options)) {
throw new RuntimeException('The consumerKey is missing in the UserSecretStorage configuration');
}

$apiClient = new Tiqr_API_Client();
$apiClient->setBaseURL($options['apiURL']);
$apiClient->setConsumerKey($options['consumerKey']);
return new Tiqr_UserSecretStorage_OathServiceClient($apiClient, $logger);
return new Tiqr_UserSecretStorage_Pdo($encryption, $logger, $handle, $tableName, $decryption);
}
throw new RuntimeException(sprintf('Unable to create a UserSecretStorage instance of type: %s', $type));
}

private function _create_oauth_service_client(LoggerInterface $logger, array $options) : Tiqr_UserSecretStorage_OathServiceClient
{
if (!array_key_exists('apiURL', $options)) {
throw new RuntimeException('The apiURL is missing in the UserSecretStorage configuration');
}
if (!array_key_exists('consumerKey', $options)) {
throw new RuntimeException('The consumerKey is missing in the UserSecretStorage configuration');
}

$apiClient = new Tiqr_API_Client();
$apiClient->setBaseURL($options['apiURL']);
$apiClient->setConsumerKey($options['consumerKey']);
return new Tiqr_UserSecretStorage_OathServiceClient($apiClient, $logger);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,38 @@
*
* @author peter
*/
class Tiqr_UserStorage_Encryption
class Tiqr_UserSecretStorage_Encryption
{
/**
* Get an encryption handler of a certain type (default: 'file')
* Get an encryption handler of a certain type (default: 'dummy')
*
* @param String $type The type of storage to create. Supported
* types are 'dummy', 'mcrypt' or the full class name.
* @param array $options The options to pass to the storage
* instance. See the documentation
* in the Encryption subdirectory for
* options per type.
* @param LoggerInterface $logger
* @param String $type The type of storage to create. Supported types are 'dummy' (default)
* or any class implementing Tiqr_UserSecretStorage_Encryption_Interface.
* In that case $type should be the full class name.
* @param array $options The options to pass to the storage instance. See the documentation
* in the Encryption subdirectory for options per type.
*
* @return Tiqr_UserSecretStorage_Encryption_Interface
*/
public static function getEncryption(LoggerInterface $logger, string $type="dummy", array $options=array()): Tiqr_UserSecretStorage_Encryption_Interface
{
$logger->info(sprintf('Using %s as UserStorage encryption type', $type));
$instance = null;
$logger->info(sprintf('Using "%s" as UserSecretStorage encryption type', $type));
switch ($type) {
case "dummy":
$instance = new Tiqr_UserSecretStorage_Encryption_Dummy($options);
case "plain":
$instance = new Tiqr_UserSecretStorage_Encryption_Plain($options);
break;
case "mcrypt":
$instance = new Tiqr_UserSecretStorage_Encryption_Mcrypt($options);
case "openssl":
$instance = new Tiqr_UserSecretStorage_Encryption_OpenSSL($options);
break;
default:
$instance = new $type($options);
default:
if (class_exists($type)) {
$instance = new $type($options);
} else {
throw new RuntimeException(sprintf("Class '%s' not found", $type));
}
}

return $instance;
Expand Down
36 changes: 25 additions & 11 deletions library/tiqr/Tiqr/UserSecretStorage/Encryption/Interface.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,39 @@ interface Tiqr_UserSecretStorage_Encryption_Interface
/**
* Construct an encryption instance.
*
* @param $config The configuration that a specific configuration class may use.
* @param array $config The configuration
* @throws RuntimeException
*/
public function __construct($config);
public function __construct(array $config);

/**
* Encrypts the given data.
* Encrypts the given data. Throws an exception if the data cannot be encrypted.
*
* @param String $data Data to encrypt.
*
* @return encrypted data
* @param string $data Data to encrypt
* @return string encrypted data
* @throws RuntimeException
*/
public function encrypt($data);
public function encrypt(string $data) : string;

/**
* Decrypts the given data.
* Decrypts the given data. May throw an exception if the data cannot be decrypted
*
* @param string $data Data to decrypt
* @return string decrypted data
* @throws RuntimeException
*/
public function decrypt(string $data) : string;

/**
* Get a string that identifies the encryption implementation
* It is recommended to use a short lowercase string that identifies the encryption implementation that is used.
* The type is stored as part of the encrypted secret to allow the correct encryption implementation
* to be selected to decrypt a secret at runtime.
*
* @param String $data Data to decrypt.
* It must not contain any spaces or special characters.
*
* @return decrypted data
* @return string The type of encryption
* @throws RuntimeException
*/
public function decrypt($data);
public function get_type() : string;
}
68 changes: 0 additions & 68 deletions library/tiqr/Tiqr/UserSecretStorage/Encryption/Mcrypt.php

This file was deleted.

Loading

0 comments on commit fa7884b

Please sign in to comment.