]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/OStatus/classes/Magicsig.php
02882d19b13e1750e43e1b31c7fe7c3a55263d62
[quix0rs-gnu-social.git] / plugins / OStatus / classes / Magicsig.php
1 <?php
2 /**
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2010, StatusNet, Inc.
5  *
6  * A sample module to show best practices for StatusNet plugins
7  *
8  * PHP version 5
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Affero General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Affero General Public License for more details.
19  *
20  * You should have received a copy of the GNU Affero General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  * @package   StatusNet
24  * @author    James Walker <james@status.net>
25  * @copyright 2010 StatusNet, Inc.
26  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
27  * @link      http://status.net/
28  */
29
30 require_once 'Crypt/RSA.php';
31
32 class Magicsig extends Memcached_DataObject
33 {
34
35     const PUBLICKEYREL = 'magic-public-key';
36     
37     public $__table = 'magicsig';
38
39     public $user_id;
40     public $keypair;
41     public $alg;
42     
43     private $_rsa;
44
45     public function __construct($alg = 'RSA-SHA256')
46     {
47         $this->alg = $alg;
48     }
49     
50     public /*static*/ function staticGet($k, $v=null)
51     {
52         return parent::staticGet(__CLASS__, $k, $v);
53     }
54
55
56     function table()
57     {
58         return array(
59             'user_id' => DB_DATAOBJECT_INT,
60             'keypair' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
61             'alg'     => DB_DATAOBJECT_STR
62         );
63     }
64
65     static function schemaDef()
66     {
67         return array(new ColumnDef('user_id', 'integer',
68                                    null, true, 'PRI'),
69                      new ColumnDef('keypair', 'varchar',
70                                    255, false),
71                      new ColumnDef('alg', 'varchar',
72                                    64, false));
73     }
74
75
76     function keys()
77     {
78         return array_keys($this->keyTypes());
79     }
80
81     function keyTypes()
82     {
83         return array('user_id' => 'K');
84     }
85
86     function insert()
87     {
88         $this->keypair = $this->toString();
89
90         return parent::insert();
91     }
92
93     public function generate($user_id, $key_length = 512)
94     {
95         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
96
97         $keypair = new Crypt_RSA_KeyPair($key_length);
98         $params['public_key'] = $keypair->getPublicKey();
99         $params['private_key'] = $keypair->getPrivateKey();
100
101         $this->_rsa = new Crypt_RSA($params);
102         PEAR::popErrorHandling();
103
104         $this->user_id = $user_id;
105         $this->insert();
106     }
107
108
109     public function toString($full_pair = true)
110     {
111         $public_key = $this->_rsa->_public_key;
112         $private_key = $this->_rsa->_private_key;
113
114         $mod = base64_url_encode($public_key->getModulus());
115         $exp = base64_url_encode($public_key->getExponent());
116         $private_exp = '';
117         if ($full_pair && $private_key->getExponent()) {
118             $private_exp = '.' . base64_url_encode($private_key->getExponent());
119         }
120
121         return 'RSA.' . $mod . '.' . $exp . $private_exp; 
122     }
123     
124     public static function fromString($text)
125     {
126         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
127
128         $magic_sig = new Magicsig();
129         
130         // remove whitespace
131         $text = preg_replace('/\s+/', '', $text);
132
133         // parse components
134         if (!preg_match('/RSA\.([^\.]+)\.([^\.]+)(.([^\.]+))?/', $text, $matches)) {
135             return false;
136         }
137         
138         $mod = base64_url_decode($matches[1]);
139         $exp = base64_url_decode($matches[2]);
140         if ($matches[4]) {
141             $private_exp = base64_url_decode($matches[4]);
142         }
143
144         $params['public_key'] = new Crypt_RSA_KEY($mod, $exp, 'public');
145         if ($params['public_key']->isError()) {
146             $error = $params['public_key']->getLastError();
147             common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage());
148             return false;
149         }
150         if ($private_exp) {
151             $params['private_key'] = new Crypt_RSA_KEY($mod, $private_exp, 'private');
152             if ($params['private_key']->isError()) {
153                 $error = $params['private_key']->getLastError();
154                 common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage());
155                 return false;
156             }
157         }
158
159         $magic_sig->_rsa = new Crypt_RSA($params);
160         PEAR::popErrorHandling();
161
162         return $magic_sig;
163     }
164
165     public function getName()
166     {
167         return $this->alg;
168     }
169
170     public function getHash()
171     {
172         switch ($this->alg) {
173
174         case 'RSA-SHA256':
175             return 'sha256';
176         }
177
178     }
179     
180     public function sign($bytes)
181     {
182         $sig = $this->_rsa->createSign($bytes, null, 'sha256');
183         if ($this->_rsa->isError()) {
184             $error = $this->_rsa->getLastError();
185             common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage());
186             return false;
187         }
188
189         return $sig;
190     }
191
192     public function verify($signed_bytes, $signature)
193     {
194         $result =  $this->_rsa->validateSign($signed_bytes, $signature, null, 'sha256');
195         if ($this->_rsa->isError()) {
196             $error = $this->keypair->getLastError();
197             common_log(LOG_DEBUG, 'RSA Error: '. $error->getMessage());
198             return false;
199         }
200         return $result;
201     }
202         
203 }
204
205 // Define a sha256 function for hashing
206 // (Crypt_RSA should really be updated to use hash() )
207 function sha256($bytes)
208 {
209     return hash('sha256', $bytes);
210 }
211
212 function base64_url_encode($input)
213 {
214     return strtr(base64_encode($input), '+/', '-_');
215 }
216
217 function base64_url_decode($input)
218 {
219     return base64_decode(strtr($input, '-_', '+/'));
220 }