mirror of
https://github.com/nicolabs/ciform.git
synced 2026-04-11 00:14:41 +02:00
+ first import
This commit is contained in:
parent
fcd8b5fc87
commit
c8f0515376
380
ciform/trunk/src/ciform.js
Normal file
380
ciform/trunk/src/ciform.js
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
/**
|
||||
@fileoverview
|
||||
|
||||
This library provides specifications and basic functions to add encryption functionalities to an HTML form,
|
||||
therefore called "Ciform".
|
||||
|
||||
@requires base64.js {@link www.haneWIN.de}
|
||||
@requires hex.js {@link www.haneWIN.de}
|
||||
@requires sha1.js {@link www.haneWIN.de}
|
||||
@requires rsa.js {@link www.haneWIN.de}
|
||||
*/
|
||||
// Data from the server is available in a literal object named 'CIFORM'
|
||||
// e.g. { 'serverURL':"login.php", 'pubKey':{'type':'rsa', 'e':10000,'m':24} }
|
||||
|
||||
// TODO : define the Ciform protocol using constants that can change from one server to another
|
||||
// This protocol would be retrieved from the server (either with a <script src> or using Ajax) so nothing is hard coded
|
||||
|
||||
// defines a namespace for this project
|
||||
ciform = {}; // end of ns:ciform
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// DEFAULT ENCODER
|
||||
//
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Implementations of an encoder must re-define all the defined method.
|
||||
@constructor
|
||||
*/
|
||||
ciform.Encoder = function()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
The basic way to encode/encrypt a message.
|
||||
|
||||
@param {String} message The text to encrypt
|
||||
@return the encrypted message (ciphertext) : the result depends on the encoder
|
||||
*/
|
||||
ciform.Encoder.prototype.encode = function( message )
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// SHA-1 ENCODER
|
||||
//
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@param {Object} options Default values :
|
||||
- 'preamble' = false (don't add meta-data in the beginning of the ciphertext)
|
||||
@constructor
|
||||
*/
|
||||
ciform.SHA1Encoder = function( options )
|
||||
{
|
||||
this.options = options ? options : {'preamble':false};
|
||||
}
|
||||
ciform.SHA1Encoder.prototype = new ciform.Encoder();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@see ciform#Encoder#encode
|
||||
@return the sha-1 of the message, base64 encoded, with meta-data about the encoding if this.options['preamble'] is true
|
||||
*/
|
||||
ciform.SHA1Encoder.prototype.encode = function( message )
|
||||
{
|
||||
console.debug(this,"encode(",message,")");
|
||||
return (this.options['preamble'] ? "sha1:b64:" : "") + b64_sha1(message);
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// RSA ENCODER
|
||||
//
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@param {Object} pubKey The public key to use for encryption : a dictionary with the following fields :
|
||||
- 'type' : must be 'rsa'
|
||||
- 'pq' : modulo of the RSA key
|
||||
- 'e' : exponent of the RSA key
|
||||
- 'mpi' (optional) : the RSA key as a base64 encoded mutli-precision integer
|
||||
@param {Object} options Default values :
|
||||
- 'preamble' = false (don't add meta-data in the beginning of the ciphertext)
|
||||
- 'salt' = false (don't add salt in the beginning of the ciphertext : WARNING : without salt, the same message encoded with the same key will always give the same ciphertext)
|
||||
- 'checkPadding' = true (check that the padding scheme is correct : does not apply if salt is added)
|
||||
@throw TypeError if the public key is not correct
|
||||
@constructor
|
||||
*/
|
||||
ciform.RSAEncoder = function( pubKey, options )
|
||||
{
|
||||
this.options = options ? options : {'preamble':false,'salt':false,'nopadding':false};
|
||||
|
||||
if ( pubKey['type'] == "rsa" )
|
||||
{
|
||||
if ( pubKey['pq'] && pubKey['e'] )
|
||||
{
|
||||
this.pubKey = pubKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new TypeError("Public key is missing a field : both 'pq' and 'e' are required");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new TypeError("Type of public key must be 'rsa'");
|
||||
}
|
||||
};
|
||||
ciform.RSAEncoder.prototype = new ciform.Encoder();
|
||||
|
||||
|
||||
|
||||
ciform.RSAEncoder.prototype.SALT_MAX = 9999;
|
||||
ciform.RSAEncoder.prototype.SALT_MIN = 1;
|
||||
|
||||
|
||||
|
||||
ciform.RSAEncoder.prototype._getMPI = function()
|
||||
{
|
||||
// this function can be called several times so we don't compute the following each time
|
||||
if ( ! this.pubKey['mpi'] )
|
||||
{
|
||||
this.pubKey['mpi'] = s2r(b2mpi(this.pubKey['pq'])+b2mpi([this.pubKey['e']])).replace(/\n/,'');
|
||||
}
|
||||
|
||||
return this.pubKey['mpi'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@return a random number between this.SALT_MIN and this.SALT_MAX
|
||||
*/
|
||||
ciform.RSAEncoder.prototype._getSalt = function()
|
||||
{
|
||||
return Math.floor(Math.random() * (this.SALT_MAX - this.SALT_MIN + 1) + this.SALT_MIN);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Computes the maximum length the message should be to prevent attacks against RSA without padding
|
||||
(http://en.wikipedia.org/wiki/RSA#Padding_schemes)
|
||||
|
||||
@return the max. length for a message to be encoded.
|
||||
In case salt is added to the ciphertext, the real max. length might be longer,
|
||||
because the salt has a variable length
|
||||
@see ciform.RSAEncoder#_getSalt
|
||||
*/
|
||||
ciform.RSAEncoder.prototype.maxLength = function()
|
||||
{
|
||||
var s = r2s(this._getMPI());
|
||||
var l = Math.floor((s.charCodeAt(0)*256 + s.charCodeAt(1)+7)/8);
|
||||
|
||||
var lmax = l - 4;
|
||||
|
||||
if ( this.options['salt'] )
|
||||
{
|
||||
lmax -= new Number(this.SALT_MAX).toString().length;
|
||||
}
|
||||
|
||||
console.debug(this,".maxLength()=",lmax);
|
||||
return lmax;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@see ciform.Encoder#encode
|
||||
@return the ciphertext of the message, encoded with the public RSA key of this encoder, with meta-data about the encoding if this.options['preamble'] is true
|
||||
@throws RangeError if the message is too long to be secure for the current public key (ignored if either 'salt' or 'nopadding' is true)
|
||||
*/
|
||||
ciform.RSAEncoder.prototype.encode = function( message )
|
||||
{
|
||||
console.debug(this,"encode(",message,")");
|
||||
|
||||
var mod=new Array();
|
||||
var exp=new Array();
|
||||
|
||||
//var s = r2s(this._getMPI());
|
||||
//var l = Math.floor((s.charCodeAt(0)*256 + s.charCodeAt(1)+7)/8);
|
||||
|
||||
//mod = mpi2b(s.substr(0,l+2));
|
||||
//exp = mpi2b(s.substr(l+2));
|
||||
|
||||
mod = this.pubKey['pq'];
|
||||
exp = this.pubKey['e'];
|
||||
|
||||
var saltMessage = message;
|
||||
if ( this.options['salt'] )
|
||||
{
|
||||
// some salt to randomize the string
|
||||
var salt = this._getSalt();
|
||||
console.debug("salt="+salt);
|
||||
saltMessage = "salt" + salt + ":" + message;
|
||||
}
|
||||
|
||||
var p = saltMessage+String.fromCharCode(1);
|
||||
|
||||
var maxLength = this.maxLength();
|
||||
if ( !this.options['nopadding'] && !this.options['salt'] && p.length > maxLength )
|
||||
{
|
||||
throw new RangeError("Plain text length must be less than "+maxLength+" characters");
|
||||
}
|
||||
|
||||
var b = s2b(p);
|
||||
|
||||
// rsa-encrypts the result and converts into mpi
|
||||
var ciphertext = RSAencrypt(b,exp,mod);
|
||||
|
||||
return (this.options['preamble'] ? "rsa:0x" : "") + s2hex(b2s(ciphertext));
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// CHAIN ENCODER
|
||||
//
|
||||
|
||||
|
||||
|
||||
/**
|
||||
This encoder simply combine encoders in a chain.
|
||||
For instance, the message will be first hashed through SHA-1, and then encrypted with a RSA key.
|
||||
@param {Array[ciform.Encoder]} encoders A list with the instances of encoders to use (The chain starts with index 0)
|
||||
*/
|
||||
ciform.ChainEncoder = function( encoders )
|
||||
{
|
||||
this.encoders = encoders;
|
||||
};
|
||||
ciform.ChainEncoder.prototype = new ciform.Encoder();
|
||||
|
||||
|
||||
|
||||
ciform.ChainEncoder.prototype.encode = function( message )
|
||||
{
|
||||
var ciphertext = message;
|
||||
|
||||
for ( var e=0 ; e<this.encoders.length ; e++ )
|
||||
{
|
||||
ciphertext = this.encoders[e].encode(ciphertext);
|
||||
}
|
||||
|
||||
return ciphertext;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// CIFORM HANDLER
|
||||
//
|
||||
|
||||
|
||||
|
||||
ciform.Ciform = function( form, pubKey )
|
||||
{
|
||||
this.form = form;
|
||||
this.pubKey = pubKey;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
This function should be called when the 'onsubmit' event happens.
|
||||
Its job is to encrypt 'input' fiels into 'output' fields.
|
||||
|
||||
@param {Object} fields An array with the inputs and outputs, like [ {'inputName1':'outputName1'}, {'inputName2':'outputName2'}, ... ].
|
||||
It can be either the DOM nodes, their id or name (in the latter, the second parameter must be set).
|
||||
Input and output can be the same : the input value will be replaced with the ciphertext.
|
||||
@param {HTMLFormElement} form The object containing the fields (optional)
|
||||
*/
|
||||
ciform.Ciform.prototype.encryptFields = function( fields, onError )
|
||||
{
|
||||
console.debug("encryptFields(",fields,onError,")");
|
||||
|
||||
var done = [];
|
||||
|
||||
for ( var f=0 ; f< fields.length ; f++ )
|
||||
{
|
||||
/*ciform.encryptFields([
|
||||
{'in':"f1",'out':"f2",'encoding':["hex","rsa","base64","sha1"]},
|
||||
{'in':"f3"},
|
||||
"f4"
|
||||
]);
|
||||
}*/
|
||||
// gets the nodes from either id, names or nodes
|
||||
var kIn = fields[f]['in'] ? fields[f]['in'] : fields[f];
|
||||
var kOut = fields[f]['out'] ? fields[f]['out'] : kIn;
|
||||
var nodIn = this.form ? this.form[kIn] : document.getElementById(kIn) ? document.getElementById(kIn) : kIn;
|
||||
var nodOut = this.form ? this.form[kOut] : document.getElementById(kOut) ? document.getElementById(kOut) : kOut;
|
||||
|
||||
//var message = nodIn.value;
|
||||
|
||||
var encoders = [];
|
||||
// takes care of one-level sha-1 encoding for such fields
|
||||
if ( /sha1/.test(nodOut.className) ) // FIXME : a more accurate filter
|
||||
{
|
||||
//message = b64_sha1(nodIn.value);
|
||||
if ( /ciform-sha1/.test(nodOut.className) )
|
||||
{
|
||||
// for this class we add meta-data
|
||||
// NOTE : message must not contain the ":" separator so it can be extracted later
|
||||
//message = "salt" + salt + ":b64:sha1:" + message;
|
||||
encoders.push( new ciform.SHA1Encoder({'preamble':true}) );
|
||||
}
|
||||
// fields to be encrypted are replaced with something else
|
||||
// because they're not supposed to be transmitted in clear
|
||||
// FIXME ? must respect character set and length of the original field
|
||||
//input_replacement = "";
|
||||
else
|
||||
{
|
||||
encoders.push( new ciform.SHA1Encoder() );
|
||||
}
|
||||
}
|
||||
encoders.push( new ciform.RSAEncoder(this.pubKey,{'preamble':true,'salt':true}) );
|
||||
var encoder = new ciform.ChainEncoder(encoders);
|
||||
|
||||
// encrypts the output field using the server's public key
|
||||
//var key = CIFORM[CIFORM_ID_PUBKEY];
|
||||
//var ciphertext = "ciform:rsa:0x" + ciform_encryptMessage(message,key);
|
||||
|
||||
try
|
||||
{
|
||||
var ciphertext = "ciform:" + encoder.encode(nodIn.value);
|
||||
done.push({'field':nodOut,'value':ciphertext});
|
||||
done.push({'field':nodIn,'value':""});
|
||||
}
|
||||
catch ( e )
|
||||
{
|
||||
// calls back the error handler if defined
|
||||
if ( onError )
|
||||
{
|
||||
onError.apply(null,[e]);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
/*// if everything went fine, stores the replacement values for later
|
||||
if ( ciphertext.length && ciphertext.length > 0 )
|
||||
{
|
||||
// TODO : lighter formalism : don't need to use formal object here
|
||||
done.push({'field':nodOut,'value':ciphertext});
|
||||
if ( input_replacement != null )
|
||||
{
|
||||
done.push({'field':input,'value':input_replacement});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// could happen if the text's length doesn't fit with the key's length
|
||||
return false;
|
||||
}*/
|
||||
} // iterating over fields is over
|
||||
|
||||
// replaces the values of the fiels (in the end, so that nothing is done if there's any error)
|
||||
for ( var f=0 ; f<done.length ; f++ )
|
||||
{
|
||||
done[f]['field'].value = done[f]['value'];
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
129
ciform/trunk/src/ciform.php
Normal file
129
ciform/trunk/src/ciform.php
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
// constants exportable to included scripts
|
||||
define("CIFORM_SESSION","CIFORM");
|
||||
define("CIFORM_SESSION_KEYPAIR","KEYPAIR"); // TODO : move to ciform_rsa.php
|
||||
if ( ! defined("CIFORM_DEBUG") ) define("CIFORM_DEBUG",FALSE);
|
||||
|
||||
require_once("ciform_rsa.php");
|
||||
|
||||
// private constants
|
||||
define("CIFORM_REQUEST_PREFIX","ciform:");
|
||||
define("CIFORM_KEYTYPE",CIFORM_RSA_KEYTYPE); // choose the desired encryption module here
|
||||
if ( ! defined("CIFORM_AUTODECRYPT") ) define("CIFORM_AUTODECRYPT", TRUE );
|
||||
|
||||
|
||||
|
||||
// TODO : embed the key in the data (e.g. ciform:rsa:keyId:0x12345:0xdd33be2b17813b396d63dd1be9c72e9756bbd8ae5d5555b93a7f4b4fd5a8c80d:salt24325234)
|
||||
function ciform_decode( $data, $keyPair, $base=1 )
|
||||
{
|
||||
if ( CIFORM_DEBUG ) echo "ciform_decrypt($data,keyPair,$base)<br>";
|
||||
|
||||
// $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;
|
||||
}
|
||||
|
||||
|
||||
// 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]);
|
||||
}
|
||||
?>
|
||||
11
ciform/trunk/src/ciform_pgp.php
Normal file
11
ciform/trunk/src/ciform_pgp.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
define("CIFORM_KEYTYPE_PGP_RSA","pgp_rsa");
|
||||
define("CIFORM_KEYTYPE_PGP_ELGAMAL","pgp_elgamal");
|
||||
|
||||
|
||||
|
||||
function ciform_pgp_rsa_pubKey2Json( $pubKey )
|
||||
{
|
||||
return "{'type':'".CIFORM_KEYTYPE_PGP_RSA."', keyId:'".$pubKey->getKeyId()."' 'mpib64Value':'".$pubKey->getMPIBase64()."'};";
|
||||
}
|
||||
?>
|
||||
139
ciform/trunk/src/ciform_rsa.php
Normal file
139
ciform/trunk/src/ciform_rsa.php
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
<?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.js");
|
||||
define("CIFORM_RSA_REQUEST_GENKEY","ciform-genkey");
|
||||
|
||||
|
||||
// TODO : include the following functions in a class inheriting from RSA_KeyPair
|
||||
|
||||
|
||||
/**
|
||||
Transforms a big integer value into a JSON array of 28 bits integers
|
||||
*/
|
||||
function ciform_rsa_bigInt2Json( $math, $binValue )
|
||||
{
|
||||
$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."]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
function ciform_rsa_pubKey2Json( $keyPair )
|
||||
{
|
||||
$pubKey = $keyPair->getPublicKey();
|
||||
$math = $keyPair->_math_obj;
|
||||
$p = ciform_rsa_bigInt2Json($math,$keyPair->_attrs['p']);
|
||||
$q = ciform_rsa_bigInt2Json($math,$keyPair->_attrs['q']);
|
||||
$e = ciform_rsa_bigInt2Json($math,$pubKey->getExponent());
|
||||
$pq = ciform_rsa_bigInt2Json($math,$pubKey->getModulus());
|
||||
//$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 ; not required (=p*q)
|
||||
//.","
|
||||
//."'mpi':'$mpi'" // e + modulus, encoded into a base64 MPI string
|
||||
."}";
|
||||
return $json;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Uses an existing keypair stored in a file or generates a new one
|
||||
*/
|
||||
function ciform_rsa_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 Crypt_RSA_KeyPair::fromPEMString($contents);
|
||||
}
|
||||
|
||||
// else, generate a new key and try to store it to a file
|
||||
else
|
||||
{
|
||||
// generates the key
|
||||
$keyPair = new Crypt_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 = ciform_rsa_pubKey2Json($keyPair);
|
||||
$jsContents .= "\nvar CIFORM = {'serverURL':'".str_replace("'","\\'",$serverURL)."', 'pubKey':$pubKey};";
|
||||
@file_put_contents($jsFilename,$jsContents);
|
||||
}
|
||||
|
||||
// returns the newly created key
|
||||
return $keyPair;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function ciform_rsa_getKeyPair()
|
||||
{
|
||||
if ( CIFORM_DEBUG ) echo "ciform_rsa_getKeyPair() = ";
|
||||
$keyPair = ciform_rsa_genKeyPair(CIFORM_RSA_KEYSIZE, CIFORM_RSA_KEYFILE_PEM, CIFORM_RSA_KEYFILE_JS);
|
||||
if ( CIFORM_DEBUG ) print_r($keyPair);
|
||||
return $keyPair;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function ciform_rsa_decrypt( $data, $keyPair )
|
||||
{
|
||||
if ( CIFORM_DEBUG ) echo "ciform_rsa_decrypt($data,keyPair)<br>";
|
||||
$privateKey = $keyPair->getPrivateKey();
|
||||
$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_genKeyPair(CIFORM_RSA_KEYSIZE, CIFORM_RSA_KEYFILE_PEM, CIFORM_RSA_KEYFILE_JS, TRUE);
|
||||
}
|
||||
|
||||
?>
|
||||
Loading…
Reference in a new issue