Skip to content

Instantly share code, notes, and snippets.

@mglinski
Last active January 3, 2016 13:19
Show Gist options
  • Save mglinski/8468442 to your computer and use it in GitHub Desktop.
Save mglinski/8468442 to your computer and use it in GitHub Desktop.
ECDSA API Encapsulation for https://github.com/mdanter/phpeccRequires GMP Libraries in PHP
<?php
/**
* Class ECDSA
*
* Encapsulate ECDSA Functions from phpecc (https://github.com/mdanter/phpecc) into an easy to use API
*
* @author Matthew Glinski
* @link
* @version 1.0
* @license MIT (http://opensource.org/licenses/MIT)
*
* ---------------------------------------
*
* Copyright (c) 2014 Matthew Glinski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
class ECDSA
{
/**
* generateEccKeys()
*
* Generate a EC Public and Private Key Pair and return the HEX formatted versions
* The CURVE type is hardcoded with prime256v1
* The DIGEST type is hardcoded with SHA256
*
* @return array
*/
public function generateEccKeys()
{
// Load up the curve constants
$generator = NISTcurve::generator_256();
$order = $generator->getOrder();
// Generate a random number as the private key
$secret_multiplier = gmp_Utils::gmp_random( $order );
// THIS NEEDS TO BE FIXED/VALIDATED, I DO NOT TRUST IT'S RANDOMNESS
// build a public key object
$pubkey = new PublicKey( $generator, Point::rmul( $generator, $secret_multiplier ) );
// convert the public key points to hex
$public = gmp_Utils::gmp_dechex($pubkey->getPoint()->getX()).gmp_Utils::gmp_dechex($pubkey->getPoint()->getY());
// convert the private key number to hex
$private = gmp_Utils::gmp_dechex($secret_multiplier);
// return the key pair
return array(
'public' => $public,
'private' => $private,
);
}
/**
* sign()
*
* sign arbitrary data using ECDSA
*
* @param $private_key
* @param $data
*
* @return array
*/
public static function sign($private_key, $data)
{
// Calculate SHA256 digest of the data
$digest = hash('sha256', $data);
// now that we have a digest instead of data, sign it
return self::sign_digest($private_key, $digest);
}
/**
* sign_digest()
*
* sign a valid sha256 digest using ECDSA
*
* @param $private_key
* @param $data
*
* @return string
*/
public static function sign_digest($private_key, $digest)
{
// Load up Curve Constants
$generator = NISTcurve::generator_256();
$order = $generator->getOrder();
// Convert the Private Key back into decimal notation
$secret = gmp_Utils::gmp_hexdec( '0x'.$private_key );
// Load data into key class constructors
$pubkey = new PublicKey($generator, Point::rmul($generator, $secret));
$privkey = new PrivateKey($pubkey, $secret);
// Get a random value for k
$k = gmp_Utils::gmp_random($order);
if(1 <= $k and $k < $order)
{
// Signing a hash value
$signature = $privkey->sign(gmp_Utils::gmp_hexdec( '0x'.$digest ), $k);
// Load the signature parts into BigInteger Classes
$sig_r = gmp_Utils::gmp_dechex( $signature->getR() );
$sig_s = gmp_Utils::gmp_dechex( $signature->getS() );
// Return the signature parts in a hex string
return $sig_r.$sig_s;
}
else
{
throw new Exception('k is not a valid random number');
}
}
/**
* validate()
*
* validate a given signature with the data that was signed
*
* @param $data
* @param $signature
* @param $public_key
*
* @return int
*/
public static function validate($data, $signature, $public_key)
{
// Calculate SHA256 digest of the data
$digest = hash('sha256', $data);
// Load up the curve in use
$generator = NISTcurve::generator_256();
$order = $generator->getOrder();
$curve = $generator->getCurve();
// get the length of the order, used to ensure sanity of hex strings
$order_len = strlen( gmp_Utils::gmp_dechex($order) );
// Generate Public Key Data Structure from HEX String if passed as HEX
if(!is_array($public_key))
{
$public_key = array(
'x' => gmp_Utils::gmp_hexdec( '0x'.substr($public_key, 0, $order_len) ),
'y' => gmp_Utils::gmp_hexdec( '0x'.substr($public_key, $order_len) )
);
}
// Generate Signature Key Data Structure from HEX String if passed as HEX
if(!is_array($signature))
{
$signature = array(
'r' => gmp_Utils::gmp_hexdec( '0x'.substr($signature, 0, $order_len) ),
's' => gmp_Utils::gmp_hexdec( '0x'.substr($signature, $order_len) )
);
}
// check for hex chars in the signature[r] string
if( !is_numeric($signature['r']) and ctype_xdigit($signature['r']) )
{
$signature['r'] = gmp_Utils::gmp_hexdec( '0x'.$signature['r'] );
}
// check for hex chars in the signature[s] string
if( !is_numeric($signature['s']) and ctype_xdigit($signature['s']) )
{
$signature['s'] = gmp_Utils::gmp_hexdec( '0x'.$signature['s'] );
}
// generate the public key object from the given x,y points
$public_key = new PublicKey( $generator, new Point( $curve, $public_key['x'], $public_key['y'], $order ) );
// create a signature object from the given signature data
$signature = new Signature( $signature['r'], $signature['s']);
// Verify the signature for the hashed data
if( $public_key->verifies( gmp_Utils::gmp_hexdec( '0x'.$digest ), $signature ) )
{
return TRUE;
}
else
{
return FALSE;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment