diff --git a/ciform/trunk/src/ciform.php b/ciform/trunk/src/ciform.php deleted file mode 100644 index 0ce182a..0000000 --- a/ciform/trunk/src/ciform.php +++ /dev/null @@ -1,159 +0,0 @@ -"; - - // $newData is going to be decoded by one of the following filters - // then, it'll be encoded to the destination base - $newData = $data; - - // this flag means this parameter is handled by this library - if ( eregi('^'.CIFORM_REQUEST_PREFIX.'(.*)$',$data,$matches) > 0 ) - { - $newData = ciform_decode($matches[1],$keyPair); - } - - // this is just salt that adds randomness to the string : it can be removed safely - else if ( eregi('^salt[^:]*:(.*)$',$data,$matches) > 0 ) - { - $newData = ciform_decode($matches[1],$keyPair); - } - - // this is an hexadecimal string - else if ( eregi('^(hex:|0x)(.*)$',$data,$matches) > 0 ) - { - $tmpData = ciform_decode($matches[2],$keyPair); - $newData = pack("H*",$tmpData); - } - - // this a base64 encoded string - else if ( eregi('^(base64|b64):(.*)$',$data,$matches) > 0 ) - { - $tmpData = ciform_decode($matches[2],$keyPair); - if ( $base == 64 ) - { - // we're already in the right radix, don't go further - // (same can be done with other bases too, but right now we only need this one) - return $tmpData; - } - $newData = base64_decode($tmpData); - } - - // this is an encrypted message - else if ( eregi('^'.CIFORM_KEYTYPE.':(.*)(:.+)?$',$data,$matches) > 0 ) - { - $tmpData = ciform_decode($matches[1],$keyPair,64); - - // decrypts the data using the configured module - $func = "ciform_".CIFORM_KEYTYPE."_decrypt"; - $newData = ciform_decode( $func($tmpData,$keyPair), $keyPair ); - } - - // FIXME : do better recursion : each case should return ciform_decode($tmpData) except if no encoding is detected (which then ends the recursion) - // FIXME : put each case in a different 'decoder' class - - // encodes the data into the desired base - switch( $base ) - { - case 64: - return base64_encode($newData); - default: - return $newData; - } - } - - - - function ciform_decryptParam( $data, $keyPair ) - { - if ( gettype($data) == "string" && eregi('^'.CIFORM_REQUEST_PREFIX.'(.*)$',$data,$matches) > 0 ) - { - return ciform_decode($matches[1],$keyPair); - } - return $data; - } - - - - function ciform_decryptParams( $request, $keyPair ) - { - $decoded = array(); - - // accepts encrypted data from the client - foreach ( $request as $key => $value ) - { - $newValue = ciform_decryptParam($value,$keyPair); - $decoded[$key] = $newValue; - } - - return $decoded; - } - - - - // returns the protocol of this script - if ( isset($_REQUEST[CIFORM_REQUEST_PROTOCOL]) ) - { - $func = "ciform_".CIFORM_KEYTYPE."_getProtocol"; - $name = $_REQUEST[CIFORM_REQUEST_PROTOCOL]; - header("Content-type: text/plain"); - // if a name was given, use it to name the variable : - // the result may be used as a full (java)script - if ( trim($name) != "" ) { - echo "var $name = " . $func() . ";"; - } - // if no name was given, just print the JSON value : - // the result may be used as an Ajax response - else { - echo $func(); - } - exit; - } - - - - // makes sure the key is accessible - // TODO : instanciate the given crypto class, - // which stores itself the key and all other specific data - // then, move the following code to the correct sub-script - if ( !isset($_SESSION[CIFORM_SESSION]) ) - { - $_SESSION[CIFORM_SESSION] = array(); - } - if ( !isset($_SESSION[CIFORM_SESSION][CIFORM_SESSION_KEYPAIR]) ) - { - // the encryption module's name is given by the defined key type - $func = "ciform_".CIFORM_KEYTYPE."_getKeyPair"; - $_SESSION[CIFORM_SESSION][CIFORM_SESSION_KEYPAIR] = $func(); - } - - - - if ( CIFORM_AUTODECRYPT ) - { - $_REQUEST = ciform_decryptParams($_REQUEST,$_SESSION[CIFORM_SESSION][CIFORM_SESSION_KEYPAIR]); - } -?> \ No newline at end of file diff --git a/ciform/trunk/src/ciform/ciform.php b/ciform/trunk/src/ciform/ciform.php new file mode 100644 index 0000000..93050cc --- /dev/null +++ b/ciform/trunk/src/ciform/ciform.php @@ -0,0 +1,176 @@ + +// + +/** + * This is the PHP server side library for Ciform + * @package ciform + */ + + +// TODO : load all files in ciform/schemes +require_once "ciform/schemes/core.php"; +require_once "ciform/schemes/rsa.php"; + + + +// +// CONSTANTS DEFINITIONS +// + + +// Comment out the following line to enable debug traces from this script +//define("CIFORM_DEBUG",TRUE); + +/** Prefix for the session variables for this library */ +define("CIFORM_SESSION","CIFORM"); + +/** + * Version number of the Ciform protocol implemented here + * @type string + */ +define("CIFORM_PROTOCOL_VERSION","0"); + +/** If the request contains a parameter with this name, this script will print out the Ciform protocol rather than doing decryption */ +define("CIFORM_REQUEST_PROTOCOL","protocol"); + +if ( ! defined("CIFORM_AUTODECRYPT") ) + /** Define this constant to TRUE in caller script to enable transparent decryption of the request */ + define("CIFORM_AUTODECRYPT", TRUE ); + +/** + * List of the schemes taken in account for auto decryption.
+ * + * Comment out the schemes you don't use in the following list.
+ * Add each (custom) scheme you want to the list to handle more schemes.
+ */ +define("CIFORM_SCHEMES_DEFAULT",array( + new Ciform_schemes_Ciform(), + new Ciform_schemes_Base16(), + new Ciform_schemes_Base64(), + new Ciform_schemes_RSA() + ); + + + +// +// CLASS 'ciform_Server' +// + + + +/** + * This class handles everything about Ciform on the server side. + */ +class ciform_Server +{ + /** + * @var Ciform_CipherChain Holds the decoders to use on the request parameters + * @access private + */ + var $codec; + + + function ciform_Server( $schemes ) + { + // registers all known schemes into a decoder chain + $this->codec = new Ciform_CipherChain($schemes); + } + + + + /** + * Decrypts all recognized parameters from the given request + * + * @param $request An associative array containing the request parameters (use $_REQUEST) + * @return array A copy of the input array, with values for all handled parameters decrypted + */ + function decodeParams( $request ) + { + $decoded = array(); + + // accepts encrypted data from the client + foreach ( $request as $key => $value ) + { + $decoded[$key] = $this->codec->decode($value); + } + + return $decoded; + } + + + + /** + * @return array the current Ciform protocol + */ + function getProtocol() + { + // FIXME : serverURL must be absolute, so scripts can call it from other servers + $serverURL = $_SERVER['PHP_SELF']; + + $schemes = array(); + foreach ( $this->codec->ciphers as $cipher ) + { + $schemes[$cipher->getName()] = $cipher->getParameters(); + } + + $protocol = array( + 'VERSION' => CIFORM_PROTOCOL_VERSION, + 'PACKET_PREFIX' => CIFORM_REQUEST_PREFIX, + 'serverURL' => str_replace("'","\\'",$serverURL), + 'schemes' => $schemes + ); + + if ( CIFORM_DEBUG ) echo "ciform_rsa_getProtocol() = ".print_r($protocol,TRUE)."
"; + + return $protocol; + } + +} + + + +// +// CASE 'PROTOCOL' : Called with the CIFORM_REQUEST_PROTOCOL parameter, +// this script is used to print the Ciform protocol parameters +// +if ( isset($_REQUEST[CIFORM_REQUEST_PROTOCOL]) ) +{ + header("Content-type: text/plain"); + + // instanciates a default Ciform server handler + $ciform = new ciform_Server(CIFORM_SCHEMES_DEFAULT); + + // if a name was given, use it to name the variable : + // the result may be used as a full (java)script + if ( trim($name) != "" ) { + echo "var $name = " . json_encode($ciform->getProtocol()) . ";"; + } + // if no name was given, just print the JSON value : + // the result may be used as an Ajax response + else { + echo json_encode($ciform->getProtocol()); + } + + exit; +} + + + +// +// CASE 'AUTODECRYPT' : If set, this script will try to automatically decrypt all parameters of the current $_REQUEST, +// so the decryption phase is transparent to the next server scripts +// +if ( CIFORM_AUTODECRYPT ) +{ + // instanciates a default Ciform server handler + $ciform = new ciform_Server(CIFORM_SCHEMES_DEFAULT); + + // and replaces the request with the unencrypted one + $_REQUEST = $ciform->decryptParams($_REQUEST); +} + +?> \ No newline at end of file diff --git a/ciform/trunk/src/ciform/schemes/core.php b/ciform/trunk/src/ciform/schemes/core.php new file mode 100644 index 0000000..a96c3ee --- /dev/null +++ b/ciform/trunk/src/ciform/schemes/core.php @@ -0,0 +1,411 @@ + +// + +/** + * Core decoders/encoders classes for ciform messages.
+ * + *

NOTE : In order to keep compatibility with PHP 4, only the basic object oriented features of PHP + * are used in this script. This may lead programmers familiar with OOP to misunderstand the classes tree sometimes. + * In particular, some classes are meant to be interfaces, but since there's only one possible extend per class, + * they were made real classes, and then the tree does not conform exactly to what it would be if multiple + * inheritance was allowed.

+ * + * @package ciform + * @subpackage ciphers + * @link http://plugnauth.sourceforge.net/ciform + * @author Nicolas BONARDELLE + */ + +require_once "crypto/ciphers/core.php"; + +// Comment out the following line to enable debug traces from this script +//define("CIFORM_DEBUG",TRUE); +/** The prefix to any Ciform packet */ +define("CIFORM_SCHEME_NAME","ciform"); +/** The regular expression that extracts the body from any Ciform packet */ +define("CIFORM_SCHEME_EXTRACT_BODY",'^'.CIFORM_SCHEME_NAME.':(.*)$'); + + + +/** + * This class specifies the interface of a scheme handler in the Ciform protocol.
+ * @abstract + */ +class Ciform_Scheme extends crypto_Cipher +{ + /** + * @access private + */ + var $name; + + Ciform_Scheme( $name ) + { + if ( defined($name) ) { + $this->name = $name; + } + } + + /** + * Used to identify this scheme. + */ + function getName() + { + return $this->name; + } + + /** + * Builds a packet with full scheme from a message. + * @param string $packet The message to pack + * @abstract + */ + function pack( $packet ) { throw new Exception("This method is not implemented."); } + + /** + * @param string $packet A 'ciphertext', including the full scheme + * @return array|FALSE FALSE if this does not matches this scheme. + * Otherwise, an array containing unpacked informations, + * with at least the body of the given packet indexed on the key body. + * For instance,rsa:0x21372A02302FD83242A723 would return array("body"=>0x21372A02302FD83242A723) + * if this class handles rsa: prefixed packets. + * @abstract + */ + function unpack( $packet ) { throw new Exception("This method is not implemented."); } +} + + + +/** + * This pseudo-cipher handles the recursive aspects of Ciform's scheme by holding a list of ciphers to use for enc/decoding.
+ * + *

As a decoder, it acts like a chain of responsibility, invoking each of its internal decoders + * in turn until one of them can decode the message.

+ * + *

NOTE : The encoder part is not implemented.

+ */ +class Ciform_CipherChain extends Ciform_Scheme +{ + /** + * @var array + * @access private + */ + var $ciphers; + + /** + * @param array $ciphers The list of the internal {@link crypto_Cipher}s in this chain + */ + function Ciform_CipherChain( $ciphers, $name="schemes" ) + { + parent::Ciform_Scheme($name); + $this->ciphers = $ciphers; + } + + + + /** + * Does one loop in the chain : tries each cipher in turn (lowest index first) on the given ciphertext.
+ * + * @return string The first result not FALSE, or FALSE if no cipher matched + * @access private + */ + function chainDecode( $packet ) + { + $message = $ciphertext; + + foreach ( $this->ciphers as $decoder ) + { + // The first decoder accepting the ciphertext is the good one, we don't need to go further. + if ( $message = $decoder->decode($message,$this) ) + { + return $message; + } + } + + // no decoder has accepted the ciphertext + return FALSE; + } + + + + /** + * @return string The result of the call to the {@link crypto_Cipher#decode} method + * of the first decoder in the chain that accepted the ciphertext, + * or the original message if none was found (never returns FALSE) + */ + function decode( $packet ) + { + // this outer loop tells to continue while the message is still encoded and handled by one of the decoders + for ( $message1 = $packet ; $message2 = $this->chainDecode($message1) ; $message1 = $message2 ); + + return $message1; + } +} + + + +/** + * This class defines a skeleton to write a Ciform enc/decoder. + * @abstract + */ +class Ciform_Codec extends Ciform_Scheme +{ + /** + * @var Ciform_Scheme Used as a default cipher chain + * @access private + * @see #decode + */ + var $chain; + + /** + * @var boolean + * @access private + */ + var $unpackOnly; + + + + /** + * @param boolean $unpackOnly If TRUE, this codec will not do the final decoding on the packet, + * but will rather return the body as is. + */ + function Ciform_Codec( $name, $unpackOnly=FALSE ) + { + parent::Ciform_Scheme($name); + $this->unpackOnly = $unpackOnly; + } + + + + /** + * @return crypto_Cipher|FALSE A cipher able to decode the body of the given packet, + * or FALSE if this scheme does not handle this kind of packet.
+ *
+ * Note that the prefered way to check if a codec does handle some packet + * is not to call this method, but rather to compare the result of the {@link unpack} method with FALSE. + * @access protected + * @abstract + */ + function getDecoder( $packet ) { throw new Exception("This method is not implemented."); } + + + + /** + * @todo Describe this method + */ + function encode( $text ) { throw new Exception("This method is not implemented."); } + + + + /** + * Decrypts and unpack in chain a Ciform packet.
+ * + *

There can be several levels of encoding in one ciphertext.
+ * For instance, a message could first be encoded into hexadecimal form, then through RSA.
+ * The decryption would then take place in two steps : first, decoding the RSA message will give the hexadecimal form; + * then, transcoding this message to the original charset (e.g. ASCII) will give back the original text.
+ * An object implementing this class is used for each step in this decoding chain.

+ * + * @param string $ciphertext The message to decode + * @param Ciform_CipherChain $chain A decoder that may be used to decrypt inner parts of the ciphertext.
+ * It should be a {@link Ciform_CipherChain}, but all that is required is that it respects the {@link Ciform_Scheme} interface.
+ * It may be used to decode some part of the message, e.g. when the decoder allows the body of the message itself to be encoded.
+ * For instance : with rsa:hex:0x1232423248, a {@link Ciform_ciphers_RSADecoder} will call the chain on hex:0x1232423248 + * in order to get the raw value to decrypt with a RSA private key. + * @return string|FALSE The decoded message or FALSE if this class cannot decode the given ciphertext. + */ + function decode( $packet, $chain=FALSE ) + { + if ( CIFORM_DEBUG ) { echo print_r($this,TRUE),"->decode($packet,",print_r($chain,TRUE),")"."\n"; } + + // uses the internal chain (if any) if the chain was not given as an argument + $myChain = $chain ? $chain : ($this->chain ? $this->chain : FALSE); + + if ( CIFORM_DEBUG ) { echo "myChain=",print_r($myChain,TRUE)."\n"; } + + // 1. First extract the body from the packet + if ( ($unpacked = $this->unpack($packet)) && isset($unpacked['body']) ) + { + if ( CIFORM_DEBUG ) { echo "unpacked=$unpacked"."\n"; } + + $body = $unpacked['body']; + + // 2. and resursively decode the body if it is itself a packet + if ( $myChain && $cleartext = $myChain->decode($body) ) + { + if ( CIFORM_DEBUG ) { echo "cleartext=$cleartext"."\n"; } + + $body = $cleartext; + } + + // 3. finally decode the body using the decoder of this cipher + if ( $this->unpackOnly ) + { + return $body; + } + else + { + // 3.a get a decoder on the given packet + $decoder = $this->getDecoder($packet); + + if ( CIFORM_DEBUG ) { echo "decoder=".print_r($decoder,TRUE)."\n"; } + + // 3.b then use the decoder to return a decoded text + return $decoder->decode($body); + } + } + + if ( CIFORM_DEBUG ) { echo "unpacked=".print_r($this->unpack($packet),TRUE)."\n"; } + + // if no decoder was found, this object does not handle this scheme + return FALSE; + } +} + + + +/** + * A simple scheme packer/unpacker based on a regular expression.
+ * + *

Such a simple scheme unpacker could be used "as is" if the operation only consist to remove a part of the packet (a prefix for instance).
+ * This is sometimes usefull to unmark a packet or remove unused information from a message.

+ * + *

NOTE : The unpacker part is not implemented.

+ */ +class Ciform_SimpleScheme extends Ciform_Codec +{ + /** + * @var string + * @access private + */ + var $regex; + + + + /** + * @param string $regex The regular expression to use to extract the message body from packets. + * It will be passed as the first argument to {@link preg_match}. + * It must isolate the message into its first capturing group ($matches[1]). + * @param boolean $unpackOnly See Ciform_Codec#Ciform_Codec() + */ + function Ciform_SimpleScheme( $name, $regex, $unpackOnly=FALSE ) + { + parent::Ciform_Codec($name,$unpackOnly); + $this->regex = $regex; + } + + + + /** + * Extracts the body of the message using its registered regular expression + */ + function unpack( $packet ) + { + if ( CIFORM_DEBUG ) { echo print_r($this,TRUE)."->unpack($packet)"."\n"; } + + if ( preg_match($this->regex,$packet,$matches) ) + { + if ( CIFORM_DEBUG ) { echo "matches=".print_r($matches,TRUE)."\n"; } + + return array( 'body' => $matches[1] ); + } + + if ( CIFORM_DEBUG ) { echo "preg_match(".$this->regex.",$packet,$matches)=".preg_match($this->regex,$packet,$matches)."\n"; } + + return FALSE; + } +} + + + +/** + * A simple decoder that removes salt from a message. + * + *

Salt is used to add randomness to a message : it can be removed safely.

+ */ +class Ciform_schemes_Salt extends Ciform_SimpleScheme +{ + /** + * Only this constructor needs to be defined, in order to pass the superclass + * the right regex to extract the salt from the message. + */ + function Ciform_schemes_Salt() + { + parent::Ciform_SimpleScheme("salt",'/^salt[^:]*:(.*)$/i'); + } +} + + + +/** + * This decoder transforms an hexadecimal string into its binary representation. + */ +class Ciform_schemes_Base16 extends Ciform_SimpleScheme +{ + /** + * @param boolean $unpackOnly If FALSE, the {@link decode()} method will not decode the ciphertext, + * but just return the hexadecimal encoded value without the hex: preamble + */ + function Ciform_schemes_Base16( $unpackOnly=FALSE ) + { + parent::Ciform_SimpleScheme("base16",'/^(?:hex:|0x)(.*)$/i',$unpackOnly); + } + + function getDecoder( $packet ) + { + if ( CIFORM_DEBUG ) { echo print_r($this,TRUE)."->getDecoder($packet)"."\n"; } + + if ( $this->unpack($packet) ) + { + return new crypto_ciphers_Base16(); + } + + return FALSE; + } +} + + + +/** + * Decodes base64 encoded texts + */ +class Ciform_schemes_Base64 extends Ciform_SimpleScheme +{ + /** + * @param boolean $unpackOnly If FALSE, the {@link #decode} method will not decode the ciphertext, + * but just return the base64 encoded value without the base64: preamble + */ + function Ciform_schemes_Base64( $unpackOnly=FALSE ) + { + parent::Ciform_SimpleScheme("base64",'/^(?:base64|b64):(.*)$/',$unpackOnly); + } + + function getDecoder( $packet ) + { + if ( CIFORM_DEBUG ) { echo print_r($this,TRUE)."->getDecoder($packet)"."\n"; } + + if ( $this->unpack($packet) ) + { + return new crypto_ciphers_Base64(); + } + + return FALSE; + } +} + + + +/** + * Simply unpacks a ciform packet + */ +class Ciform_schemes_Ciform extends Ciform_SimpleScheme +{ + function Ciform_schemes_Ciform() + { + parent::Ciform_SimpleScheme(CIFORM_SCHEME_NAME,CIFORM_SCHEME_EXTRACT_BODY,TRUE); + } +} + +?> \ No newline at end of file diff --git a/ciform/trunk/src/ciform_ciphers.php b/ciform/trunk/src/ciform_ciphers.php deleted file mode 100644 index cee3919..0000000 --- a/ciform/trunk/src/ciform_ciphers.php +++ /dev/null @@ -1,422 +0,0 @@ - - */ - class Scheme - { - /** - * @return the body of the given packet, or FALSE if this does not matches this scheme. - * For instance,rsa:0x21372A02302FD83242A723 would return 0x21372A02302FD83242A723 - * if this class handles rsa: prefixed packets. - */ - function getBody( $packet ) { return FALSE; } - } - - - - /** - * This class defines the interface decoders have to implement in order to decrypt in chain Ciform messages.
- * - *

There can be several levels of encoding in one ciphertext.
- * For instance, a message could first be encoded into hexadecimal form, then through RSA.
- * The decryption would then take place in two steps : first, decoding the RSA message will give the hexadecimal form; - * then, transcoding this message to the original charset (e.g. ASCII) will give back the original text.
- * - * An object implementing this class is used for each step in this decoding chain.

- * - * @abstract - */ - class ChainDecoder extends Scheme - { -// /** -// * @param string $ciphertext The message to decode -// * @return boolean TRUE if this decoder can handle the given message, FALSE if not. -// * @abstract -// */ -// function canDecode( $ciphertext ) { return FALSE }; - - /** - * {@link ::canDecode()} must be called before to call this method. - * - * @param string $ciphertext The message to decode - * @param ChainDecoder $chain The chain decoder to invoke next.
- * It must not be used when the decoder cannot handle the ciphertext (in this case, it must return FALSE).
- * It may be used to decode the rest of the message, when the decoder allows the body of the message to be encoded itself.
- * For instance : with rsa:hex:0x1232423248, a {@link RSADecoder} will call the chain on hex:0x1232423248 - * in order to get the raw value to decrypt with a RSA private key. - * @return string|FALSE The decoded message or FALSE if an error happened. - * @abstract - */ - function decode( $ciphertext, $chain ) { return FALSE; } - } - - - - /** - * This decoder acts like a chain of responsibility : it invokes each of its internal decoders - * in turn until one of them can decode the message.
- * - *

Its role is not to be a single link in the chain, but to make the chain start. - * However, it respects the {@link ChainDecoder} interface.

- */ - class ChainDecoderChain extends ChainDecoder - { - /** @access private */ - var $decoders; - - /** - * @param array $decoders The list of the internal decoders of this chain - */ - function ChainDecoderChain( $decoders ) - { - $this->$decoders = $decoders; - } - - function canDecode( $ciphertext ) - { - foreach ( $this->$decoders as $decoder ) - { - if ( $decoder->canDecode($ciphertext) ) { - return TRUE; - } - } - - return FALSE; - } - - /** - * NOTE : the $chain parameter is not used here - * @return TRUE if at least one decoder in the chain could decode some part of the ciphertext, FALSE else - */ - function decode( $ciphertext, $chain ) - { - if ( ! $this->canDecode($ciphertext) ) { - return FALSE; - } - - $message = $ciphertext; - - // this outer loop tells to continue while the message is still encoded and handled by one of the decoders - while ( $this->canDecode($message) ) - { - // this inner loop tells to try each decoder in turn - foreach ( $this->$decoders as $decoder ) - { - if ( $decoder->canDecode($message) ) { - $message = $decoder->decode($message,$this); - // The first decoder accepting the ciphertext is the good one, we don't need to go further. - // This break is not necessary since there is no real priority order in the chain, - // but it helps to show the logic of the loop. - break; - } - } - } - - return $message; - } - } - - - - /** - * A simple de-packetizer of (for instance) "ciform:" prepended messages.
- * - *

Such a simple decoder could exist just to unmark a packet or remove unused information from a message.

- */ - class Depacketizer extends ChainDecoder - { - /** - * @var array Matches of the last message passed to {@link ::canDecode()} - * @access private - */ - var $matches; - - /** - * @var string - * @access private - */ - var $regex; - - /** - * @param string $regex The regular expression to use to extract core the message from packets. - * It will be passed as the first argument to {@link eregi}. - * It must isolate the message into its first capturing group ($matches[1]). - * Defaults to {@link CIFORM_PACKET_EXTRACT_MESSAGE} - */ - function Depacketizer( $regex=CIFORM_PACKET_EXTRACT_MESSAGE ) - { - $this->$regex = $regex; - } - - /** @return TRUE if the the ciphertext matches the regular expression, giving at least one result */ - function canDecode( $ciphertext ) - { - return eregi($this->$regex,$message,$this->$matches) > 0; - } - - /** Extracts the core message using its regular expression, and calls the chain to return a totally decoded message */ - function decode( $ciphertext, $chain ) - { - if ( defined($this->$matches) ) - { - $cleartext = $chain->decode($matches[1]); - delete $this->$matches; - return $cleartext; - } - - // canDecode() *must* be called before decode() - return FALSE; - } - } - - - - /** - * A simple decoder that removes salt from a message. - * Salt is used to add randomness to a message : it can be removed safely - */ - class Desalter extends Depacketizer - { - /** - * Only this constructor needs to be defined, in order to pass the superclass - * the right regex to extract the salt from the message. - */ - function Desalter() - { - parent::Depacketizer('^salt[^:]*:(.*)$'); - } - } - - - - /** - * This decoder transforms an hexadecimal string into its binary representation - */ - class HexDecoder extends Depacketizer - { - function HexDecoder() - { - parent::Depacketizer('^(?:hex:|0x)(.*)$'); - } - - function decode( $ciphertext, $chain ) - { - // first step : let the base class extract the wanted message - $message = parent::decode($ciphertext,$chain); - - if ( $message ) - { - // second step : do hexadecimal-to-text conversion - return pack("H*",$message); - } - - return FALSE; - } - } - - - - /** - * Decodes base64 encoded texts - */ - class Base64Decoder extends Depacketizer - { - function Base64Decoder() - { - parent::Depacketizer('^(?:base64|b64):(.*)$'); - } - - function decode( $ciphertext, $chain ) - { - // first step : let the base class extract the wanted message - $message = parent::decode($ciphertext,$chain); - - if ( $message ) - { - // second step : pass the message to the available decoders to get the raw value to work on - $cleartext = $chain->decode($message); - - // final step : do hexadecimal-to-text conversion - return pack("H*",$cleartext); - if ( $base == 64 ) - { - // we're already in the right radix, don't go further - // (same can be done with other bases too, but right now we only need this one) - return $tmpData; - } - $newData = base64_decode($tmpData); - } - - return FALSE; - } - } - - - - // TODO : embed the key in the data (e.g. ciform:rsa:keyId:0x12345:0xdd33be2b17813b396d63dd1be9c72e9756bbd8ae5d5555b93a7f4b4fd5a8c80d:salt24325234) - // TODO : use the responsibility chain to rewrite this function - function ciform_decode( $data, $keyPair, $base=1 ) - { - if ( CIFORM_DEBUG ) echo "ciform_decrypt($data,keyPair,$base)
"; - - // $newData is going to be decoded by one of the following filters - // then, it'll be encoded to the destination base - $newData = $data; - - // this flag means this parameter is handled by this library - if ( eregi('^'.CIFORM_REQUEST_PREFIX.'(.*)$',$data,$matches) > 0 ) - { - $newData = ciform_decode($matches[1],$keyPair); - } - - // this is just salt that adds randomness to the string : it can be removed safely - else if ( eregi('^salt[^:]*:(.*)$',$data,$matches) > 0 ) - { - $newData = ciform_decode($matches[1],$keyPair); - } - - // this is an hexadecimal string - else if ( eregi('^(hex:|0x)(.*)$',$data,$matches) > 0 ) - { - $tmpData = ciform_decode($matches[2],$keyPair); - $newData = pack("H*",$tmpData); - } - - // this a base64 encoded string - else if ( eregi('^(base64|b64):(.*)$',$data,$matches) > 0 ) - { - $tmpData = ciform_decode($matches[2],$keyPair); - if ( $base == 64 ) - { - // we're already in the right radix, don't go further - // (same can be done with other bases too, but right now we only need this one) - return $tmpData; - } - $newData = base64_decode($tmpData); - } - - // this is an encrypted message - else if ( eregi('^'.CIFORM_KEYTYPE.':(.*)(:.+)?$',$data,$matches) > 0 ) - { - $tmpData = ciform_decode($matches[1],$keyPair,64); - - // decrypts the data using the configured module - $func = "ciform_".CIFORM_KEYTYPE."_decrypt"; - $newData = ciform_decode( $func($tmpData,$keyPair), $keyPair ); - } - - // FIXME : do better recursion : each case should return ciform_decode($tmpData) except if no encoding is detected (which then ends the recursion) - // FIXME : put each case in a different 'decoder' class - - // encodes the data into the desired base - switch( $base ) - { - case 64: - return base64_encode($newData); - default: - return $newData; - } - } - - - - function ciform_decryptParam( $data, $keyPair ) - { - if ( gettype($data) == "string" && eregi('^'.CIFORM_REQUEST_PREFIX.'(.*)$',$data,$matches) > 0 ) - { - return ciform_decode($matches[1],$keyPair); - } - return $data; - } - - - - function ciform_decryptParams( $request, $keyPair ) - { - $decoded = array(); - - // accepts encrypted data from the client - foreach ( $request as $key => $value ) - { - $newValue = ciform_decryptParam($value,$keyPair); - $decoded[$key] = $newValue; - } - - return $decoded; - } - - - - // returns the protocol of this script - if ( isset($_REQUEST[CIFORM_REQUEST_PROTOCOL]) ) - { - $func = "ciform_".CIFORM_KEYTYPE."_getProtocol"; - $name = $_REQUEST[CIFORM_REQUEST_PROTOCOL]; - header("Content-type: text/plain"); - // if a name was given, use it to name the variable : - // the result may be used as a full (java)script - if ( trim($name) != "" ) { - echo "var $name = " . $func() . ";"; - } - // if no name was given, just print the JSON value : - // the result may be used as an Ajax response - else { - echo $func(); - } - exit; - } - - - - // makes sure the key is accessible - // TODO : instanciate the given crypto class, - // which stores itself the key and all other specific data - // then, move the following code to the correct sub-script - if ( !isset($_SESSION[CIFORM_SESSION]) ) - { - $_SESSION[CIFORM_SESSION] = array(); - } - if ( !isset($_SESSION[CIFORM_SESSION][CIFORM_SESSION_KEYPAIR]) ) - { - // the encryption module's name is given by the defined key type - $func = "ciform_".CIFORM_KEYTYPE."_getKeyPair"; - $_SESSION[CIFORM_SESSION][CIFORM_SESSION_KEYPAIR] = $func(); - } - - - - if ( CIFORM_AUTODECRYPT ) - { - $_REQUEST = ciform_decryptParams($_REQUEST,$_SESSION[CIFORM_SESSION][CIFORM_SESSION_KEYPAIR]); - } -?> \ No newline at end of file diff --git a/ciform/trunk/src/ciform_rsa.php b/ciform/trunk/src/ciform_rsa.php deleted file mode 100644 index f6ce171..0000000 --- a/ciform/trunk/src/ciform_rsa.php +++ /dev/null @@ -1,230 +0,0 @@ -_math_obj ) - { - $json = "["; - - $intValue = $math->bin2int($binValue); - $szBits = $math->bitLen($intValue); // total length, in bits - - for ( $b=0 ; $b<$szBits ; ) - { - $l = min(28,$szBits-$b); - $json .= $math->subint($intValue, $b, $l); - $b += $l; - if ( $b<$szBits ) - { - $json .= ","; - } - } - - return $json."]"; - } - - - - /** - * Transforms an RSA public key into a JSON structure - * - * @param Crypt_RSA_KeyPair $keyPair Optional RSA key pair holding the public key (use this if called from the class context). - * @return string The public key as a JSON structure - * @access private - */ - function pubKey2Json( $keyPair=$this ) - { - $pubKey = $keyPair->getPublicKey(); - $math = $keyPair->_math_obj; - $p = Ciform_RSA_KeyPair::bigInt2Json($keyPair->_attrs['p'],$math); - $q = Ciform_RSA_KeyPair::bigInt2Json($keyPair->_attrs['q'],$math); - $e = Ciform_RSA_KeyPair::bigInt2Json($pubKey->getExponent(),$math); - $pq = Ciform_RSA_KeyPair::bigInt2Json($pubKey->getModulus(),$math); - //$mpi = base64_encode($math->bin2int($pubKey->getModulus())+$math->bin2int($pubKey->getExponent())); - $json = "{" - ."'type':'".CIFORM_RSA_KEYTYPE."'," - ."'size':".$pubKey->getKeyLength()."," // size of the key, in bits - ."'p':$p," // prime factor p, as an array of 28 bits integers - ."'q':$q," // prime factor q, as an array of 28 bits integers - ."'e':$e," // public exponent as an array of 28 bits integers - ."'pq':$pq}"; // modulus, as an array of 28 bits integers - //."'mpi':'$mpi'" // e + modulus, encoded into a base64 MPI string - return $json; - } - - - - /** - * Clones an existing key pair by copying its intrisinc fields into this one, - * - * @param Crypt_RSA_KeyPair $keyPair The key pair to copy - * @return $this - * @todo This implementation depends totally on the version of the superclass : - * if a field is added or removed, this method can very possibly fail to do its job - * @private - */ - function copy( $keyPair ) - { - $this->$_math_obj = $keyPair->$_math_obj; - $this->$_key_len = $keyPair->$_key_len; - $this->$_public_key = $keyPair->$_public_key; - $this->$_private_key = $keyPair->$_private_key; - $this->$_random_generator = $keyPair->$_random_generator; - $this->$_attrs = $keyPair->$_attrs; - return $this; - } - - - - /** - * This method is overriden to instanciate an object from the same class as the current object - * @see Crypt_RSA_KeyPair::fromPEMString - * @todo This should be done in the superclass : it should dynamically return a new instance of the current class - */ - function &fromPEMString($str, $wrapper_name = 'default', $error_handler = '') - { - $keyPair1 = parent::fromPEMString($str,$wrapper_name,$error_handler); - $keyPair2 = new Crypt_RSA_KeyPair(); - $keyPair2->copy($keyPair1); - return $keyPair2; - } - - - - /** - * Uses an existing key pair stored in a file or generates a new one. - * - * If the PEM file exist, the key pair will be read from it. If it doesn't, the key pair will be generated.
- * Upon generation of a new key pair, both a PEM and a Javascript file will be created if they don't exist already. - * - * @param int $keySize Size of the key to generate, in bits - * @param string $pemFilename Name of the file where a PEM formated keypair may be found / stored - * @param string $jsFilename Name of the file where to store the key upon generation as a Javascript script - * @param boolean $force Forces generation of both the PEM and the Javascript file. If false, the files will not be overwritten if they exist already. - * @access private - * @static - */ - function genKeyPair( $keySize, $pemFilename, $jsFilename, $force=FALSE ) - { - // if the key has been stored to a file, get it from there - if ( $contents = @file_get_contents($pemFilename) ) - { - return Ciform_RSA_KeyPair::fromPEMString($contents); - } - - // else, generate a new key and try to store it to a file - else - { - // generates the key - $keyPair = new Ciform_RSA_KeyPair($keySize); - - // stores as PEM - if ( $force || !@file_exists($pemFilename) ) - { - @mkdir(dirname($pemFilename),0777,TRUE); - @file_put_contents($pemFilename,$keyPair->toPEMString()); - } - - // store some Javascript variables, including the public key - // FIXME : if file_put_contents fails, no notification but the file is never written - if ( $force || !@file_exists($jsFilename) ) - { - @mkdir(dirname($jsFilename),0777,TRUE); - // FIXME : serverURL must be absolute, so scripts can call it from other servers - //$serverURL = $_SERVER['PHP_SELF']; - $pubKey = $keyPair->pubKey2Json(); - //$jsContents = "\nvar CIFORM = {'serverURL':'".str_replace("'","\\'",$serverURL)."', 'pubKey':$pubKey};"; - @file_put_contents($jsFilename,$pubKey); - } - - // returns the newly created key - return $keyPair; - } - } - } - - - - /** - * Ciform handler using the RSA cipher - */ - class Ciform_RSA - { - /** - * @return Ciform_RSA_KeyPair the current key pair (or a new one if none defined) - */ - function getKeyPair() - { - if ( CIFORM_DEBUG ) echo "ciform_rsa_getKeyPair() = "; - $keyPair = Ciform_RSA_KeyPair::genKeyPair(CIFORM_RSA_KEYSIZE, CIFORM_RSA_KEYFILE_PEM, CIFORM_RSA_KEYFILE_JS); - if ( CIFORM_DEBUG ) print_r($keyPair); - return $keyPair; - } - - - - /** - * @return string the current Ciform protocol - */ - function getProtocol() - { - if ( CIFORM_DEBUG ) echo "ciform_rsa_getProtocol() = "; - // FIXME : serverURL must be absolute, so scripts can call it from other servers - $serverURL = $_SERVER['PHP_SELF']; - $keyPair = Ciform_RSA::getKeyPair(); - $protocol = "{ - 'VERSION':".CIFORM_PROTOCOL_VERSION.", - 'PACKET_PREFIX':'".CIFORM_REQUEST_PREFIX."', - 'serverURL':'".str_replace("'","\\'",$serverURL)."', - 'pubKey':".$keyPair->pubKey2Json() - ."}"; - if ( CIFORM_DEBUG ) print_r($protocol); - return $protocol; - } - - - - /** - * - */ - function decrypt( $data, $keyPair ) - { - if ( CIFORM_DEBUG ) echo "ciform_rsa_decrypt($data,keyPair)
"; - $privateKey = $keyPair->getPrivateKey(); - // TODO make the math object configurable, because there are big differences between them and to offer better compatibility - $rsa = new Crypt_RSA($privateKey->getKeyLength(),'BCMath'); - return $rsa->decrypt($data,$privateKey); - } - } - - - - // keypair generation is forced if this parameter is set - if ( isset($_SESSION[CIFORM_RSA_REQUEST_GENKEY]) ) - { - $_SESSION[CIFORM_SESSION][CIFORM_SESSION_KEYPAIR] = Ciform_RSA_KeyPair::genKeyPair(CIFORM_RSA_KEYSIZE, CIFORM_RSA_KEYFILE_PEM, CIFORM_RSA_KEYFILE_JS, TRUE); - } - -?> \ No newline at end of file diff --git a/ciform/trunk/src/crypto/Cipher.class.php b/ciform/trunk/src/crypto/Cipher.class.php new file mode 100644 index 0000000..c286587 --- /dev/null +++ b/ciform/trunk/src/crypto/Cipher.class.php @@ -0,0 +1,49 @@ + +// + +/** + * Core ciphers for ciform messages.
+ * + * COPYRIGHT NOTICE :
+ *
+ * Copyright © 2008 Nicolas BONARDELLE 
+ *
+ *
+ * + *

Most of the ciphers here are only partially implemented, since this server-side library doesn't use encryption yet.

+ * + * @package ciform + * @subpackage ciphers + * @link http://plugnauth.sourceforge.net/ciform + * @author Nicolas BONARDELLE + */ + + + +/** + * This class specifies the interface of a cipher : both the encoding and the decoding parts.
+ * + * @abstract + */ +class crypto_Cipher +{ + /** + * @param string $cleartext The message to encode + * @return string The encoded message (= ciphertext) + * @abstract + */ + function encode( $cleartext ) { throw new Exception("This method is not implemented."); } + + /** + * @param string $ciphertext The encoded message to decode + * @return string|FALSE The decoded message or FALSE if this object cannot decode the given ciphertext + * @abstract + */ + function decode( $ciphertext ) { throw new Exception("This method is not implemented."); } +} + +?> \ No newline at end of file diff --git a/ciform/trunk/src/crypto/ciphers/core.php b/ciform/trunk/src/crypto/ciphers/core.php new file mode 100644 index 0000000..5822ffd --- /dev/null +++ b/ciform/trunk/src/crypto/ciphers/core.php @@ -0,0 +1,60 @@ + +// + +/** + * A few common ciphers.
+ * + * COPYRIGHT NOTICE :
+ *
+ * Copyright © 2008 Nicolas BONARDELLE 
+ *
+ *
+ * + *

Most of the ciphers here are only partially implemented, since this server-side library doesn't use encryption yet.

+ * + * @package crypto + * @subpackage ciphers + * @link http://plugnauth.sourceforge.net/ciform + * @author Nicolas BONARDELLE + */ + +require_once "crypto/Cipher.class.php"; + +// Comment out the following line to enable debug traces from this script +//define("CRYPTO_DEBUG",TRUE); + + + +/** + * This cipher transforms an text into its hexadecimal representation + */ +class crypto_ciphers_Base16 extends crypto_Cipher +{ + function decode( $base16msg ) + { + if ( CRYPTO_DEBUG) { echo print_r($this,TRUE)."->decode($base16msg)"."\n"; } + + return pack("H*",$base16msg); + } +} + + + +/** + * Encodes/decodes text into/from a base64 string + */ +class crypto_ciphers_Base64 extends crypto_Cipher +{ + function decode( $base64msg ) + { + if ( CRYPTO_DEBUG) { echo print_r($this,TRUE)."->decode($base64msg)"."\n"; } + + return base64_decode($base64msg); + } +} + +?> \ No newline at end of file diff --git a/ciform/trunk/src/ciform_pgp.php b/ciform/trunk/src/crypto/ciphers/pgp.php similarity index 100% rename from ciform/trunk/src/ciform_pgp.php rename to ciform/trunk/src/crypto/ciphers/pgp.php diff --git a/ciform/trunk/src/crypto/ciphers/rsa.php b/ciform/trunk/src/crypto/ciphers/rsa.php new file mode 100644 index 0000000..d1a2987 --- /dev/null +++ b/ciform/trunk/src/crypto/ciphers/rsa.php @@ -0,0 +1,308 @@ + +// + +require_once "crypto/ciphers/core.php"; +require_once("Crypt/RSA.php"); + +define("CIFORM_RSA_KEYTYPE","rsa"); +define("CIFORM_RSA_KEYSIZE",768); +define("CIFORM_RSA_KEYSTORE","keys"); +define("CIFORM_RSA_KEYFILE_PEM",CIFORM_RSA_KEYSTORE."/protected/key-rsa.pem"); +define("CIFORM_RSA_KEYFILE_JS",CIFORM_RSA_KEYSTORE."/key-rsa.pub.json"); +define("CIFORM_RSA_REQUEST_GENKEY","ciform-genkey"); +define("CIFORM_SESSION_KEYPAIR","KEYPAIR"); // TODO : move to ciform_rsa.php +/** */ +define("CIFORM_KEYTYPE",CIFORM_RSA_KEYTYPE); // choose the desired encryption module here + + +// TODO : embed the key in the data (e.g. ciform:rsa:keyId:0x12345:0xdd33be2b17813b396d63dd1be9c72e9756bbd8ae5d5555b93a7f4b4fd5a8c80d:salt24325234) + + +// +// RSA SPECIAL HANDLING : Since this is the default encryption, +// the script will retrieve the keys or generated them if not found. +// +// TODO : instanciate the given crypto class, +// which stores itself the key and all other specific data +// then, move the following code to the correct sub-script +if ( !isset($_SESSION[CIFORM_SESSION]) ) +{ + $_SESSION[CIFORM_SESSION] = array(); +} +if ( !isset($_SESSION[CIFORM_SESSION][CIFORM_SESSION_KEYPAIR]) ) +{ + // the encryption module's name is given by the defined key type + $func = "ciform_".CIFORM_KEYTYPE."_getKeyPair"; + $_SESSION[CIFORM_SESSION][CIFORM_SESSION_KEYPAIR] = $func(); +} + + + +/** + * This class extends Crypt_RSA_KeyPair by adding conversion functions to Javascript and to the Ciform protocol + */ +class Ciform_ciphers_rsa_KeyPair extends Crypt_RSA_KeyPair +{ + /** + * Transforms a big integer value into a JSON array of 28 bits integers + * + * @param string $binValue The raw, binary string value of the big integer + * @param Crypt_RSA_Math_* $math Optional math wrapper to use to manipulate large integers. Will use the current one if not specified. + * @see Crypt_RSA_KeyPair::$_math_obj + * @return string The number as a JSON structure + * @access private + */ + function bigInt2Json( $binValue, $math=$this->_math_obj ) + { + $json = "["; + + $intValue = $math->bin2int($binValue); + $szBits = $math->bitLen($intValue); // total length, in bits + + for ( $b=0 ; $b<$szBits ; ) + { + $l = min(28,$szBits-$b); + $json .= $math->subint($intValue, $b, $l); + $b += $l; + if ( $b<$szBits ) + { + $json .= ","; + } + } + + return $json."]"; + } + + + + /** + * Exports a RSA public key into an associative array, ready for JSON transformation + * + * @param Crypt_RSA_KeyPair $keyPair Optional RSA key pair holding the public key (use this if called from the class context). + * @return array The public key as an associative array + * @access private + */ + function exportPubKey( $keyPair=$this ) + { + $pubKey = $keyPair->getPublicKey(); + $math = $keyPair->_math_obj; + $p = Ciform_RSA_KeyPair::bigInt2Json($keyPair->_attrs['p'],$math); + $q = Ciform_RSA_KeyPair::bigInt2Json($keyPair->_attrs['q'],$math); + $e = Ciform_RSA_KeyPair::bigInt2Json($pubKey->getExponent(),$math); + $pq = Ciform_RSA_KeyPair::bigInt2Json($pubKey->getModulus(),$math); + //$mpi = base64_encode($math->bin2int($pubKey->getModulus())+$math->bin2int($pubKey->getExponent())); + + $export = array( + 'type' => CIFORM_RSA_KEYTYPE, + 'size' => $pubKey->getKeyLength(), // size of the key, in bits + 'p' => $p, // prime factor p, as an array of 28 bits integers + 'q' => $q, // prime factor q, as an array of 28 bits integers + 'e' => $e, // public exponent as an array of 28 bits integers + 'pq' => $pq; // modulus, as an array of 28 bits integers + //'mpi' => $mpi // e + modulus, encoded into a base64 MPI string + ); + + return $export; + } + + + + /** + * Clones an existing key pair by copying its intrisinc fields into this one, + * + * @param Crypt_RSA_KeyPair $keyPair The key pair to copy + * @return $this + * @todo This implementation depends totally on the version of the superclass : + * if a field is added or removed, this method can very possibly fail to do its job + * @private + */ + function copy( $keyPair ) + { + $this->$_math_obj = $keyPair->$_math_obj; + $this->$_key_len = $keyPair->$_key_len; + $this->$_public_key = $keyPair->$_public_key; + $this->$_private_key = $keyPair->$_private_key; + $this->$_random_generator = $keyPair->$_random_generator; + $this->$_attrs = $keyPair->$_attrs; + return $this; + } + + + + /** + * This method is overriden to instanciate an object from the same class as the current object + * @see Crypt_RSA_KeyPair::fromPEMString + * @todo This should be done in the superclass : it should dynamically return a new instance of the current class + */ + function &fromPEMString($str, $wrapper_name = 'default', $error_handler = '') + { + $keyPair1 = parent::fromPEMString($str,$wrapper_name,$error_handler); + $keyPair2 = new Crypt_RSA_KeyPair(); + $keyPair2->copy($keyPair1); + return $keyPair2; + } + + + + /** + * Uses an existing key pair stored in a file or generates a new one. + * + * If the PEM file exist, the key pair will be read from it. If it doesn't, the key pair will be generated.
+ * Upon generation of a new key pair, both a PEM and a Javascript file will be created if they don't exist already. + * + * @param int $keySize Size of the key to generate, in bits + * @param string $pemFilename Name of the file where a PEM formated keypair may be found / stored + * @param string $jsFilename Name of the file where to store the key upon generation as a Javascript script + * @param boolean $force Forces generation of both the PEM and the Javascript file. If false, the files will not be overwritten if they exist already. + * @access private + * @static + */ + function genKeyPair( $keySize, $pemFilename, $jsFilename, $force=FALSE ) + { + // if the key has been stored to a file, get it from there + if ( $contents = @file_get_contents($pemFilename) ) + { + return Ciform_RSA_KeyPair::fromPEMString($contents); + } + + // else, generate a new key and try to store it to a file + else + { + // generates the key + $keyPair = new Ciform_RSA_KeyPair($keySize); + + // stores as PEM + if ( $force || !@file_exists($pemFilename) ) + { + @mkdir(dirname($pemFilename),0777,TRUE); + @file_put_contents($pemFilename,$keyPair->toPEMString()); + } + + // store some Javascript variables, including the public key + // FIXME : if file_put_contents fails, no notification but the file is never written + if ( $force || !@file_exists($jsFilename) ) + { + @mkdir(dirname($jsFilename),0777,TRUE); + // FIXME : serverURL must be absolute, so scripts can call it from other servers + //$serverURL = $_SERVER['PHP_SELF']; + $pubKey = $keyPair->pubKey2Json(); + //$jsContents = "\nvar CIFORM = {'serverURL':'".str_replace("'","\\'",$serverURL)."', 'pubKey':$pubKey};"; + @file_put_contents($jsFilename,$pubKey); + } + + // returns the newly created key + return $keyPair; + } + } +} + + + +/** + * Ciform handler using the RSA cipher + */ +class Ciform_RSA extends Ciform_ +{ + + + /** + * @return Ciform_RSA_KeyPair the current key pair (or a new one if none defined) + */ + function getKeyPair() + { + if ( CIFORM_DEBUG ) echo "ciform_rsa_getKeyPair() = "; + $keyPair = Ciform_RSA_KeyPair::genKeyPair(CIFORM_RSA_KEYSIZE, CIFORM_RSA_KEYFILE_PEM, CIFORM_RSA_KEYFILE_JS); + if ( CIFORM_DEBUG ) print_r($keyPair); + return $keyPair; + } + + + + /** + * @return string the current Ciform protocol + */ + function getProtocol() + { + 'pubKey' => $keyPair->exportPubKey(), + + if ( CIFORM_DEBUG ) echo "ciform_rsa_getProtocol() = "; + // FIXME : serverURL must be absolute, so scripts can call it from other servers + $serverURL = $_SERVER['PHP_SELF']; + $keyPair = Ciform_RSA::getKeyPair(); + $protocol = "{ + 'VERSION':".CIFORM_PROTOCOL_VERSION.", + 'PACKET_PREFIX':'".CIFORM_REQUEST_PREFIX."', + 'serverURL':'".str_replace("'","\\'",$serverURL)."', + 'pubKey':".$keyPair->pubKey2Json() + ."}"; + if ( CIFORM_DEBUG ) print_r($protocol); + return $protocol; + } + + + + /** + * + */ + function decrypt( $data, $keyPair ) + { + if ( CIFORM_DEBUG ) echo "ciform_rsa_decrypt($data,keyPair)
"; + $privateKey = $keyPair->getPrivateKey(); + // TODO make the math object configurable, because there are big differences between them and to offer better compatibility + $rsa = new Crypt_RSA($privateKey->getKeyLength(),'BCMath'); + return $rsa->decrypt($data,$privateKey); + } +} + + + + + + + + +class Ciform_schemes_RSA extends Ciform_SimpleScheme +{ + function Ciform_schemes_RSA() + { + parent::Ciform_SimpleScheme("rsa",'/^rsa:(.*)(:.+)?$/i'); + } + + function export() + { + return array( 'pubKey' => $keyPair->exportPubKey() ); + } + + function getDecoder( $packet ) + { + if ( CIFORM_DEBUG ) { echo print_r($this,TRUE)."->getDecoder($packet)"."\n"; } + + if ( $this->unpack($packet) ) + { + return new crypto_ciphers_Base64(); + } + + return FALSE; + } +} + + + + + + + + + + +// keypair generation is forced if this parameter is set +if ( isset($_SESSION[CIFORM_RSA_REQUEST_GENKEY]) ) +{ + $_SESSION[CIFORM_SESSION][CIFORM_SESSION_KEYPAIR] = Ciform_RSA_KeyPair::genKeyPair(CIFORM_RSA_KEYSIZE, CIFORM_RSA_KEYFILE_PEM, CIFORM_RSA_KEYFILE_JS, TRUE); +} + +?> \ No newline at end of file