Compare commits
13 Commits
Author | SHA1 | Date |
---|---|---|
Daniel Legt | 1fbe6f2fb0 | |
Daniel Legt | defe60efb9 | |
Daniel Legt | cb38762215 | |
Daniel Legt | 2645ce64fa | |
Daniel Legt | 752dfd0c23 | |
Daniel Legt | a5923c43e4 | |
Daniel Legt | e2e770dcfe | |
Daniel Legt | 3ee04e2080 | |
Daniel Legt | 1ee954c97f | |
Daniel Legt | 9d16171dca | |
Daniel Legt | e5f7264803 | |
Daniel Legt | 5ae3d8294b | |
Daniel Legt | a1833a238c |
|
@ -1 +1,5 @@
|
|||
test_input_file.txt
|
||||
config.inc.php
|
||||
example.enc.php
|
||||
example.dec.php
|
||||
testdir
|
109
README.md
109
README.md
|
@ -6,22 +6,111 @@ The Project is a simple php encryption wrapper, not even a library, the whole po
|
|||
## Usage
|
||||
Simply use the provided functions from the lib.php file, you can simply import it into any project using that file.
|
||||
|
||||
#### String Encryption
|
||||
|
||||
```php
|
||||
require_once("/path/to/the/file/kpcrypt/lib.php")
|
||||
<?php
|
||||
require_once("./lib.php");
|
||||
@require_once("./config.inc.php");
|
||||
|
||||
$input = "Super secret string!";
|
||||
$key = "My key to encrypt the string with";
|
||||
// Check if the config succesfully loaded, or if the mandatory config fields are missing.
|
||||
if ( empty($config) || empty($config['key']) || empty($config['input']) ) {
|
||||
echo "Please copy the config.sample.inc.php to config.inc.php and change the configuration to match your needs.";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Encrypt the data, the cipher can be easily changed, the integrity_check is recommended to be left to TRUE even if it takes some extra time to decrypt and check.
|
||||
$encryptedData = encryptData($input, $key, 'AES-256-CBC', TRUE);
|
||||
// The memory limit has been set so that we can pass it big strings and test how much it can/will use.
|
||||
ini_set('memory_limit','1G');
|
||||
|
||||
// Echo out the encrypted values to check them
|
||||
function limitStringSize($str, $amount = 20) {
|
||||
if (strlen($str) > $amount)
|
||||
$str = substr($str, 0, $amount) . '...';
|
||||
return $str;
|
||||
}
|
||||
|
||||
echo "Encrypted: " . $encryptedData;
|
||||
$kpc = new kpcrypt($config['key']);
|
||||
|
||||
echo "Key: " . $kpc->getKey() . " \n";
|
||||
|
||||
// Echo out the results
|
||||
$encryptedData = $kpc->encryptData($config['input'], 'AES-256-CBC', TRUE);
|
||||
|
||||
echo "Encrypted: " . limitStringSize($encryptedData);
|
||||
echo "\n";
|
||||
echo "Decrypted: " . decryptData($encryptedData, $key);
|
||||
echo "Decrypted: " . limitStringSize($kpc->decryptData($encryptedData));
|
||||
echo "\n";
|
||||
echo "Peak Memory: " . memory_get_peak_usage() / 1024 . "Kb"; // Check the memory in kb
|
||||
echo "Peak Memory: " . memory_get_peak_usage() / 1024 / 1024 . "Mb"; // Check the memory in kb
|
||||
echo "\n\n";
|
||||
|
||||
// Calculate the string size increse
|
||||
$inputSize = strlen($config['input']); // Bytes
|
||||
$outputSize = strlen($encryptedData); // Bytes
|
||||
|
||||
// Echo out sizing information
|
||||
echo "Sizeof input: " . strlen($config['input']) . "\n"; // Bytes
|
||||
echo "Sizeof output:" . strlen($encryptedData) . "\n"; // Bytes
|
||||
|
||||
echo "\n";
|
||||
```
|
||||
|
||||
#### File Encryption
|
||||
```php
|
||||
<?php
|
||||
|
||||
require("./lib.php");
|
||||
|
||||
/**
|
||||
* This is a simple example of how to encrypt files with the library
|
||||
* The following code will read the file in chunks instead of loading
|
||||
* the whole thing in memory, trying to keep the "Peak Memory Usage"
|
||||
* as low as possible.
|
||||
*/
|
||||
|
||||
define("INPUT_FILE", "./lib.php");
|
||||
define("OUTPUT_FILE", "./testdir/" . "./example.enc.php");
|
||||
define("DEC_OUTPUT_FILE", "./testdir/" . "./example.dec.php");
|
||||
|
||||
// Make sure the testing folder exists
|
||||
if ( !file_exists("./testdir") ) {
|
||||
mkdir("./testdir", 0777, true);
|
||||
}
|
||||
|
||||
|
||||
// Initialize the class
|
||||
$lib = new kpcrypt();
|
||||
|
||||
// $lib->setEncryptionBlocks(128); // This will take ~10 times more time, but will use half as much memory.
|
||||
// Really the best value is the default one.
|
||||
|
||||
$enc_start = round(microtime(true) * 1000);
|
||||
|
||||
// Encrypt the file
|
||||
$lib->encryptFile(INPUT_FILE, OUTPUT_FILE);
|
||||
|
||||
$enc_end = round(microtime(true) * 1000) - $enc_start;
|
||||
$dec_start = round(microtime(true) * 1000);
|
||||
|
||||
// Decrypt the file as well
|
||||
$lib->decryptFile(OUTPUT_FILE, DEC_OUTPUT_FILE);
|
||||
|
||||
$dec_end = round(microtime(true) * 1000) - $dec_start;
|
||||
|
||||
/**
|
||||
* NOTE: You can also compress the output using gzip
|
||||
*/
|
||||
|
||||
echo "\n\n";
|
||||
echo "Input File Size: " . round(filesize(INPUT_FILE) / 1024 / 1024, 2) . "Mb";
|
||||
echo "\n";
|
||||
echo "Output File Size: " . round(filesize(OUTPUT_FILE) / 1024 / 1024, 2) . "Mb";
|
||||
echo "\n";
|
||||
echo "Peak Memory: " . memory_get_peak_usage() / 1024 / 1024 . "Mb"; // Check the memory in Mb
|
||||
echo "\n";
|
||||
echo "Encryption Time: $enc_end ms\n"; // 9700k = ~210ms ( 4Mb = 100ms )
|
||||
echo "Decryption Time: $dec_end ms\n";
|
||||
echo "\n";
|
||||
$errors = $lib->getErrors();
|
||||
echo "Errors: " . ( !empty($errors) ? "\n" . json_encode($errors, JSON_PRETTY_PRINT) : "No Errors!");
|
||||
|
||||
```
|
||||
|
||||
|
@ -29,4 +118,4 @@ echo "Peak Memory: " . memory_get_peak_usage() / 1024 . "Kb"; // Check the memor
|
|||
The licensing of the project is the [MIT license](https://mit-license.org/)
|
||||
|
||||
#### Credit
|
||||
Icons made by [monkik](https://www.flaticon.com/authors/monkik) from [www.flaticon.com](https://www.flaticon.com/);
|
||||
Repository icon made by [monkik](https://www.flaticon.com/authors/monkik) from [www.flaticon.com](https://www.flaticon.com/);
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
require("./lib.php");
|
||||
|
||||
/**
|
||||
* This is a simple example of how to encrypt files with the library
|
||||
* The following code will read the file in chunks instead of loading
|
||||
* the whole thing in memory, trying to keep the "Peak Memory Usage"
|
||||
* as low as possible.
|
||||
*/
|
||||
|
||||
define("INPUT_FILE", "./lib.php");
|
||||
define("OUTPUT_FILE", "./testdir/" . "./example.enc.php");
|
||||
define("DEC_OUTPUT_FILE", "./testdir/" . "./example.dec.php");
|
||||
|
||||
// Make sure the testing folder exists
|
||||
if ( !file_exists("./testdir") ) {
|
||||
mkdir("./testdir", 0777, true);
|
||||
}
|
||||
|
||||
|
||||
// Initialize the class
|
||||
$lib = new kpcrypt();
|
||||
|
||||
// $lib->setEncryptionBlocks(128); // This will take ~10 times more time, but will use half as much memory.
|
||||
// Really the best value is the default one.
|
||||
|
||||
$enc_start = round(microtime(true) * 1000);
|
||||
|
||||
// Encrypt the file
|
||||
$lib->encryptFile(INPUT_FILE, OUTPUT_FILE);
|
||||
|
||||
$enc_end = round(microtime(true) * 1000) - $enc_start;
|
||||
$dec_start = round(microtime(true) * 1000);
|
||||
|
||||
// Decrypt the file as well
|
||||
$lib->decryptFile(OUTPUT_FILE, DEC_OUTPUT_FILE);
|
||||
|
||||
$dec_end = round(microtime(true) * 1000) - $dec_start;
|
||||
|
||||
/**
|
||||
* NOTE: You can also compress the output using gzip
|
||||
*/
|
||||
|
||||
echo "\n\n";
|
||||
echo "Input File Size: " . round(filesize(INPUT_FILE) / 1024 / 1024, 2) . "Mb";
|
||||
echo "\n";
|
||||
echo "Output File Size: " . round(filesize(OUTPUT_FILE) / 1024 / 1024, 2) . "Mb";
|
||||
echo "\n";
|
||||
echo "Peak Memory: " . memory_get_peak_usage() / 1024 / 1024 . "Mb"; // Check the memory in Mb
|
||||
echo "\n";
|
||||
echo "Encryption Time: $enc_end ms\n"; // 9700k = ~210ms ( 4Mb = 100ms )
|
||||
echo "Decryption Time: $dec_end ms\n";
|
||||
echo "\n";
|
||||
$errors = $lib->getErrors();
|
||||
echo "Errors: " . ( !empty($errors) ? "\n" . json_encode($errors, JSON_PRETTY_PRINT) : "No Errors!");
|
43
example.php
43
example.php
|
@ -8,5 +8,46 @@ if ( empty($config) || empty($config['key']) || empty($config['input']) ) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
ini_set('memory_limit','1G');
|
||||
|
||||
function limitStringSize($str, $amount = 20) {
|
||||
if (strlen($str) > $amount)
|
||||
$str = substr($str, 0, $amount) . '...';
|
||||
return $str;
|
||||
}
|
||||
|
||||
$kpc = new kpcrypt($config['key']);
|
||||
|
||||
echo "Key: " . $kpc->getKey() . " \n";
|
||||
|
||||
$enc_start = round(microtime(true) * 1000);
|
||||
|
||||
// Echo out the results
|
||||
echo $encryptedData = encryptData($config['input'], $config['key'], 'AES-256-CBC', TRUE);
|
||||
$encryptedData = $kpc->encryptData($config['input'], 'AES-256-CBC', TRUE);
|
||||
|
||||
$enc_end = round(microtime(true) * 1000) - $enc_start;
|
||||
|
||||
$dec_start = round(microtime(true) * 1000);
|
||||
echo "Encrypted: " . limitStringSize($encryptedData);
|
||||
echo "\n";
|
||||
echo "Decrypted: " . limitStringSize($kpc->decryptData($encryptedData));
|
||||
|
||||
$dec_end = round(microtime(true) * 1000) - $dec_start;
|
||||
|
||||
echo "\n";
|
||||
echo "Peak Memory: " . memory_get_peak_usage() / 1024 / 1024 . "Mb"; // Check the memory in kb
|
||||
echo "\n\n";
|
||||
|
||||
// Calculate the string size increse
|
||||
$inputSize = strlen($config['input']); // Bytes
|
||||
$outputSize = strlen($encryptedData); // Bytes
|
||||
|
||||
// Echo out sizing information
|
||||
echo "Sizeof input: " . strlen($config['input']) . "\n"; // Bytes
|
||||
echo "Sizeof output:" . strlen($encryptedData) . "\n"; // Bytes
|
||||
echo "\n";
|
||||
echo "Encryption Time: $enc_end ms\n"; // 9700k = ~210ms
|
||||
echo "\n";
|
||||
echo "Decryption Time: $dec_end ms\n";
|
||||
|
||||
echo "\n";
|
235
lib.php
235
lib.php
|
@ -1,26 +1,109 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @param string $data The data to be encrypted, this can only encrypt strings.
|
||||
* @param string $key The key to use to encrypt the data, this key should be generated using the openssl_random_pseudo_bytes
|
||||
* @param string $cipherMethod The cypher method to use in the encryption process, these can be checked using
|
||||
* @param bool $integrity_check Check if the encrypted data can also be decypted, this will take 2x more time to process the data, but will make 100% sure that the data is safe and can be decrypted.
|
||||
* @author Kato Twofold
|
||||
* @copyright MIT
|
||||
*
|
||||
* The class has full support for encryption of strings, provides validation for those
|
||||
* and makes sure they can be decrypted on the other end, the key is extremely important
|
||||
* and you MUST keep track of it and not lose it as there is no way of getting it back.
|
||||
*
|
||||
*/
|
||||
function encryptData( string $data, string $key, string $cipherMethod = 'AES-256-CBC', bool $integrity_check = TRUE) {
|
||||
class kpcrypt {
|
||||
|
||||
// The key to use in the encryption process
|
||||
private $key = null;
|
||||
|
||||
/**
|
||||
*
|
||||
* Define the number of blocks that should be read from the source file for each chunk.
|
||||
* For 'AES-128-CBC' each block consist of 16 bytes.
|
||||
* So if we read 10,000 blocks we load 160kb into memory. You may adjust this value
|
||||
* to read/write shorter or longer chunks.
|
||||
*
|
||||
* The higher this size is, the faster the file will be
|
||||
* processed but the more memory will in turn be also used
|
||||
*
|
||||
*/
|
||||
private $blocks = 10000;
|
||||
|
||||
/**
|
||||
* A log of all of the errors, rather nice for debugging
|
||||
* Please don't write to this, only read from it since
|
||||
* it should only store errors about this class.
|
||||
*/
|
||||
private $errorLog = [];
|
||||
|
||||
// The encryption cipher to use
|
||||
private $cipherMethod = "AES-256-CBC";
|
||||
|
||||
/**
|
||||
* @param string $key [Optional] The key to use for encryption, if none is mentioned a random one will be generated
|
||||
*/
|
||||
public function __construct( string $key = null, string $cipherMethod = "AES-256-CBC" ) {
|
||||
// If no key is mentioned, generate one
|
||||
if ( empty($key) ) {
|
||||
$key = bin2hex(openssl_random_pseudo_bytes("64"));
|
||||
}
|
||||
|
||||
// Lowercase the cipher
|
||||
$cipherMethod = strtolower($cipherMethod);
|
||||
$this->cipherMethod = strtolower($cipherMethod);
|
||||
|
||||
// Check if the encryption method is valid
|
||||
if (!in_array($cipherMethod, openssl_get_cipher_methods())) {
|
||||
if (!in_array($this->cipherMethod, openssl_get_cipher_methods())) {
|
||||
// Cypher was not in the available ciphers list.
|
||||
$this->errorLog[] = "[" . __LINE__ . "]" . $this->cipherMethod . " isn't a valid cipherMethod.";
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$this->key = $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key that the instance is currently using, really useful for when you randomly generate it!
|
||||
* @return string The key of the instance
|
||||
*/
|
||||
public function getKey() {
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the encryption blocks for files
|
||||
*/
|
||||
public function getEncryptionBlocks() {
|
||||
return $this->blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redefine the encryption blocks size
|
||||
*/
|
||||
public function setEncryptionBlocks(int $size = 10000) {
|
||||
// Make sure the size has a minimum of blocks read.
|
||||
if ( $size < 1 ) $size = 1;
|
||||
|
||||
// Set the local blocks
|
||||
$this->blocks = $size;
|
||||
}
|
||||
|
||||
public function getErrors() {
|
||||
return $this->errorLog;
|
||||
}
|
||||
|
||||
// #region String Encryption
|
||||
|
||||
/**
|
||||
* @param string $data The data to be encrypted, this can only encrypt strings.
|
||||
* @param bool $integrity_check Check if the encrypted data can also be decypted, this will take 2x more time to process the data, but will make 100% sure that the data is safe and can be decrypted.
|
||||
*/
|
||||
function encryptData(string $data, bool $integrity_check = TRUE) {
|
||||
// Grab the key from self-reference
|
||||
$key = $this->key;
|
||||
|
||||
// To encrypt a string
|
||||
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipherMethod));
|
||||
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($this->cipherMethod));
|
||||
|
||||
// Encrypt the data
|
||||
$encryptedData = openssl_encrypt($data, $cipherMethod, $key, OPENSSL_RAW_DATA, $iv);
|
||||
$encryptedData = openssl_encrypt($data, $this->cipherMethod, $key, OPENSSL_RAW_DATA, $iv);
|
||||
|
||||
// Append the iv to the encrypted data
|
||||
$encryptedData = $iv . $encryptedData;
|
||||
|
@ -29,52 +112,142 @@ function encryptData( string $data, string $key, string $cipherMethod = 'AES-256
|
|||
$encryptedData = base64_encode($encryptedData);
|
||||
|
||||
// Check if we should verify the integrity of the encryption
|
||||
if ( $integrity_check === TRUE ) {
|
||||
if ($integrity_check === TRUE) {
|
||||
// Test for decryption validity
|
||||
if ( md5(decryptData($encryptedData, $key, $cipherMethod)) === md5($data) ) {
|
||||
if (md5($this->decryptData($encryptedData)) === md5($data)) {
|
||||
// Put the output in the result
|
||||
return $encryptedData;
|
||||
} else {
|
||||
// Assign the output to the result
|
||||
$this->errorLog[] = "[" . __LINE__ . "]" . "Failed integrity check";
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
// Simply return the results
|
||||
return $encryptedData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data The data to be encrypted, this can only encrypt strings.
|
||||
* @param string $key The key to use to encrypt the data, this key should be generated using the openssl_random_pseudo_bytes
|
||||
* @param string $cipherMethod The cypher method to use in the encryption process, these can be checked using
|
||||
*/
|
||||
function decryptData( string $data, string $key, string $cipherMethod = 'AES-256-CBC' ) {
|
||||
|
||||
// Lowercase the cipher
|
||||
$cipherMethod = strtolower($cipherMethod);
|
||||
|
||||
// Check if the encryption method is valid
|
||||
if (!in_array($cipherMethod, openssl_get_cipher_methods())) {
|
||||
// Cypher was not in the available ciphers list.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data The data to be encrypted, this can only encrypt strings.
|
||||
*/
|
||||
function decryptData(string $data) {
|
||||
// Grab the key from self-reference
|
||||
$key = $this->key;
|
||||
|
||||
// base64 decode the data.
|
||||
$data = base64_decode($data);
|
||||
|
||||
// Get the length of the IV
|
||||
$iv_length = openssl_cipher_iv_length($cipherMethod);
|
||||
$iv_length = openssl_cipher_iv_length($this->cipherMethod);
|
||||
// Get the IV from the decoded data
|
||||
$iv = substr($data,0,$iv_length);
|
||||
$iv = substr($data, 0, $iv_length);
|
||||
|
||||
// Get the encrypted string from the data
|
||||
$data = substr($data, $iv_length);
|
||||
|
||||
// Decrypt the data
|
||||
$data = openssl_decrypt($data,$cipherMethod,$key, OPENSSL_RAW_DATA, $iv);
|
||||
$data = openssl_decrypt($data, $this->cipherMethod, $key, OPENSSL_RAW_DATA, $iv);
|
||||
|
||||
|
||||
// Return the data
|
||||
return $data;
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
|
||||
/**
|
||||
* File encryption should only be used on larger files ( 512kb+ )
|
||||
* Since the string encryption will work better on the smaller files, since it's all
|
||||
* in the memory, this simlpy pipes the file through itself, for every 1Mb file it only uses ~0.1Mb of memory with the default block size
|
||||
*/
|
||||
// #region File Encryption
|
||||
|
||||
public function encryptFile(string $fileInput, string $fileOutput, bool $integrity_check = TRUE) {
|
||||
|
||||
// To encrypt a string
|
||||
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($this->cipherMethod));
|
||||
|
||||
// Try and open the destionation
|
||||
if ( $fout = fopen($fileOutput, 'w') ) {
|
||||
// Try and open the input file
|
||||
if ($fin = fopen($fileInput, 'rb') ) {
|
||||
// Place the IV at the beginning of the file for later decryption
|
||||
fwrite($fout, $iv);
|
||||
|
||||
// Start reading from the input file
|
||||
while ( !feof($fin) ) {
|
||||
// Read in blocks of 16
|
||||
$plaintext = fread($fin, 16 * $this->blocks);
|
||||
$ciphertext = openssl_encrypt($plaintext, $this->cipherMethod, $this->key, OPENSSL_RAW_DATA, $iv);
|
||||
// Use the first 16 bytes of the ciphertext as the next initialization vector
|
||||
$iv = substr($ciphertext, 0, 16);
|
||||
fwrite($fout, $ciphertext);
|
||||
}
|
||||
|
||||
// Close the input file
|
||||
fclose($fin);
|
||||
|
||||
} else {
|
||||
$this->errorLog[] = "[" . __LINE__ . "]" . "Could not open input file for reading.";
|
||||
// Close the output file
|
||||
fclose($fout);
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->errorLog[] = "[" . __LINE__ . "]" . "Could not open file output path for writing.";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Close the output file
|
||||
fclose($fout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileInput The path to the encrypted file we want to decrypt
|
||||
* @param string $fileOutput The path to where to place the decrypted content
|
||||
*/
|
||||
public function decryptFile(string $fileInput, string $fileOutput) {
|
||||
|
||||
|
||||
// Try and open the destionation
|
||||
if ( $fout = fopen($fileOutput, 'w') ) {
|
||||
// Try and open the input file
|
||||
if ($fin = fopen($fileInput, 'rb') ) {
|
||||
// Get the IV from the beginning of the file
|
||||
$iv = fread($fin, openssl_cipher_iv_length($this->cipherMethod));
|
||||
|
||||
while (!feof($fin)) {
|
||||
// we have to read one block more for decrypting than for encrypting
|
||||
$ciphertext = fread($fin, 16 * ($this->blocks + 1));
|
||||
$plaintext = openssl_decrypt($ciphertext, $this->cipherMethod, $this->key, OPENSSL_RAW_DATA, $iv);
|
||||
// Use the first 16 bytes of the ciphertext as the next initialization vector
|
||||
$iv = substr($ciphertext, 0, 16);
|
||||
fwrite($fout, $plaintext);
|
||||
}
|
||||
|
||||
// Close the input file
|
||||
fclose($fin);
|
||||
} else {
|
||||
$this->errorLog[] = "[" . __LINE__ . "]" . "Could not open file input path for writing.";
|
||||
return false;
|
||||
}
|
||||
// Close the output file
|
||||
fclose($fout);
|
||||
return 1;
|
||||
} else {
|
||||
$this->errorLog[] = "[" . __LINE__ . "]" . "Could not open file output path for writing.";
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
Reference in New Issue