Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

added a README and introduced keygen()

  • Loading branch information...
commit 754d8ab4d81229faa8224173ab61ee17bb10383d 1 parent 2f1f11d
ndejong authored

Showing 3 changed files with 218 additions and 12 deletions. Show diff stats Hide diff stats

  1. +63 12 CryptClass.php
  2. +142 0 README
  3. +13 0 tests/crypt_class_key_tests.php
75 CryptClass.php
@@ -16,9 +16,11 @@ class Crypt {
16 16 /**
17 17 * Default CryptAesClass settings
18 18 */
19   - static public $compress = true;
20   - static public $url_safe = true;
21   - static public $base64_encode = true;
  19 + static public $compress = true; // compress the data before encrypting
  20 + static public $base64_encode = true; // base64_encode the encrypted data
  21 + static public $url_safe = true; // make the encrypted data url_safe
  22 + static public $use_keygen = true; // transform a user supplied key into a key using more of the available keyspace
  23 + static public $keygen_length = 32; // where 32 = AES256, 24 = AES192, 16 = AES128
22 24 static public $test_decrypt_before_return = false;
23 25
24 26 /**
@@ -58,6 +60,17 @@ static public function decrypt($data,$key=null) {
58 60 }
59 61
60 62 /**
  63 + * keygen
  64 + *
  65 + * @param string $data
  66 + * @return string
  67 + */
  68 + static public function keygen($clear_text,$length=32) {
  69 + self::__init(null);
  70 + return self::$CryptAesClass->keygen($clear_text,$length);
  71 + }
  72 +
  73 + /**
61 74 * __init
62 75 *
63 76 * @param string $key
@@ -71,9 +84,11 @@ static private function __init($key) {
71 84
72 85 // Setup the options for CryptAesClass
73 86 $options = array(
74   - 'compress' => self::$compress,
75   - 'url_safe' => self::$url_safe,
76   - 'base64_encode' => self::$base64_encode,
  87 + 'compress' => self::$compress,
  88 + 'base64_encode' => self::$base64_encode,
  89 + 'url_safe' => self::$url_safe,
  90 + 'use_keygen' => self::$use_keygen,
  91 + 'keygen_length' => self::$keygen_length,
77 92 'test_decrypt_before_return' => self::$test_decrypt_before_return,
78 93 );
79 94
@@ -128,9 +143,11 @@ function __construct($key=null,$options=array()) {
128 143 // The options to use
129 144 $this->options = array_merge(
130 145 array(
131   - 'compress' => true,
132   - 'url_safe' => true,
133   - 'base64_encode' => true,
  146 + 'compress' => true, // compress the data before encrypting
  147 + 'base64_encode' => true, // base64_encode the encrypted data
  148 + 'url_safe' => true, // make the encrypted data url_safe
  149 + 'use_keygen' => true, // transform a user supplied key into a key using more of the available keyspace
  150 + 'keygen_length' => 32, // where 32 = AES256, 24 = AES192, 16 = AES128
134 151 'test_decrypt_before_return' => false,
135 152 ),
136 153 (array)$options
@@ -238,6 +255,30 @@ public function decrypt($data_in,$key=null) {
238 255 }
239 256
240 257 /**
  258 + * keygen()
  259 + *
  260 + * generates the same return value for any given input value
  261 + *
  262 + * @param string $clear_text
  263 + */
  264 + public function keygen($clear_text,$length=null) {
  265 +
  266 + // Set the length of the key we will generate here
  267 + if(empty($length)) {
  268 + $length = $this->options['keygen_length'];
  269 + }
  270 +
  271 + // The hard coded first character to pick from the $string below
  272 + $first_character_position = 20;
  273 +
  274 + // The generated string based on the known $clear_text
  275 + $string = base64_encode(base64_encode(md5($clear_text,true).md5($clear_text,true)));
  276 +
  277 + // The key to return based on the first position and the required length
  278 + return substr($string,$first_character_position,$length);
  279 + }
  280 +
  281 + /**
241 282 * _decryptData
242 283 *
243 284 * @param string $data_with_iv_suffix
@@ -249,9 +290,14 @@ protected function _decryptData($data_with_iv_suffix,$key) {
249 290
250 291 $this->_preChecks($key);
251 292
  293 + // Transform the user key into something that uses a wider spectrum of the possible keyspace
  294 + if($this->options['use_keygen']) {
  295 + $key = $this->keygen($key,$this->options['keygen_length']);
  296 + }
  297 +
252 298 // encrypt the data
253 299 $data = mcrypt_decrypt(
254   - MCRYPT_RIJNDAEL_128, // AES is block size 128 only
  300 + MCRYPT_RIJNDAEL_128, // AES is RIJNDAEL with a block size of 128 bits only
255 301 $key, // secret key - NOTE: key size determines AES_128, AES_192 or AES_256
256 302 substr($data_with_iv_suffix,0,(strlen($data_with_iv_suffix)-16)), // the data with the last 128 bytes (16 chars) removed since that part is the iv
257 303 MCRYPT_MODE_CBC, // cipher mode
@@ -279,12 +325,17 @@ protected function _encryptData($data,$key) {
279 325
280 326 $this->_preChecks($key);
281 327
  328 + // Transform the user key into something that uses a wider spectrum of the possible keyspace
  329 + if($this->options['use_keygen']) {
  330 + $key = $this->keygen($key,$this->options['keygen_length']);
  331 + }
  332 +
282 333 // Choose a good random iv -> 16chars * 8bits = 128 block size for MCRYPT_RIJNDAEL_128
283   - $iv = substr(str_shuffle(base64_encode( md5(mt_rand(10000000,99999999)).md5(microtime(true)) )),0,16);
  334 + $iv = $this->keygen(md5(mt_rand(0,1000000000)).md5(mt_rand(0,1000000000)),16);
284 335
285 336 // encrypt the data
286 337 $data = mcrypt_encrypt(
287   - MCRYPT_RIJNDAEL_128, // AES is block size 128 only
  338 + MCRYPT_RIJNDAEL_128, // AES is RIJNDAEL with a block size of 128 bits only
288 339 $key, // secret key - NOTE: key size determines AES_128, AES_192 or AES_256
289 340 $data, // data to encrypt
290 341 MCRYPT_MODE_CBC, // cipher mode
142 README
... ... @@ -0,0 +1,142 @@
  1 +/****************************************************************************
  2 + * Crypt / CryptAesClass / CryptClass
  3 + * Nicholas de Jong - http://nicholasdejong.com - https://github.com/ndejong
  4 + * 27 November 2011
  5 + *
  6 + * @author Nicholas de Jong
  7 + * @copyright Nicholas de Jong
  8 + ****************************************************************************/
  9 +
  10 +Q: What's this all about?
  11 +A: Crypt / CryptAesClass / CryptClass are a set of PHP classes that greatly
  12 + simplifies encrypting and decrypting data (strings, arrays, bool, objects) in
  13 + PHP allowing you to get on with developing cool stuff.
  14 +
  15 +Q: What kind of data can I encrypt?
  16 +A: Anything you can put into a PHP variable, which means, strings, binaries,
  17 + bools, arrays, objects.
  18 +
  19 +Q: What does the encrypted data look like?
  20 +A: A URL safe plain string (see more below)
  21 +
  22 +Q: How do I use it?
  23 +A: There are several ways to work with Crypt and CryptAesClass, perhaps the easiest
  24 + is as a static function:-
  25 +
  26 + include_once('CryptClass.php');
  27 + Crypt::$key = 'hello world';
  28 + $encrypted = Crypt::encrypt($my_data);
  29 + $decrypted = Crypt::decrypt($encrypted);
  30 +
  31 + You may like to specify the key when you make the function call instead:-
  32 +
  33 + $encrypted = Crypt::encrypt($my_data,'hello world');
  34 + $decrypted = Crypt::decrypt($encrypted,'hello world');
  35 +
  36 + Alternatively you may take a traditional class based approach:-
  37 +
  38 + include_once('CryptClass.php');
  39 + $Crypt = new CryptAesClass('hello world');
  40 + $encrypted = $Crypt->encrypt($my_data);
  41 + $decrypted = $Crypt->decrypt($encrypted);
  42 +
  43 + Again you can specify the key when you make the function call if you like:-
  44 +
  45 + $encrypted = $Crypt->encrypt($my_data,'hello world');
  46 + $decrypted = $Crypt->decrypt($encrypted,'hello world');
  47 +
  48 +Q: How can I use this in CakePHP (or other frameworks)?
  49 +A: (step 1) Copy or symlink in the CryptClass.php file to Lib/CryptClass.php
  50 + (step 2) Load CryptClass.php via bootstrap.php or core.php like this:-
  51 +
  52 + App::uses('CryptClass', 'Lib');
  53 + Crypt::$key = Config::read('Security.salt');
  54 +
  55 + (step 3) You can now just use it like this:-
  56 +
  57 + $encrypted = Crypt::encrypt($my_data);
  58 + $decrypted = Crypt::decrypt($encrypted);
  59 +
  60 +Q: What about the mcrypt libraries in PHP?
  61 +A: The mcrypt libraries are fantastic, and these classes use mcrypt! The thing
  62 + about mcrypt though is that the developer actually needs to learn something
  63 + about crypto to use it effectively without making mistakes and even then it's
  64 + possible to unknowingly overlook something.
  65 +
  66 +Q: What does the encrypted data look like again?
  67 +A: By default the encrypted data is URL safe base64 encoded which means you can
  68 + pass an array/object (anything) back as a part of an off-site callback, which
  69 + was the original motivation for wanting this functionality in the first place.
  70 + For example, say you want some kind of trusted/secure information coming back
  71 + to you in a Paypal return URL, that's no problem with a return URL that looks
  72 + something like this http://hostname/path/<enc_data>
  73 + You just grab the <enc_data> string and decrypt it to obtain whatever data you
  74 + were working with in the first place - makes this a great way to manage state
  75 + when passing back and forth between off-site services with callbacks, Amazon
  76 + S3 uploads also come to mind here.
  77 +
  78 +Q: Do you compress the data before you encrypt it?
  79 +A: By default yes, though you can disable this with an option if you want.
  80 +
  81 +Q: What configuration options exist?
  82 +A: All deliberately kept simple, the default settings are listed here:-
  83 +
  84 + $options = array(
  85 + 'compress' => true, // compress the data before encrypting
  86 + 'base64_encode' => true, // base64_encode the encrypted data
  87 + 'url_safe' => true, // make the encrypted data url_safe
  88 + 'use_keygen' => true, // transform a user supplied key into a key using more of the available keyspace
  89 + 'keygen_length' => 32, // where 32 = AES256, 24 = AES192, 16 = AES128
  90 + 'test_decrypt_before_return' => false,
  91 + ),
  92 +
  93 + You can apply these options when you instantiate the class using the second
  94 + parameter, like this:-
  95 +
  96 + $Crypt = new CryptAesClass($key,$options);
  97 +
  98 + Or if using the static class approach, you set them like this:-
  99 +
  100 + Crypt::$compress = true;
  101 + Crypt::$url_safe = true;
  102 + Crypt::$base64_encode = true;
  103 + Crypt::$test_decrypt_before_return = false;
  104 +
  105 +Q: What encryption does it use, can it be broken?
  106 +A: AES128, AES192, AES256 depending on the key length the developer uses for
  107 + encryption - AES is the US data encryption standard, it is considered to be
  108 + very resilient to attack. By default CryptAesClass uses AES256.
  109 +
  110 +Q: Your _encryptData() function says it is using something called Rijndael?
  111 +A: Rijndael with a block size 128 bits and key bit of lengths 128, 192 or 256 are
  112 + the AES encryption standard. We use AES because it is a trusted encryption
  113 + scheme that has been peer reviewed and examined at length.
  114 +
  115 +Q: What's all this business about key length?
  116 +A: You *MUST* use a key length of 128 or 192 or 256 bits, this is part of the way
  117 + that AES (ie Rijndael) works. Because 256 bits = 32 bytes * 8 bits per byte
  118 + a naive way to "convert" clear text passwords into 256 bits is to just md5()
  119 + your clear text, ie $key = md5('my cool password') - the result will always be
  120 + a 32 character string which is what you are looking for if you want to use
  121 + AES256.... however what you are actually doing is reducing the keyspace to use
  122 + because md5() will only provide you with a string of characters where each
  123 + character is between 0 and f. The available keyspace can be any character
  124 + (including non printable) ones. To address this problem the Crypt::keygen()
  125 + function is made to automatically transform the user supplied key into a key
  126 + that uses a much wider range (but not all) of the possible keyspace, you can
  127 + change this by setting the 'use_keygen' option to false.
  128 +
  129 +Q: Dude, AES was chosen by the US government!
  130 +A: Yep, if that worries you... oh I'm not going to bother, good luck.
  131 +
  132 +Q: What's the deal with the old CryptClass?
  133 +A: In short, there was a glaring problem, my old CryptClass used a static IV and
  134 + it was not as easy to use as this.
  135 +
  136 +Q: Why is CryptAesClass better than the old CryptClass?
  137 +A: Other than addressing the IV issue this version is simpler to use and comes
  138 + with a test harness that 100% passes - I discovered after testing there was a
  139 + strange edge case where the padded null bytes that are introduced through the
  140 + encrypt process would sometimes cause gzuncompress to fail, ouch! Also this
  141 + version is binary safe due to the use of PHP serialize() rather than json.
  142 +
13 tests/crypt_class_key_tests.php
... ... @@ -0,0 +1,13 @@
  1 +#!/usr/bin/php
  2 +<?php
  3 +
  4 +include_once('../CryptClass.php');
  5 +
  6 +for($count=0;$count<1;$count++) {
  7 +
  8 + $clear_text = microtime(true).$count;
  9 +
  10 + echo Crypt::keygen($clear_text,32)."\n";
  11 + echo Crypt::keygen($clear_text,24)."\n";
  12 + echo Crypt::keygen($clear_text,16)."\n";
  13 +}

0 comments on commit 754d8ab

Please sign in to comment.
Something went wrong with that request. Please try again.