CryptoMañana Documentation

The Object-Oriented PHP Cryptography Framework

Asymmetric Cryptography

    The type of symmetric cryptography, that is also known as public-key cryptography, defines a security system that uses two different keys for each processing operation (encryption/decryption). The main reason why they are called asymmetric is the fact that the encryption key is different from the decryption key and the actual operation logic is totally different (in contrast to symmetric algorithms). The asymmetric ciphers are widely used for encryption/decryption of small amounts of data (like symmetrical algorithm keys), data signature implementations and key exchange protocols. This type of category has a slow processing speed and is limited to the size of the key (minus a few bytes).

This type of cryptographic system uses pairs of keys that are generated by cryptographic algorithms which are based on complex mathematical problems (termed as one-way functions). Each pair of keys consists of a public key, for encryption or verification purposes, and a private key, for decryption or signing type of processes. The private key must stay known only to the owner (or server), while the public key can be openly distributed to clients without compromising security. There are three main types of ciphers in this category:

    The CryptoMañana (CryptoManana) cryptography framework provides object-oriented components for each of the three types and has a huge set of available realizations. It is important to note, that the key exchange algorithms are added to the cryptographic protocol namespace because of their dependency on other cryptographic primitives to function correctly. They are described on the next page of this documentation’s tutorial.

Basic Methods

    The provided software components for asymmetrical ciphers in the cryptography model always include:

setKeyPair() // set the two keys
getKeyPair() // get the two keys
setPrivateKey() // set a private key
getPrivateKey() // get the private key
setPublicKey() // set a public key
getPublicKey() // get the public key
checkIfThePrivateKeyIsSet() // is private key set
checkIfThePublicKeyIsSet() // is public key set

Note: It is important to note that the objects support working with just one key, because some often asymmetric primitives or protocols have that need and thus is the need of the last two methods above.

Key Pair Format

    The key pair format uses a Base64 encoded value of the standard OpenSSL representation starting with -----BEGIN {type in here} KEY----- and ending with -----END {type in here} KEY-----. This detail is actually quite not important, because there is a created component in the CryptoMañana (CryptoManana) cryptography framework that provides key pair generation (and more). Of course, you could always do more advanced manual key importing by doing a Base64 encoding of the values of your keys. You can generate your key pairs with the PHP OpenSSL functions (like openssl_pkey_export()) or even with a console-based OpenSSL tool. In short, the key format is the Base64 version of the standard format (base64_encode($key)).

    The simplest way to generate a key pair via the framework is by using the TokenGenerator component (which will be examined in more detail in one of the next pages of this manual). This component will return a data structure object of type KeyPair which will contain the two keys and can be used directly with the setKeyPair() method of each asymmetric object:

use CryptoManana\Utilities\TokenGenerator;
use CryptoManana\DataStructures\KeyPair;

$generator = new TokenGenerator();

$keyPair = $generator->getAsymmetricKeyPair(
	$generator::KEY_PAIR_1024_BITS, // or 1024
	$generator::RSA_KEY_PAIR_TYPE // $generator::DSA_KEY_PAIR_TYPE
);

if ($keyPair instanceof CryptoManana\DataStructures\KeyPair) {
	echo 'The keypair is a valid framework object!';
} else {
	echo 'The keypair is of invalid data format!';
}

$privateKey = $keyPair->private;
$publicKey = $keyPair->public;

echo 'Private Key: ' . $privateKey . '<br>';
echo 'Public Key: ' . $publicKey . '<br>';

// -----BEGIN PRIVATE KEY----- ..... -----END PRIVATE KEY
echo 'Raw Private Key: ' . base64_decode($privateKey) . '<br>';

// -----BEGIN PUBLIC KEY----- ..... -----END PUBLIC KEY
echo 'Raw Public Key: ' . base64_decode($publicKey) . '<br>';

Note: The supported types are RSA_KEY_PAIR_TYPE and DSA_KEY_PAIR_TYPE.

Key Pair Reuse

    One of the best practices states that you should generate one key pair for your website (one website, multiple clients) or many for example when needing to implement multilevel signing/verification (multiple authority verification). As with other keys for cryptography primitive, try to avoid reuse or a too frequent period of generation for a new key pair. Key pair generation is slow and the key management can be frustrating, but ensure you are using the correct strategy for your system.

    It is important to note that mathematically asymmetric algorithms may allow you to generate multiple public keys derived from one private key, but from a security point, this is forbidden. This is because having too many public keys can create the possibility of calculating or reverse-engineering the private key. The most frequently pointed example is the Chinese remainder theorem that can be used to exploit certain vulnerabilities in certain asymmetric systems.

Asymmetric Encryption

    The first supported type is the data encryption cipher that is important for securing cryptographic configurations (like secret keys). This type of encryption can handle only small chunks of data (smaller than the key size) and also apply a padding operation to make the block filled (similar to symmetric block ciphers). The supported algorithm/standard realizations at the \CryptoManana\AsymmetricEncryption namespace are:

    It is important to mention that the asymmetric encryption cipher components have 13 other methods available:

encryptData() // encrypt a string of binary data
decryptData() // decrypt a ciphertext representation
encryptObject() // encrypt an object's serialization state
decryptObject() // decrypt an object's serialization state
encryptFile() // encrypt a file's content
decryptFile() // decrypt a file's content
setPaddingStandard() // set the padding standard
getPaddingStandard() // get the padding standard
getPaddingReservedSize() // get how many bytes are reserved
setCipherFormat() // set the ciphertext format
getCipherFormat() // get the ciphertext format
enableChunkProcessing() // enable chunk encryption
disableChunkProcessing() // disable chunk encryption

    This type of component has 1 public constant available:

KEY_SIZE // The secret key size measured in bits

    As previously discussed, these algorithms are meant to process a small amount of data that are limited to the key size minus a few reserved bytes. This limitation can be removed via the usage of chunks, however, this type of approach is insecure. The framework provides this feature but does not promote its usage, so it is disabled by default. If you want to enable it, use the enableChunkProcessing()/disableChunkProcessing() methods.

    The software framework supports a vast variety of well-known and frequently used data formats for the input/output ciphertext value. Each asymmetrical encryption object provides 5 formats that can be easily configured. The specific format can be enabled via the setCipherFormat() setter method (the default setting is ENCRYPTION_OUTPUT_BASE_64_URL) and the available format setting constants per each object. The following options are available for each component:

    The asymmetrical encryption object provides 2 padding standards that can be easily configured. The specific padding mode can be enabled via the setPaddingStandard() setter method (the default setting is OAEP_PADDING) and the available setting constants per each object. The framework supports the following final block padding modes for encryption/decryption:

    Here is a simple example for the usage of this type of encryption component:

use CryptoManana\AsymmetricEncryption\Rsa1024;
use CryptoManana\Utilities\TokenGenerator;
use \stdClass as stdClass;

$generator = new TokenGenerator();

$keyPair = $generator->getAsymmetricKeyPair(
	$generator::KEY_PAIR_1024_BITS, // or 1024
	$generator::RSA_KEY_PAIR_TYPE
);

$crypter = new Rsa1024();

$crypter->setKeyPair($keyPair)
	->setPaddingStandard($crypter::OAEP_PADDING); // or `Rsa1024::`

$data = 'testing information';
echo 'Data: ' . $data . '<br>';

$cipherData = $crypter->encryptData($data);
echo 'Cipher Data: ' . $cipherData . '<br>';

echo $data === $crypter->decryptData($cipherData) ?
	'Data is decrypted successfully' : 'Wrong decryption!';

$object = new stdClass();
$object->data = $data;

$cipherObject = $crypter->encryptObject($object);
echo 'Cipher Object: ' . $cipherObject . '<br>';

$tmp = $crypter->decryptObject($cipherObject);

echo $object->data === $tmp->data ?
	'Object is decrypted successfully' : 'Wrong decryption!';

$crypter->enableChunkProcessing(); // this is insecure usage
$encryptedContent = $crypter->encryptFile(__FILE__);

$fileName = trim(sys_get_temp_dir()) ?: (string)ini_get('upload_tmp_dir');
$fileName .= DIRECTORY_SEPARATOR . 'testing-file.encrypted';

file_put_contents($fileName, $encryptedContent);

$decryptedContent = $crypter->decryptFile($fileName);

echo file_get_contents(__FILE__) === $decryptedContent ?
	'File is decrypted successfully' : 'Wrong decryption!';

@unlink($fileName);

Note: Please read more about the RSA algorithm before you use it!

Digital Signatures

    The second supported type is the digital signature algorithm that is important for the data and the owner verification process. They are widely used to sign valid computer documents under a valid authority and have an actual legal value. It is important to note that in the next examples we will generate and use insecure self-signed signatures to show how they can be used for internal security (but not as legal proof). Also, this type of system uses a paired hash function inside, which is used to verify the integrity of the data being signed. The supported algorithm/standard realizations at the \CryptoManana\AsymmetricEncryption namespace are:

    It is important to mention that the asymmetric digital signature components have 13 other methods available:

signData() // sign and obtain a signature value
verifyDataSignature() // verify a signature against data
signObject() // sing an object's serialization state
verifyObjectSignature() // verify a signature against an object
signFile() // sing a file's content
verifyFileSignature() // verify a file's signature against the content
setSignatureFormat() // set the signature format
getSignatureFormat() // get the current signature format
setSignatureDigestion() // set the internal digestion algorithm
getSignatureDigestion() // set the current digestion algorithm

    This type of component has 1 public constant available:

KEY_SIZE // The secret key size measured in bits

    The software framework supports a vast variety of well-known and frequently used data formats for the output digital signature value. Each asymmetrical signature object provides 5 formats that can be easily configured. The specific format can be enabled via the setSignatureFormat() setter method (the default setting is SIGNATURE_OUTPUT_HEX_UPPER) and the available format setting constants per each object. The following options are available for each component:

    The implementation of the component supports all currently flagged hash functions used by the digestion specification of digital signatures. This provides each asymmetrical signature object with 5 digestion algorithms that can be easily chosen. The specific format can be enabled via the setSignatureDigestion() setter method (the default setting is SHA2_384_SIGNING) and the available format setting constants per each object. The following options are available for each component:

Note: These are the current available secure algorithms, that are used by standard, but in the future, these can become absolute.

    Here is a simple example for the usage of this type of signature component:

use CryptoManana\AsymmetricEncryption\Dsa1024;
use CryptoManana\Utilities\TokenGenerator;
use \stdClass as stdClass;

$generator = new TokenGenerator();

// This signature is self-signed
$keyPair = $generator->getAsymmetricKeyPair(
    $generator::KEY_PAIR_1024_BITS, // or 1024
    $generator::DSA_KEY_PAIR_TYPE
);

$signer = new Dsa1024();

$signer->setKeyPair($keyPair)
    ->setSignatureFormat($signer::SIGNATURE_OUTPUT_HEX_LOWER) // or `Dsa1024::`
    ->setSignatureDigestion($signer::SHA2_512_SIGNING); // or `Dsa1024::`

$data = 'testing information';
$signature = $signer->signData($data);
echo 'Data: ' . $data . '<br>';
echo 'Signature: ' . $signature . '<br>';

if ($signer->verifyDataSignature($signature, $data)) {
    echo "The signature is valid!";
} else {
    echo "Invalid data or signature!";
}

$object = new stdClass();
$object->data = $data;

$objectSignature = $signer->signObject($object);
echo 'Object Signature: ' . $objectSignature . '<br>';

if ($signer->verifyObjectSignature($objectSignature, $object)) {
    echo "The object signature is valid!";
} else {
    echo "Invalid object data or signature!";
}

$fileSignature = $signer->signFile(__FILE__);

if ($signer->verifyFileSignature($fileSignature, __FILE__)) {
    echo "The file signature is valid!";
} else {
    echo "Invalid file data or signature!";
}

Note: Please read more about the DSA/DSS algorithm before you use it!

The Object Hierarchy

    The internal components’ hierarchy is visualized as a technical diagram and can be seen in Figure 1.

The Asymmetric Encryption Hierarchy

Figure 1: The data asymmetric encryption components hierarchy.

    For more information about the capabilities of the components, please see the technical documentation for \CryptoManana\AsymmetricEncryption namespace.

    In addition, as previously stated the key exchange algorithms are described on the next page of this documentation’s tutorial.

Previous Next