Crypto++ extension happenings
| From: | J Smith | Date: | Sun, 17 Mar 2002 00:35:17 +0000 |
| Subject: | Crypto++ extension happenings | ||
| Groups: | php.dev | ||
| Request: | Send a blank email to php-dev+get-81367@lists.php.net to get a copy of this message | ||
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