As I reluctantly mentioned a few weeks ago, I'm working on a PHP crypto 
extension that uses Crypto++, a C++ library that provides implementations 
for a bunch of crypto and hash algorithms. I was reluctant to bring it up 
because I didn't know if I was going to finish it at all, and I didn't want 
to get anybody's hopes up. The rationale behind the extension was partially 
because we need a crypto library at work that we can use on win32 platforms 
for a Windows Media Services plugin and one that PHP can use to create 
ciphertext compatible with the aforementioned plugin. Unfortunately, 
libmcrypt now requires cygwin on win32, and that sort of depedency would be 
hellish for a WMS plugin. Crypto++ works fine on Windows using VC++, and 
also works fine on UNIX systems using g++. Thus, a crypto extension for PHP 
that works on both major platforms.

Well, things have come along a bit further, and although the extension is 
still quite a way from being complete, it's getting there. The basic 
structure of the extension goes something like this:

- there's a base class in C++ that a template inherits from that provides 
the basic members and methods needed to encrypt and decrypt messages, along 
with all of the usual methods that allow you to set the IV for a crypto 
algorithm, the secret key, key length, mode (CBC, ECB, etc.), and 
plaintext. The base class is pure abstract virtual, as is the template that 
encapsulates it. (The template may seem a bit unnecessary, but it's used to 
set things like the block size for ciphers with variable block sizes and 
such. The base class it derives from makes things easier when dealing with 
C++'s templates, which allows it to compile on several compilers, like g++ 
and VC++, which all seem to disagree on how to use templates.)

- from there, there are a bunch of classes that provide interfaces to the 
various crypto algorithms, like Blowfish, 3-Way, Rijnadael, etc. So far, 
I've only implemented those three algorithms, but others will be done 
eventually, like the various CAST ciphers, RC5, etc. So far I've only 
worked with block ciphers -- I haven't started anything with the stream 
ciphers, like ARC4, WAKE, etc. All of the more popular block cipher modes 
are working, like OFB, CFB, several CBC padding modes, etc.

- on the hash side, there's a base hash class, from which various other 
classes derive that provide interfaces to the hash algorithms. So far, MD5, 
MD2, Panama and RIPEMD160 are the only hashes I've implemented; HAVAL and 
others will follow. (Although, for whatever reason, HAVAL is being a bitch 
and doesn't like compiling properly. Don't know why yet.)

Besides all of the C++ stuff, I've been working on C functions to access 
from the PHP code. (extern "C" stuff, that all jazz.) They're mostly 
complete for the cipher side; I haven't started on C stuff for the hashes 
yet.

I'm thinking the PHP fuctions themselves will work much like the mcrypt 
library, something like described below. These function names are all 
subject to change, obviously, since I haven't started writing this portion 
of the project yet. I may end up going the object oriented route using PHP 
classes; I'm not sure yet. Depends on feedback. (And more importantly, what 
work wants -- please remember, this extension is being worked on for my 
job; the fact that I can allow everyone else to use it as free software is 
a luxury.)


- resource cryptopp_create_cipher(int cipher) -- cipher is a constant that 
refers to the cipher algorithm, like CRYPTOPP_CIPHER_BLOWFISH, or 
CRYPTOPP_CIPHER_AES for AES/Rijnadael. The function returns a PHP resource 
that will be used for the other functions, or false on error.

- bool cryptopp_destroy_cipher(resource cipher) -- closes a cipher.

- bool cryptopp_set_rand_iv(resource cipher, int length [, int rand]) -- 
creates a random IV for cipher of the length specified. This is created via 
/dev/urandom or /dev/random on systems that support them; otherwise, it 
uses the standard rand() function. The rand argument can be used to specify 
the method used to create the IV, i.e. CRYPTOPP_RAND_URANDOM for 
/dev/urandom, CRYPTOPP_RAND_RAND for the rand() function, etc. Returns true 
on success, false on error. By default, win32 systems will likely use the 
rand() function, while systems that can provide either /dev/random or 
/dev/urandom will use one of them, preferably urandom.

- bool cryptopp_set_iv(resource cipher, string iv [, bool hex]) -- add a 
specific IV to the resource. hex is used to determine whether the IV being 
added is being given in hex or in binary, with binary being the default. 
True/false on success/error.

- string cryptopp_get_iv(resource cipher [, bool hex]) -- returns the IV of 
resource or false on error. hex specifies whether the IV should be returned 
in binary or in hex, with binary being the default. false on error.

- bool cryptopp_set_mode(resource cipher, int mode) -- sets the mode of the 
cipher, i.e. CRYPTOPP_MODE_PADDED_CBC, CRYPTOPP_MODE_ECB, etc. false on 
error, true on success.

- int cryptopp_get_mode(resource cipher) -- gets the mode the current 
cipher is using, or false on error.

- bool cryptopp_set_plaintext(resouce cipher, string plaintext) -- set the 
plaintext of the cipher. true/false on success/error. I may add a hex 
argument here, as well as a length argument.

- string cryptopp_get_plaintext(resource cipher [, bool hex]) -- get the 
plaintext of the resource. false on error. Returns in binary by default. 
(Might remove the hex argument here.)

- bool cryptopp_set_ciphertext(resource cipher, string ciphertext [, bool 
hex) -- set the ciphertext of the resource. hex determines whether the 
input is in hex or binary, with binary being the default. Returns 
true/false on success/error.

- string cryptopp_get_ciphertext(resource cipher [, bool hex]) -- get the 
ciphertext of the resource. Binary by default. Returns false on error.

- bool cryptopp_set_key(resource cipher, string key [, bool hex]) -- set 
the key, yadda, yadda.

- string cryptopp_get_key(resource cipher [, bool hex]) -- returns the key 
in bin or hex, bin the default, returns false on error.

- bool cryptopp_set_keylength(resource cipher, int keylength) -- sets the 
keylength of the cipher, which may be different than the actual length of 
the key being used. (For instance, you can have a secret key that is in 
reality 32 characters long, but only the first 16 of those characters are 
actually used. 3-way is like this, as it is uses a fixed keylength of 12.) 
True/false on succes/error.

- int cryptopp_get_keylength(resource cipher) -- gets the keylength of the 
resource, or false on error. This should always be checked after setting 
the keylength, as it might not set to what you're expecting. For instance, 
Rijnadael uses a variable keylength of 16, 24 or 32, and if you try to set 
they keylength to something else, like 56, it rounds the keylength off to 
the next lowest correct keylength (32). Likewise, setting a keylength of 12 
in reality sets the keylength to 16. Maybe a notice or warning should be 
raised here...


For variable block-size ciphers, there will be two matching functions to 
set and get those -- cryptopp_set_block_size() and 
cryptopp_get_block_size().


- bool cryptopp_encrypt(resource cipher) -- encrypt the resource using the 
settings provided above. This will set the ciphertext to something you can 
get using cryptopp_get_ciphertext(). Returns true/false as usual.

- bool cryptopp_decrypt(resource cipher) -- same as above, but obviously it 
decrypts ciphertext into plaintext.


There will be a few other functions for the crypto half of the project, but 
those are the main ones.

For the hash side of things, there will be functions similar to those 
above. I may call them hashpp_* to differentiate from the crypto functions. 
Not sure yet. For the sake of example, though...

- resource hashpp_create_hash(int hash) -- returns a resource to be used 
with the hash functions. hash is the constant refering to one of the hash 
algorithms, like CRYPTOPP_HASH_MD5, etc. Returns false on error.

- bool hashpp_destroy_hash(resource hash) -- destroys a hash resource.

- bool hashpp_set_plaintext(resource hash, string plaintext [, bool hex]) 
-- same deal as cryptopp_add_plaintext(). Similarly, hashpp_get_plaintext() 
will get the plaintext.

- bool hashpp_set_hashtext(resource hash, string hashtext [, bool hex]) -- 
sets the hashtext of the resource. Naturally, you can't convert hashtext 
back to plaintext, but this will still be useful as we'll see below. 
hashpp_get_hashtext() compliments the function.

- bool hashpp_hash(resource hash) -- hashes the plaintext into hashtext, 
which you can get using hashpp_get_hashtext().

- int hashpp_validate(resource hash) -- if you have both the plaintext and 
the hashtext and you want to see quickly if the hashtext provided matches 
the plaintext for the current algorithm, use this function. Returns a 
positive value if they match, 0 if they don't, and false (or maybe -1) on 
error, as a bad match doesn't constitute a real error.


There may be other functions added, specifically for hashes with multiple 
block sizes and such.

Other functions that will find their way into the extension eventually -- 
functions for stream ciphers, maybe some public/private key stuff. 

So basically, you'd use the extension thusly (without any error checking):

<?php

$crypto = cryptopp_create_cipher(CRYPTOPP_CIPHER_BLOWFISH);
cryptopp_set_plaintext($crypto, "this is plaintext");
cryptopp_set_rand_iv($crypto, 16);
cryptopp_set_mode($crypto, CRYPTOPP_MODE_PADDED_CBC);
cryptopp_set_key($crypto, "this is a secret key");
cryptopp_encrypt($crypto);

print "Plaintext: " . cryptopp_get_plaintext($crypto) . "<br>\n";
print "IV: " . cryptopp_get_iv($crypto, true) . "<br>\n";
print "Secret key: " . cryptopp_get_key($crypto) . "<br>\n";
print "Ciphertext: " . cryptopp_get_ciphertext($crypto, true) . "<br>\n";

crypto_destroy_cipher($crypto);

?>

Which gives:

Plaintext: this is plaintext
IV: 0B273F291168170A265F755401602A7B
Secret key: this is a secret key
Ciphertext: 1EC05EEB11F127C3CAF929D280E6296EF54679E7F6CAD910

Decrypting is similar -- just set the ciphertext using 
cryptopp_set_ciphertext(), call cryptopp_decrypt() and check out 
cryptopp_get_plaintext(). (Obviously, set the IV, mode and secret key 
accordingly before calling cryptopp_decrypt().) The hash portion of the 
extension works similarly, but you obviously can't retrieve the plaintext 
from a hash. (At least, definitely not easily.)


There is a lot left to do on this extension, so it's not going to be ready 
for a while. I just figued I would let people know it's still being worked 
on. I have no idea when I'll finish the extension, so don't hold your 
breath if you're interested. 

Comments are appreciated.

J


-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to