From ae371e5364820611d3602f7a2bd25169a00df4db Mon Sep 17 00:00:00 2001 From: cbonar Date: Wed, 2 Jul 2008 23:20:48 +0000 Subject: [PATCH] + more fixes --- ciform/trunk/src/ciform/ciform.php | 10 +- ciform/trunk/src/ciform/schemes/core.php | 36 +++-- ciform/trunk/src/crypto/ciphers/rsa.php | 190 ++++++++++------------- 3 files changed, 112 insertions(+), 124 deletions(-) diff --git a/ciform/trunk/src/ciform/ciform.php b/ciform/trunk/src/ciform/ciform.php index 93050cc..6fef7f9 100644 --- a/ciform/trunk/src/ciform/ciform.php +++ b/ciform/trunk/src/ciform/ciform.php @@ -35,7 +35,7 @@ define("CIFORM_SESSION","CIFORM"); 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"); +define("CIFORM_REQUEST_PROTOCOL","ciform-protocol"); if ( ! defined("CIFORM_AUTODECRYPT") ) /** Define this constant to TRUE in caller script to enable transparent decryption of the request */ @@ -106,7 +106,7 @@ class ciform_Server /** * @return array the current Ciform protocol */ - function getProtocol() + function export() { // FIXME : serverURL must be absolute, so scripts can call it from other servers $serverURL = $_SERVER['PHP_SELF']; @@ -114,7 +114,7 @@ class ciform_Server $schemes = array(); foreach ( $this->codec->ciphers as $cipher ) { - $schemes[$cipher->getName()] = $cipher->getParameters(); + $schemes[$cipher->getName()] = $cipher->export(); } $protocol = array( @@ -147,12 +147,12 @@ if ( isset($_REQUEST[CIFORM_REQUEST_PROTOCOL]) ) // 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()) . ";"; + echo "var $name = " . json_encode($ciform->export()) . ";"; } // 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()); + echo json_encode($ciform->export()); } exit; diff --git a/ciform/trunk/src/ciform/schemes/core.php b/ciform/trunk/src/ciform/schemes/core.php index a96c3ee..6a55d8a 100644 --- a/ciform/trunk/src/ciform/schemes/core.php +++ b/ciform/trunk/src/ciform/schemes/core.php @@ -42,7 +42,7 @@ class Ciform_Scheme extends crypto_Cipher */ var $name; - Ciform_Scheme( $name ) + function Ciform_Scheme( $name ) { if ( defined($name) ) { $this->name = $name; @@ -57,6 +57,21 @@ class Ciform_Scheme extends crypto_Cipher return $this->name; } + /** + * This method provides a representation of this object to send to the client.
+ * + *

The clients will be provided this representation, which must contain all information + * necessary to the correct transmission of encrypted informations to (and from) this server.

+ * + *

Since it is carried by each scheme, different implementations of the same scheme must return the same kind of data.

+ * + * @return array The crucial properties of this object in an array. Defaults to an empty array. + */ + function export() + { + return array(); + } + /** * Builds a packet with full scheme from a message. * @param string $packet The message to pack @@ -94,12 +109,13 @@ class Ciform_CipherChain extends Ciform_Scheme */ var $ciphers; + /** * @param array $ciphers The list of the internal {@link crypto_Cipher}s in this chain */ - function Ciform_CipherChain( $ciphers, $name="schemes" ) + function Ciform_CipherChain( $ciphers ) { - parent::Ciform_Scheme($name); + parent::Ciform_Scheme(NULL); $this->ciphers = $ciphers; } @@ -113,14 +129,12 @@ class Ciform_CipherChain extends Ciform_Scheme */ 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) ) + if ( $cleartext = $decoder->decode($packet,$this) ) { - return $message; + return $cleartext; } } @@ -137,6 +151,8 @@ class Ciform_CipherChain extends Ciform_Scheme */ function decode( $packet ) { + if ( CIFORM_DEBUG ) echo print_r($this,TRUE)."->decode($packet)"."\n"; + // 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 ); @@ -218,7 +234,7 @@ class Ciform_Codec extends Ciform_Scheme */ function decode( $packet, $chain=FALSE ) { - if ( CIFORM_DEBUG ) { echo print_r($this,TRUE),"->decode($packet,",print_r($chain,TRUE),")"."\n"; } + if ( CIFORM_DEBUG ) { echo print_r($this,TRUE),"->decode($packet,)"."\n"; } // uses the internal chain (if any) if the chain was not given as an argument $myChain = $chain ? $chain : ($this->chain ? $this->chain : FALSE); @@ -257,7 +273,7 @@ class Ciform_Codec extends Ciform_Scheme } } - if ( CIFORM_DEBUG ) { echo "unpacked=".print_r($this->unpack($packet),TRUE)."\n"; } + if ( CIFORM_DEBUG ) { echo "unpacked=$unpacked"."\n"; } // if no decoder was found, this object does not handle this scheme return FALSE; @@ -379,7 +395,7 @@ class Ciform_schemes_Base64 extends Ciform_SimpleScheme */ function Ciform_schemes_Base64( $unpackOnly=FALSE ) { - parent::Ciform_SimpleScheme("base64",'/^(?:base64|b64):(.*)$/',$unpackOnly); + parent::Ciform_SimpleScheme("base64",'/^(?:base64|b64):(.*)$/i',$unpackOnly); } function getDecoder( $packet ) diff --git a/ciform/trunk/src/crypto/ciphers/rsa.php b/ciform/trunk/src/crypto/ciphers/rsa.php index d1a2987..353deda 100644 --- a/ciform/trunk/src/crypto/ciphers/rsa.php +++ b/ciform/trunk/src/crypto/ciphers/rsa.php @@ -8,27 +8,19 @@ 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 + +/** Name of the entry in $_SESSION that will hold the current RSA key pairs */ +define("CIFORM_RSA_SESSION_KEYRING","CIFORM_RSA_SESSION_KEYRING"); +/** Default size, in bits, of the keys to generate */ +define("CIFORM_RSA_DEFAULT_KEYSIZE",768); +/** Path to the .PEM file containing the default key pair */ +define("CIFORM_RSA_DEFAULT_PEMFILE","keys/protected/key-rsa.pem"); +/** Path to the .json file containing the default public key */ +define("CIFORM_RSA_DEFAULT_JSFILE","keys/key-rsa.pub.json"); // 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(); @@ -43,22 +35,26 @@ if ( !isset($_SESSION[CIFORM_SESSION][CIFORM_SESSION_KEYPAIR]) ) /** - * This class extends Crypt_RSA_KeyPair by adding conversion functions to Javascript and to the Ciform protocol + * This class extends Crypt_RSA_KeyPair by adding conversion functions in order to conform to the Ciform protocol + * + * @package ciform + * @subpackage schemes.rsa */ -class Ciform_ciphers_rsa_KeyPair extends Crypt_RSA_KeyPair +class crypto_ciphers_rsa_KeyPair extends Crypt_RSA_KeyPair { /** - * Transforms a big integer value into a JSON array of 28 bits integers + * Transforms a big integer value into an 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 + * @return array The number as an array of 28 bits integers * @access private + * @static */ - function bigInt2Json( $binValue, $math=$this->_math_obj ) + function bigInt2Array( $binValue, $math=$this->_math_obj ) { - $json = "["; + $export = array(); $intValue = $math->bin2int($binValue); $szBits = $math->bitLen($intValue); // total length, in bits @@ -66,15 +62,11 @@ class Ciform_ciphers_rsa_KeyPair extends Crypt_RSA_KeyPair for ( $b=0 ; $b<$szBits ; ) { $l = min(28,$szBits-$b); - $json .= $math->subint($intValue, $b, $l); + $export[$b] = $math->subint($intValue, $b, $l); $b += $l; - if ( $b<$szBits ) - { - $json .= ","; - } } - return $json."]"; + return $export; } @@ -86,18 +78,18 @@ class Ciform_ciphers_rsa_KeyPair extends Crypt_RSA_KeyPair * @return array The public key as an associative array * @access private */ - function exportPubKey( $keyPair=$this ) + function pubKey2Array( $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); + $p = crypto_ciphers_rsa_KeyPair::bigInt2Array($keyPair->_attrs['p'],$math); + $q = crypto_ciphers_rsa_KeyPair::bigInt2Array($keyPair->_attrs['q'],$math); + $e = crypto_ciphers_rsa_KeyPair::bigInt2Array($pubKey->getExponent(),$math); + $pq = crypto_ciphers_rsa_KeyPair::bigInt2Array($pubKey->getModulus(),$math); //$mpi = base64_encode($math->bin2int($pubKey->getModulus())+$math->bin2int($pubKey->getExponent())); $export = array( - 'type' => CIFORM_RSA_KEYTYPE, + 'type' => "rsa", '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 @@ -116,7 +108,7 @@ class Ciform_ciphers_rsa_KeyPair extends Crypt_RSA_KeyPair * * @param Crypt_RSA_KeyPair $keyPair The key pair to copy * @return $this - * @todo This implementation depends totally on the version of the superclass : + * FIXME This implementation totally depends on private parts of the superclass : * if a field is added or removed, this method can very possibly fail to do its job * @private */ @@ -161,12 +153,18 @@ class Ciform_ciphers_rsa_KeyPair extends Crypt_RSA_KeyPair * @access private * @static */ - function genKeyPair( $keySize, $pemFilename, $jsFilename, $force=FALSE ) + function getInstance( $keyId, $keySize, $pemFilename, $jsFilename, $force=FALSE ) { - // if the key has been stored to a file, get it from there + // first of all, if the key is in the current session, retrieve it + if ( isset($keyId) && isset($_SESSION[CIFORM_RSA_SESSION_KEYRING][$keyId]) ) + { + return $_SESSION[CIFORM_RSA_SESSION_KEYRING][$keyId]; + } + + // second chance : 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); + return crypto_ciphers_rsa_KeyPair::fromPEMString($contents); } // else, generate a new key and try to store it to a file @@ -202,107 +200,81 @@ class Ciform_ciphers_rsa_KeyPair extends Crypt_RSA_KeyPair -/** - * Ciform handler using the RSA cipher - */ -class Ciform_RSA extends Ciform_ +class crypto_ciphers_RSA extends crypto_Cipher { - + var $keyPair; + var $cipher; - /** - * @return Ciform_RSA_KeyPair the current key pair (or a new one if none defined) - */ - function getKeyPair() + + function crypto_ciphers_RSA( $keyPair ) { - 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; - } + if ( CIFORM_DEBUG ) echo "new crypto_ciphers_RSA()
"; + $this->keyPair = $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); + $this->cipher = new Crypt_RSA($this->getPrivateKey->getKeyLength(),'BCMath'); + + if ( CIFORM_DEBUG ) echo "keyPair=".print_r($keyPair,TRUE)."
"; + } + + + function &getInstance( $keyId, $keySize=CIFORM_RSA_KEYSIZE, $pemFile=CIFORM_RSA_KEYFILE_PEM, $jsFile=CIFORM_RSA_KEYFILE_JS, $forceGen=FALSE ) + { + return new crypto_ciphers_RSA( crypto_ciphers_rsa_KeyPair::getInstance($keyId,$keySize,$pemFile,$jsFile,$forceGen) ); + } + + + function decode( $ciphertext ) + { + if ( CIFORM_DEBUG ) echo print_r($this,TRUE)."->decode($ciphertext)
"; + + return $rsa->decrypt( $ciphertext, $keyPair->getPrivateKey() ); } } - - - - - +/** + * Ciform handler using the RSA cipher + */ class Ciform_schemes_RSA extends Ciform_SimpleScheme { - function Ciform_schemes_RSA() + var $keyId; + var $keySize; + var $pemFile; + var $jsFile; + var $forceGen; + + + function Ciform_schemes_RSA( $keyId=NULL, $keySize=CIFORM_RSA_KEYSIZE, $pemFile=CIFORM_RSA_KEYFILE_PEM, $jsFile=CIFORM_RSA_KEYFILE_JS, $forceGen=FALSE ) { parent::Ciform_SimpleScheme("rsa",'/^rsa:(.*)(:.+)?$/i'); + $this->keyId = $keyId; + $this->keySize = $keySize; + $this->pemFile = $pemFile; + $this->jsFile = $jsFile; + $this->forceGen = $forceGen; } + function export() { - return array( 'pubKey' => $keyPair->exportPubKey() ); + return array( 'pubKey' => $this->getKeyPair()->pubKey2Array() ); } + function getDecoder( $packet ) { if ( CIFORM_DEBUG ) { echo print_r($this,TRUE)."->getDecoder($packet)"."\n"; } if ( $this->unpack($packet) ) { - return new crypto_ciphers_Base64(); + return crypto_ciphers_RSA::getInstance( $this->keyId, $this->keySize, $this->pemFile, $this->jsFile, $this->forceGen ); } 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