diff options
Diffstat (limited to 'plugins/OStatus/classes/Magicsig.php')
-rw-r--r-- | plugins/OStatus/classes/Magicsig.php | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/plugins/OStatus/classes/Magicsig.php b/plugins/OStatus/classes/Magicsig.php new file mode 100644 index 000000000..5a46aeeb6 --- /dev/null +++ b/plugins/OStatus/classes/Magicsig.php @@ -0,0 +1,233 @@ +<?php +/** + * StatusNet - the distributed open-source microblogging tool + * Copyright (C) 2010, StatusNet, Inc. + * + * A sample module to show best practices for StatusNet plugins + * + * PHP version 5 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package StatusNet + * @author James Walker <james@status.net> + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +require_once 'Crypt/RSA.php'; + +class Magicsig extends Memcached_DataObject +{ + + const PUBLICKEYREL = 'magic-public-key'; + + public $__table = 'magicsig'; + + public $user_id; + public $keypair; + public $alg; + + private $_rsa; + + public function __construct($alg = 'RSA-SHA256') + { + $this->alg = $alg; + } + + public /*static*/ function staticGet($k, $v=null) + { + $obj = parent::staticGet(__CLASS__, $k, $v); + if (!empty($obj)) { + return Magicsig::fromString($obj->keypair); + } + + return $obj; + } + + + function table() + { + return array( + 'user_id' => DB_DATAOBJECT_INT, + 'keypair' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, + 'alg' => DB_DATAOBJECT_STR + ); + } + + static function schemaDef() + { + return array(new ColumnDef('user_id', 'integer', + null, true, 'PRI'), + new ColumnDef('keypair', 'varchar', + 255, false), + new ColumnDef('alg', 'varchar', + 64, false)); + } + + + function keys() + { + return array_keys($this->keyTypes()); + } + + function keyTypes() + { + return array('user_id' => 'K'); + } + + function sequenceKey() { + return array(false, false, false); + } + + function insert() + { + $this->keypair = $this->toString(); + + return parent::insert(); + } + + public function generate($user_id, $key_length = 512) + { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + + $keypair = new Crypt_RSA_KeyPair($key_length); + $params['public_key'] = $keypair->getPublicKey(); + $params['private_key'] = $keypair->getPrivateKey(); + + $this->_rsa = new Crypt_RSA($params); + PEAR::popErrorHandling(); + + $this->user_id = $user_id; + $this->insert(); + } + + + public function toString($full_pair = true) + { + $public_key = $this->_rsa->_public_key; + $private_key = $this->_rsa->_private_key; + + $mod = base64_url_encode($public_key->getModulus()); + $exp = base64_url_encode($public_key->getExponent()); + $private_exp = ''; + if ($full_pair && $private_key->getExponent()) { + $private_exp = '.' . base64_url_encode($private_key->getExponent()); + } + + return 'RSA.' . $mod . '.' . $exp . $private_exp; + } + + public static function fromString($text) + { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + + $magic_sig = new Magicsig(); + + // remove whitespace + $text = preg_replace('/\s+/', '', $text); + + // parse components + if (!preg_match('/RSA\.([^\.]+)\.([^\.]+)(.([^\.]+))?/', $text, $matches)) { + return false; + } + + $mod = base64_url_decode($matches[1]); + $exp = base64_url_decode($matches[2]); + if (!empty($matches[4])) { + $private_exp = base64_url_decode($matches[4]); + } else { + $private_exp = false; + } + + $params['public_key'] = new Crypt_RSA_KEY($mod, $exp, 'public'); + if ($params['public_key']->isError()) { + $error = $params['public_key']->getLastError(); + common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage()); + return false; + } + if ($private_exp) { + $params['private_key'] = new Crypt_RSA_KEY($mod, $private_exp, 'private'); + if ($params['private_key']->isError()) { + $error = $params['private_key']->getLastError(); + common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage()); + return false; + } + } + + $magic_sig->_rsa = new Crypt_RSA($params); + PEAR::popErrorHandling(); + + return $magic_sig; + } + + public function getName() + { + return $this->alg; + } + + public function getHash() + { + switch ($this->alg) { + + case 'RSA-SHA256': + return 'magicsig_sha256'; + } + + } + + public function sign($bytes) + { + $hash = $this->getHash(); + $sig = $this->_rsa->createSign($bytes, null, $hash); + if ($this->_rsa->isError()) { + $error = $this->_rsa->getLastError(); + common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage()); + return false; + } + + return $sig; + } + + public function verify($signed_bytes, $signature) + { + $hash = $this->getHash(); + $result = $this->_rsa->validateSign($signed_bytes, $signature, null, $hash); + if ($this->_rsa->isError()) { + $error = $this->keypair->getLastError(); + common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage()); + return false; + } + return $result; + } + +} + +// Define a sha256 function for hashing +// (Crypt_RSA should really be updated to use hash() ) +function magicsig_sha256($bytes) +{ + return hash('sha256', $bytes); +} + +function base64_url_encode($input) +{ + return strtr(base64_encode($input), '+/', '-_'); +} + +function base64_url_decode($input) +{ + return base64_decode(strtr($input, '-_', '+/')); +}
\ No newline at end of file |