Rev 846 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
827 | daniel-mar | 1 | <?php |
2 | |||
3 | /** |
||
4 | * Generic EC Key Parsing Helper functions |
||
5 | * |
||
6 | * PHP version 5 |
||
7 | * |
||
874 | daniel-mar | 8 | * @category Crypt |
9 | * @package EC |
||
827 | daniel-mar | 10 | * @author Jim Wigginton <terrafrost@php.net> |
11 | * @copyright 2015 Jim Wigginton |
||
12 | * @license http://www.opensource.org/licenses/mit-license.html MIT License |
||
13 | * @link http://phpseclib.sourceforge.net |
||
14 | */ |
||
15 | |||
16 | namespace phpseclib3\Crypt\EC\Formats\Keys; |
||
17 | |||
18 | use ParagonIE\ConstantTime\Hex; |
||
19 | use phpseclib3\Common\Functions\Strings; |
||
20 | use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve; |
||
21 | use phpseclib3\Crypt\EC\BaseCurves\Binary as BinaryCurve; |
||
22 | use phpseclib3\Crypt\EC\BaseCurves\Prime as PrimeCurve; |
||
23 | use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve; |
||
24 | use phpseclib3\Exception\UnsupportedCurveException; |
||
25 | use phpseclib3\File\ASN1; |
||
26 | use phpseclib3\File\ASN1\Maps; |
||
27 | use phpseclib3\Math\BigInteger; |
||
28 | |||
29 | /** |
||
30 | * Generic EC Key Parsing Helper functions |
||
31 | * |
||
874 | daniel-mar | 32 | * @package EC |
827 | daniel-mar | 33 | * @author Jim Wigginton <terrafrost@php.net> |
874 | daniel-mar | 34 | * @access public |
827 | daniel-mar | 35 | */ |
36 | trait Common |
||
37 | { |
||
38 | /** |
||
39 | * Curve OIDs |
||
40 | * |
||
41 | * @var array |
||
42 | */ |
||
43 | private static $curveOIDs = []; |
||
44 | |||
45 | /** |
||
46 | * Child OIDs loaded |
||
47 | * |
||
48 | * @var bool |
||
49 | */ |
||
50 | protected static $childOIDsLoaded = false; |
||
51 | |||
52 | /** |
||
53 | * Use Named Curves |
||
54 | * |
||
55 | * @var bool |
||
56 | */ |
||
57 | private static $useNamedCurves = true; |
||
58 | |||
59 | /** |
||
60 | * Initialize static variables |
||
61 | */ |
||
62 | private static function initialize_static_variables() |
||
63 | { |
||
64 | if (empty(self::$curveOIDs)) { |
||
65 | // the sec* curves are from the standards for efficient cryptography group |
||
66 | // sect* curves are curves over binary finite fields |
||
67 | // secp* curves are curves over prime finite fields |
||
68 | // sec*r* curves are regular curves; sec*k* curves are koblitz curves |
||
69 | // brainpool*r* curves are regular prime finite field curves |
||
70 | // brainpool*t* curves are twisted versions of the brainpool*r* curves |
||
71 | self::$curveOIDs = [ |
||
72 | 'prime192v1' => '1.2.840.10045.3.1.1', // J.5.1, example 1 (aka secp192r1) |
||
73 | 'prime192v2' => '1.2.840.10045.3.1.2', // J.5.1, example 2 |
||
74 | 'prime192v3' => '1.2.840.10045.3.1.3', // J.5.1, example 3 |
||
75 | 'prime239v1' => '1.2.840.10045.3.1.4', // J.5.2, example 1 |
||
76 | 'prime239v2' => '1.2.840.10045.3.1.5', // J.5.2, example 2 |
||
77 | 'prime239v3' => '1.2.840.10045.3.1.6', // J.5.2, example 3 |
||
78 | 'prime256v1' => '1.2.840.10045.3.1.7', // J.5.3, example 1 (aka secp256r1) |
||
79 | |||
80 | // https://tools.ietf.org/html/rfc5656#section-10 |
||
81 | 'nistp256' => '1.2.840.10045.3.1.7', // aka secp256r1 |
||
82 | 'nistp384' => '1.3.132.0.34', // aka secp384r1 |
||
83 | 'nistp521' => '1.3.132.0.35', // aka secp521r1 |
||
84 | |||
85 | 'nistk163' => '1.3.132.0.1', // aka sect163k1 |
||
86 | 'nistp192' => '1.2.840.10045.3.1.1', // aka secp192r1 |
||
87 | 'nistp224' => '1.3.132.0.33', // aka secp224r1 |
||
88 | 'nistk233' => '1.3.132.0.26', // aka sect233k1 |
||
89 | 'nistb233' => '1.3.132.0.27', // aka sect233r1 |
||
90 | 'nistk283' => '1.3.132.0.16', // aka sect283k1 |
||
91 | 'nistk409' => '1.3.132.0.36', // aka sect409k1 |
||
92 | 'nistb409' => '1.3.132.0.37', // aka sect409r1 |
||
93 | 'nistt571' => '1.3.132.0.38', // aka sect571k1 |
||
94 | |||
95 | // from https://tools.ietf.org/html/rfc5915 |
||
96 | 'secp192r1' => '1.2.840.10045.3.1.1', // aka prime192v1 |
||
97 | 'sect163k1' => '1.3.132.0.1', |
||
98 | 'sect163r2' => '1.3.132.0.15', |
||
99 | 'secp224r1' => '1.3.132.0.33', |
||
100 | 'sect233k1' => '1.3.132.0.26', |
||
101 | 'sect233r1' => '1.3.132.0.27', |
||
102 | 'secp256r1' => '1.2.840.10045.3.1.7', // aka prime256v1 |
||
103 | 'sect283k1' => '1.3.132.0.16', |
||
104 | 'sect283r1' => '1.3.132.0.17', |
||
105 | 'secp384r1' => '1.3.132.0.34', |
||
106 | 'sect409k1' => '1.3.132.0.36', |
||
107 | 'sect409r1' => '1.3.132.0.37', |
||
108 | 'secp521r1' => '1.3.132.0.35', |
||
109 | 'sect571k1' => '1.3.132.0.38', |
||
110 | 'sect571r1' => '1.3.132.0.39', |
||
111 | // from http://www.secg.org/SEC2-Ver-1.0.pdf |
||
112 | 'secp112r1' => '1.3.132.0.6', |
||
113 | 'secp112r2' => '1.3.132.0.7', |
||
114 | 'secp128r1' => '1.3.132.0.28', |
||
115 | 'secp128r2' => '1.3.132.0.29', |
||
116 | 'secp160k1' => '1.3.132.0.9', |
||
117 | 'secp160r1' => '1.3.132.0.8', |
||
118 | 'secp160r2' => '1.3.132.0.30', |
||
119 | 'secp192k1' => '1.3.132.0.31', |
||
120 | 'secp224k1' => '1.3.132.0.32', |
||
121 | 'secp256k1' => '1.3.132.0.10', |
||
122 | |||
123 | 'sect113r1' => '1.3.132.0.4', |
||
124 | 'sect113r2' => '1.3.132.0.5', |
||
125 | 'sect131r1' => '1.3.132.0.22', |
||
126 | 'sect131r2' => '1.3.132.0.23', |
||
127 | 'sect163r1' => '1.3.132.0.2', |
||
128 | 'sect193r1' => '1.3.132.0.24', |
||
129 | 'sect193r2' => '1.3.132.0.25', |
||
130 | 'sect239k1' => '1.3.132.0.3', |
||
131 | |||
132 | // from http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.202.2977&rep=rep1&type=pdf#page=36 |
||
133 | /* |
||
134 | 'c2pnb163v1' => '1.2.840.10045.3.0.1', // J.4.1, example 1 |
||
135 | 'c2pnb163v2' => '1.2.840.10045.3.0.2', // J.4.1, example 2 |
||
136 | 'c2pnb163v3' => '1.2.840.10045.3.0.3', // J.4.1, example 3 |
||
137 | 'c2pnb172w1' => '1.2.840.10045.3.0.4', // J.4.2, example 1 |
||
138 | 'c2tnb191v1' => '1.2.840.10045.3.0.5', // J.4.3, example 1 |
||
139 | 'c2tnb191v2' => '1.2.840.10045.3.0.6', // J.4.3, example 2 |
||
140 | 'c2tnb191v3' => '1.2.840.10045.3.0.7', // J.4.3, example 3 |
||
141 | 'c2onb191v4' => '1.2.840.10045.3.0.8', // J.4.3, example 4 |
||
142 | 'c2onb191v5' => '1.2.840.10045.3.0.9', // J.4.3, example 5 |
||
143 | 'c2pnb208w1' => '1.2.840.10045.3.0.10', // J.4.4, example 1 |
||
144 | 'c2tnb239v1' => '1.2.840.10045.3.0.11', // J.4.5, example 1 |
||
145 | 'c2tnb239v2' => '1.2.840.10045.3.0.12', // J.4.5, example 2 |
||
146 | 'c2tnb239v3' => '1.2.840.10045.3.0.13', // J.4.5, example 3 |
||
147 | 'c2onb239v4' => '1.2.840.10045.3.0.14', // J.4.5, example 4 |
||
148 | 'c2onb239v5' => '1.2.840.10045.3.0.15', // J.4.5, example 5 |
||
149 | 'c2pnb272w1' => '1.2.840.10045.3.0.16', // J.4.6, example 1 |
||
150 | 'c2pnb304w1' => '1.2.840.10045.3.0.17', // J.4.7, example 1 |
||
151 | 'c2tnb359v1' => '1.2.840.10045.3.0.18', // J.4.8, example 1 |
||
152 | 'c2pnb368w1' => '1.2.840.10045.3.0.19', // J.4.9, example 1 |
||
153 | 'c2tnb431r1' => '1.2.840.10045.3.0.20', // J.4.10, example 1 |
||
154 | */ |
||
155 | |||
156 | // http://www.ecc-brainpool.org/download/Domain-parameters.pdf |
||
157 | // https://tools.ietf.org/html/rfc5639 |
||
158 | 'brainpoolP160r1' => '1.3.36.3.3.2.8.1.1.1', |
||
159 | 'brainpoolP160t1' => '1.3.36.3.3.2.8.1.1.2', |
||
160 | 'brainpoolP192r1' => '1.3.36.3.3.2.8.1.1.3', |
||
161 | 'brainpoolP192t1' => '1.3.36.3.3.2.8.1.1.4', |
||
162 | 'brainpoolP224r1' => '1.3.36.3.3.2.8.1.1.5', |
||
163 | 'brainpoolP224t1' => '1.3.36.3.3.2.8.1.1.6', |
||
164 | 'brainpoolP256r1' => '1.3.36.3.3.2.8.1.1.7', |
||
165 | 'brainpoolP256t1' => '1.3.36.3.3.2.8.1.1.8', |
||
166 | 'brainpoolP320r1' => '1.3.36.3.3.2.8.1.1.9', |
||
167 | 'brainpoolP320t1' => '1.3.36.3.3.2.8.1.1.10', |
||
168 | 'brainpoolP384r1' => '1.3.36.3.3.2.8.1.1.11', |
||
169 | 'brainpoolP384t1' => '1.3.36.3.3.2.8.1.1.12', |
||
170 | 'brainpoolP512r1' => '1.3.36.3.3.2.8.1.1.13', |
||
171 | 'brainpoolP512t1' => '1.3.36.3.3.2.8.1.1.14' |
||
172 | ]; |
||
173 | ASN1::loadOIDs([ |
||
174 | 'prime-field' => '1.2.840.10045.1.1', |
||
175 | 'characteristic-two-field' => '1.2.840.10045.1.2', |
||
176 | 'characteristic-two-basis' => '1.2.840.10045.1.2.3', |
||
177 | // per http://www.secg.org/SEC1-Ver-1.0.pdf#page=84, gnBasis "not used here" |
||
178 | 'gnBasis' => '1.2.840.10045.1.2.3.1', // NULL |
||
179 | 'tpBasis' => '1.2.840.10045.1.2.3.2', // Trinomial |
||
180 | 'ppBasis' => '1.2.840.10045.1.2.3.3' // Pentanomial |
||
181 | ] + self::$curveOIDs); |
||
182 | } |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * Explicitly set the curve |
||
187 | * |
||
188 | * If the key contains an implicit curve phpseclib needs the curve |
||
189 | * to be explicitly provided |
||
190 | * |
||
191 | * @param \phpseclib3\Crypt\EC\BaseCurves\Base $curve |
||
192 | */ |
||
193 | public static function setImplicitCurve(BaseCurve $curve) |
||
194 | { |
||
195 | self::$implicitCurve = $curve; |
||
196 | } |
||
197 | |||
198 | /** |
||
199 | * Returns an instance of \phpseclib3\Crypt\EC\BaseCurves\Base based |
||
200 | * on the curve parameters |
||
201 | * |
||
202 | * @param array $params |
||
203 | * @return \phpseclib3\Crypt\EC\BaseCurves\Base|false |
||
204 | */ |
||
205 | protected static function loadCurveByParam(array $params) |
||
206 | { |
||
207 | if (count($params) > 1) { |
||
208 | throw new \RuntimeException('No parameters are present'); |
||
209 | } |
||
210 | if (isset($params['namedCurve'])) { |
||
211 | $curve = '\phpseclib3\Crypt\EC\Curves\\' . $params['namedCurve']; |
||
212 | if (!class_exists($curve)) { |
||
213 | throw new UnsupportedCurveException('Named Curve of ' . $params['namedCurve'] . ' is not supported'); |
||
214 | } |
||
215 | return new $curve(); |
||
216 | } |
||
217 | if (isset($params['implicitCurve'])) { |
||
218 | if (!isset(self::$implicitCurve)) { |
||
219 | throw new \RuntimeException('Implicit curves can be provided by calling setImplicitCurve'); |
||
220 | } |
||
221 | return self::$implicitCurve; |
||
222 | } |
||
223 | if (isset($params['specifiedCurve'])) { |
||
224 | $data = $params['specifiedCurve']; |
||
225 | switch ($data['fieldID']['fieldType']) { |
||
226 | case 'prime-field': |
||
227 | $curve = new PrimeCurve(); |
||
228 | $curve->setModulo($data['fieldID']['parameters']); |
||
229 | $curve->setCoefficients( |
||
230 | new BigInteger($data['curve']['a'], 256), |
||
231 | new BigInteger($data['curve']['b'], 256) |
||
232 | ); |
||
233 | $point = self::extractPoint("\0" . $data['base'], $curve); |
||
234 | $curve->setBasePoint(...$point); |
||
235 | $curve->setOrder($data['order']); |
||
236 | return $curve; |
||
237 | case 'characteristic-two-field': |
||
238 | $curve = new BinaryCurve(); |
||
239 | $params = ASN1::decodeBER($data['fieldID']['parameters']); |
||
240 | $params = ASN1::asn1map($params[0], Maps\Characteristic_two::MAP); |
||
241 | $modulo = [(int) $params['m']->toString()]; |
||
242 | switch ($params['basis']) { |
||
243 | case 'tpBasis': |
||
244 | $modulo[] = (int) $params['parameters']->toString(); |
||
245 | break; |
||
246 | case 'ppBasis': |
||
247 | $temp = ASN1::decodeBER($params['parameters']); |
||
248 | $temp = ASN1::asn1map($temp[0], Maps\Pentanomial::MAP); |
||
249 | $modulo[] = (int) $temp['k3']->toString(); |
||
250 | $modulo[] = (int) $temp['k2']->toString(); |
||
251 | $modulo[] = (int) $temp['k1']->toString(); |
||
252 | } |
||
253 | $modulo[] = 0; |
||
254 | $curve->setModulo(...$modulo); |
||
255 | $len = ceil($modulo[0] / 8); |
||
256 | $curve->setCoefficients( |
||
257 | Hex::encode($data['curve']['a']), |
||
258 | Hex::encode($data['curve']['b']) |
||
259 | ); |
||
260 | $point = self::extractPoint("\0" . $data['base'], $curve); |
||
261 | $curve->setBasePoint(...$point); |
||
262 | $curve->setOrder($data['order']); |
||
263 | return $curve; |
||
264 | default: |
||
265 | throw new UnsupportedCurveException('Field Type of ' . $data['fieldID']['fieldType'] . ' is not supported'); |
||
266 | } |
||
267 | } |
||
268 | throw new \RuntimeException('No valid parameters are present'); |
||
269 | } |
||
270 | |||
271 | /** |
||
272 | * Extract points from a string |
||
273 | * |
||
274 | * Supports both compressed and uncompressed points |
||
275 | * |
||
276 | * @param string $str |
||
277 | * @param \phpseclib3\Crypt\EC\BaseCurves\Base $curve |
||
278 | * @return object[] |
||
279 | */ |
||
280 | public static function extractPoint($str, BaseCurve $curve) |
||
281 | { |
||
282 | if ($curve instanceof TwistedEdwardsCurve) { |
||
283 | // first step of point deciding as discussed at the following URL's: |
||
284 | // https://tools.ietf.org/html/rfc8032#section-5.1.3 |
||
285 | // https://tools.ietf.org/html/rfc8032#section-5.2.3 |
||
286 | $y = $str; |
||
287 | $y = strrev($y); |
||
288 | $sign = (bool) (ord($y[0]) & 0x80); |
||
289 | $y[0] = $y[0] & chr(0x7F); |
||
290 | $y = new BigInteger($y, 256); |
||
291 | if ($y->compare($curve->getModulo()) >= 0) { |
||
292 | throw new \RuntimeException('The Y coordinate should not be >= the modulo'); |
||
293 | } |
||
294 | $point = $curve->recoverX($y, $sign); |
||
295 | if (!$curve->verifyPoint($point)) { |
||
296 | throw new \RuntimeException('Unable to verify that point exists on curve'); |
||
297 | } |
||
298 | return $point; |
||
299 | } |
||
300 | |||
301 | // the first byte of a bit string represents the number of bits in the last byte that are to be ignored but, |
||
302 | // currently, bit strings wanting a non-zero amount of bits trimmed are not supported |
||
303 | if (($val = Strings::shift($str)) != "\0") { |
||
304 | throw new \UnexpectedValueException('extractPoint expects the first byte to be null - not ' . Hex::encode($val)); |
||
305 | } |
||
306 | if ($str == "\0") { |
||
307 | return []; |
||
308 | } |
||
309 | |||
310 | $keylen = strlen($str); |
||
311 | $order = $curve->getLengthInBytes(); |
||
312 | // point compression is being used |
||
313 | if ($keylen == $order + 1) { |
||
314 | return $curve->derivePoint($str); |
||
315 | } |
||
316 | |||
317 | // point compression is not being used |
||
318 | if ($keylen == 2 * $order + 1) { |
||
319 | preg_match("#(.)(.{{$order}})(.{{$order}})#s", $str, $matches); |
||
320 | list(, $w, $x, $y) = $matches; |
||
321 | if ($w != "\4") { |
||
322 | throw new \UnexpectedValueException('The first byte of an uncompressed point should be 04 - not ' . Hex::encode($val)); |
||
323 | } |
||
324 | $point = [ |
||
325 | $curve->convertInteger(new BigInteger($x, 256)), |
||
326 | $curve->convertInteger(new BigInteger($y, 256)) |
||
327 | ]; |
||
328 | |||
329 | if (!$curve->verifyPoint($point)) { |
||
330 | throw new \RuntimeException('Unable to verify that point exists on curve'); |
||
331 | } |
||
332 | |||
333 | return $point; |
||
334 | } |
||
335 | |||
336 | throw new \UnexpectedValueException('The string representation of the points is not of an appropriate length'); |
||
337 | } |
||
338 | |||
339 | /** |
||
340 | * Encode Parameters |
||
341 | * |
||
342 | * @todo Maybe at some point this could be moved to __toString() for each of the curves? |
||
343 | * @param \phpseclib3\Crypt\EC\BaseCurves\Base $curve |
||
344 | * @param bool $returnArray optional |
||
345 | * @param array $options optional |
||
346 | * @return string|false |
||
347 | */ |
||
348 | private static function encodeParameters(BaseCurve $curve, $returnArray = false, array $options = []) |
||
349 | { |
||
350 | $useNamedCurves = isset($options['namedCurve']) ? $options['namedCurve'] : self::$useNamedCurves; |
||
351 | |||
352 | $reflect = new \ReflectionClass($curve); |
||
353 | $name = $reflect->getShortName(); |
||
354 | if ($useNamedCurves) { |
||
355 | if (isset(self::$curveOIDs[$name])) { |
||
356 | if ($reflect->isFinal()) { |
||
357 | $reflect = $reflect->getParentClass(); |
||
358 | $name = $reflect->getShortName(); |
||
359 | } |
||
360 | return $returnArray ? |
||
361 | ['namedCurve' => $name] : |
||
362 | ASN1::encodeDER(['namedCurve' => $name], Maps\ECParameters::MAP); |
||
363 | } |
||
364 | foreach (new \DirectoryIterator(__DIR__ . '/../../Curves/') as $file) { |
||
365 | if ($file->getExtension() != 'php') { |
||
366 | continue; |
||
367 | } |
||
368 | $testName = $file->getBasename('.php'); |
||
369 | $class = 'phpseclib3\Crypt\EC\Curves\\' . $testName; |
||
370 | $reflect = new \ReflectionClass($class); |
||
371 | if ($reflect->isFinal()) { |
||
372 | continue; |
||
373 | } |
||
374 | $candidate = new $class(); |
||
375 | switch ($name) { |
||
376 | case 'Prime': |
||
377 | if (!$candidate instanceof PrimeCurve) { |
||
378 | break; |
||
379 | } |
||
380 | if (!$candidate->getModulo()->equals($curve->getModulo())) { |
||
381 | break; |
||
382 | } |
||
383 | if ($candidate->getA()->toBytes() != $curve->getA()->toBytes()) { |
||
384 | break; |
||
385 | } |
||
386 | if ($candidate->getB()->toBytes() != $curve->getB()->toBytes()) { |
||
387 | break; |
||
388 | } |
||
389 | |||
390 | list($candidateX, $candidateY) = $candidate->getBasePoint(); |
||
391 | list($curveX, $curveY) = $curve->getBasePoint(); |
||
392 | if ($candidateX->toBytes() != $curveX->toBytes()) { |
||
393 | break; |
||
394 | } |
||
395 | if ($candidateY->toBytes() != $curveY->toBytes()) { |
||
396 | break; |
||
397 | } |
||
398 | |||
399 | return $returnArray ? |
||
400 | ['namedCurve' => $testName] : |
||
401 | ASN1::encodeDER(['namedCurve' => $testName], Maps\ECParameters::MAP); |
||
402 | case 'Binary': |
||
403 | if (!$candidate instanceof BinaryCurve) { |
||
404 | break; |
||
405 | } |
||
406 | if ($candidate->getModulo() != $curve->getModulo()) { |
||
407 | break; |
||
408 | } |
||
409 | if ($candidate->getA()->toBytes() != $curve->getA()->toBytes()) { |
||
410 | break; |
||
411 | } |
||
412 | if ($candidate->getB()->toBytes() != $curve->getB()->toBytes()) { |
||
413 | break; |
||
414 | } |
||
415 | |||
416 | list($candidateX, $candidateY) = $candidate->getBasePoint(); |
||
417 | list($curveX, $curveY) = $curve->getBasePoint(); |
||
418 | if ($candidateX->toBytes() != $curveX->toBytes()) { |
||
419 | break; |
||
420 | } |
||
421 | if ($candidateY->toBytes() != $curveY->toBytes()) { |
||
422 | break; |
||
423 | } |
||
424 | |||
425 | return $returnArray ? |
||
426 | ['namedCurve' => $testName] : |
||
427 | ASN1::encodeDER(['namedCurve' => $testName], Maps\ECParameters::MAP); |
||
428 | } |
||
429 | } |
||
430 | } |
||
431 | |||
432 | $order = $curve->getOrder(); |
||
433 | // we could try to calculate the order thusly: |
||
434 | // https://crypto.stackexchange.com/a/27914/4520 |
||
435 | // https://en.wikipedia.org/wiki/Schoof%E2%80%93Elkies%E2%80%93Atkin_algorithm |
||
436 | if (!$order) { |
||
437 | throw new \RuntimeException('Specified Curves need the order to be specified'); |
||
438 | } |
||
439 | $point = $curve->getBasePoint(); |
||
440 | $x = $point[0]->toBytes(); |
||
441 | $y = $point[1]->toBytes(); |
||
442 | |||
443 | if ($curve instanceof PrimeCurve) { |
||
444 | /* |
||
445 | * valid versions are: |
||
446 | * |
||
447 | * ecdpVer1: |
||
448 | * - neither the curve or the base point are generated verifiably randomly. |
||
449 | * ecdpVer2: |
||
450 | * - curve and base point are generated verifiably at random and curve.seed is present |
||
451 | * ecdpVer3: |
||
452 | * - base point is generated verifiably at random but curve is not. curve.seed is present |
||
453 | */ |
||
454 | // other (optional) parameters can be calculated using the methods discused at |
||
455 | // https://crypto.stackexchange.com/q/28947/4520 |
||
456 | $data = [ |
||
457 | 'version' => 'ecdpVer1', |
||
458 | 'fieldID' => [ |
||
459 | 'fieldType' => 'prime-field', |
||
460 | 'parameters' => $curve->getModulo() |
||
461 | ], |
||
462 | 'curve' => [ |
||
463 | 'a' => $curve->getA()->toBytes(), |
||
464 | 'b' => $curve->getB()->toBytes() |
||
465 | ], |
||
466 | 'base' => "\4" . $x . $y, |
||
467 | 'order' => $order |
||
468 | ]; |
||
469 | |||
470 | return $returnArray ? |
||
471 | ['specifiedCurve' => $data] : |
||
472 | ASN1::encodeDER(['specifiedCurve' => $data], Maps\ECParameters::MAP); |
||
473 | } |
||
474 | if ($curve instanceof BinaryCurve) { |
||
475 | $modulo = $curve->getModulo(); |
||
476 | $basis = count($modulo); |
||
477 | $m = array_shift($modulo); |
||
478 | array_pop($modulo); // the last parameter should always be 0 |
||
479 | //rsort($modulo); |
||
480 | switch ($basis) { |
||
481 | case 3: |
||
482 | $basis = 'tpBasis'; |
||
483 | $modulo = new BigInteger($modulo[0]); |
||
484 | break; |
||
485 | case 5: |
||
486 | $basis = 'ppBasis'; |
||
487 | // these should be in strictly ascending order (hence the commented out rsort above) |
||
488 | $modulo = [ |
||
489 | 'k1' => new BigInteger($modulo[2]), |
||
490 | 'k2' => new BigInteger($modulo[1]), |
||
491 | 'k3' => new BigInteger($modulo[0]) |
||
492 | ]; |
||
493 | $modulo = ASN1::encodeDER($modulo, Maps\Pentanomial::MAP); |
||
494 | $modulo = new ASN1\Element($modulo); |
||
495 | } |
||
496 | $params = ASN1::encodeDER([ |
||
497 | 'm' => new BigInteger($m), |
||
498 | 'basis' => $basis, |
||
499 | 'parameters' => $modulo |
||
500 | ], Maps\Characteristic_two::MAP); |
||
501 | $params = new ASN1\Element($params); |
||
502 | $a = ltrim($curve->getA()->toBytes(), "\0"); |
||
503 | if (!strlen($a)) { |
||
504 | $a = "\0"; |
||
505 | } |
||
506 | $b = ltrim($curve->getB()->toBytes(), "\0"); |
||
507 | if (!strlen($b)) { |
||
508 | $b = "\0"; |
||
509 | } |
||
510 | $data = [ |
||
511 | 'version' => 'ecdpVer1', |
||
512 | 'fieldID' => [ |
||
513 | 'fieldType' => 'characteristic-two-field', |
||
514 | 'parameters' => $params |
||
515 | ], |
||
516 | 'curve' => [ |
||
517 | 'a' => $a, |
||
518 | 'b' => $b |
||
519 | ], |
||
520 | 'base' => "\4" . $x . $y, |
||
521 | 'order' => $order |
||
522 | ]; |
||
523 | |||
524 | return $returnArray ? |
||
525 | ['specifiedCurve' => $data] : |
||
526 | ASN1::encodeDER(['specifiedCurve' => $data], Maps\ECParameters::MAP); |
||
527 | } |
||
528 | |||
529 | throw new UnsupportedCurveException('Curve cannot be serialized'); |
||
530 | } |
||
531 | |||
532 | /** |
||
533 | * Use Specified Curve |
||
534 | * |
||
535 | * A specified curve has all the coefficients, the base points, etc, explicitely included. |
||
536 | * A specified curve is a more verbose way of representing a curve |
||
537 | */ |
||
538 | public static function useSpecifiedCurve() |
||
539 | { |
||
540 | self::$useNamedCurves = false; |
||
541 | } |
||
542 | |||
543 | /** |
||
544 | * Use Named Curve |
||
545 | * |
||
546 | * A named curve does not include any parameters. It is up to the EC parameters to |
||
547 | * know what the coefficients, the base points, etc, are from the name of the curve. |
||
548 | * A named curve is a more concise way of representing a curve |
||
549 | */ |
||
550 | public static function useNamedCurve() |
||
551 | { |
||
552 | self::$useNamedCurves = true; |
||
553 | } |
||
554 | } |