* @link http://status.net/
*/
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
require_once 'Crypt/RSA.php';
-class Magicsig extends Memcached_DataObject
+class Magicsig extends Managed_DataObject
{
-
const PUBLICKEYREL = 'magic-public-key';
public $__table = 'magicsig';
+ /**
+ * Key to user.id/profile.id for the local user whose key we're storing.
+ *
+ * @var int
+ */
public $user_id;
+
+ /**
+ * Flattened string representation of the key pair; callers should
+ * usually use $this->publicKey and $this->privateKey directly,
+ * which hold live Crypt_RSA key objects.
+ *
+ * @var string
+ */
public $keypair;
+
+ /**
+ * Crypto algorithm used for this key; currently only RSA-SHA256 is supported.
+ *
+ * @var string
+ */
public $alg;
+ /**
+ * Public RSA key; gets serialized in/out via $this->keypair string.
+ *
+ * @var Crypt_RSA
+ */
public $publicKey;
+
+ /**
+ * PrivateRSA key; gets serialized in/out via $this->keypair string.
+ *
+ * @var Crypt_RSA
+ */
public $privateKey;
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)) {
- $obj = Magicsig::fromString($obj->keypair);
-
- // Double check keys: Crypt_RSA did not
- // consistently generate good keypairs.
- // We've also moved to 1024 bit keys.
- if (strlen($obj->publicKey->modulus->toBits()) != 1024) {
- $obj->delete();
- return false;
- }
- }
-
- return $obj;
- }
-
-
function table()
{
return array(
64, false));
}
-
function keys()
{
return array_keys($this->keyTypes());
return array(false, false, false);
}
+ /**
+ * Save this keypair into the database.
+ *
+ * Overloads default insert behavior to encode the live key objects
+ * as a flat string for storage.
+ *
+ * @return mixed
+ */
function insert()
{
$this->keypair = $this->toString();
return parent::insert();
}
+ /**
+ * Generate a new keypair for a local user and store in the database.
+ *
+ * Warning: this can be very slow on systems without the GMP module.
+ * Runtimes of 20-30 seconds are not unheard-of.
+ *
+ * @param int $user_id id of local user we're creating a key for
+ */
public function generate($user_id)
{
$rsa = new Crypt_RSA();
$this->insert();
}
-
+ /**
+ * Encode the keypair or public key as a string.
+ *
+ * @param boolean $full_pair set to false to leave out the private key.
+ * @return string
+ */
public function toString($full_pair = true)
{
$mod = Magicsig::base64_url_encode($this->publicKey->modulus->toBytes());
return 'RSA.' . $mod . '.' . $exp . $private_exp;
}
+ /**
+ * Decode a string representation of an RSA public key or keypair
+ * as a Magicsig object which can be used to sign or verify.
+ *
+ * @param string $text
+ * @return Magicsig
+ */
public static function fromString($text)
{
$magic_sig = new Magicsig();
return $magic_sig;
}
+ /**
+ * Fill out $this->privateKey or $this->publicKey with a Crypt_RSA object
+ * representing the give key (as mod/exponent pair).
+ *
+ * @param string $mod base64-encoded
+ * @param string $exp base64-encoded exponent
+ * @param string $type one of 'public' or 'private'
+ */
public function loadKey($mod, $exp, $type = 'public')
{
common_log(LOG_DEBUG, "Adding ".$type." key: (".$mod .', '. $exp .")");
}
}
+ /**
+ * Returns the name of the crypto algorithm used for this key.
+ *
+ * @return string
+ */
public function getName()
{
return $this->alg;
}
+ /**
+ * Returns the name of a hash function to use for signing with this key.
+ *
+ * @return string
+ * @fixme is this used? doesn't seem to be called by name.
+ */
public function getHash()
{
switch ($this->alg) {
case 'RSA-SHA256':
return 'sha256';
}
-
}
+ /**
+ * Generate base64-encoded signature for the given byte string
+ * using our private key.
+ *
+ * @param string $bytes as raw byte string
+ * @return string base64-encoded signature
+ */
public function sign($bytes)
{
$sig = $this->privateKey->sign($bytes);
return Magicsig::base64_url_encode($sig);
}
+ /**
+ *
+ * @param string $signed_bytes as raw byte string
+ * @param string $signature as base64
+ * @return boolean
+ */
public function verify($signed_bytes, $signature)
{
$signature = Magicsig::base64_url_decode($signature);
return $this->publicKey->verify($signed_bytes, $signature);
}
-
+ /**
+ * URL-encoding-friendly base64 variant encoding.
+ *
+ * @param string $input
+ * @return string
+ */
public static function base64_url_encode($input)
{
return strtr(base64_encode($input), '+/', '-_');
}
+ /**
+ * URL-encoding-friendly base64 variant decoding.
+ *
+ * @param string $input
+ * @return string
+ */
public static function base64_url_decode($input)
{
return base64_decode(strtr($input, '-_', '+/'));