.gitignore000064400000000037150736751610006547 0ustar00vendor/ vendor2/ composer.lock README.md000064400000003472150736751610006044 0ustar00# php sm2 sm3 sm4 国密算法整理 * php版本的国密sm2的签名算法,sm3的hash, sm4的ecb加解密,要求PHP7,打开gmp支持 * 目前如果服务器配套的使用的是openssl 1.1.1x, 目前到1.1.1k ,sm3,sm4都可以直接用openssl_xxx系列函数直接实现,不必大量的代码,但不支持sm2的签名,sm2的加解密 ### SM2 * 该算法主体基于PHPECC算法架构,添加了sm2的椭圆参数算法, * 参考了 https://github.com/ToAnyWhere/phpsm2 童鞋的sm2验签算法,密钥生成算法 * 添加了签名算法, 支持sm2的16进制,base64公私钥的签名,验签算法 * 支持从文件中读取pem文件的签名,验签算法 * sm2的加密解密算法在openssl 1.1.1的版本下自带的函数中暂无sm2的公钥私钥的加密函数,得自己实现,建议使用C,C++的算法,打包成PHP扩展的方式 * 由于 openssl没有实现sm2withsm3算法,用系统函数无法实现签名及证书的自签名分发 ### SM3 * 该算法直接使用 https://github.com/ToAnyWhere/phpsm2 童鞋的sm3, 未做修改 * 也可使用 openssl的函数, 详见openssl_tsm3.php ### SM4 * 该算法直接使用 https://github.com/yinfany/sm 童鞋的sm4算法 * 只实现了ecb算法,没有实现cbc算法 * 在openssl 1.1.1下可使用系统的函数,已支持sm4-cbc,sm4-cfb,sm4-ctr,sm4-ecb,sm4-ofb, 详见openssl_tsm4.php ### 总结 * 这里封装的测试函数已与相关的js, python, java都可以互签互认 * js: https://github.com/JuneAndGreen/sm-crypto * python: https://github.com/duanhongyi/gmssl * java: https://github.com/ZZMarquis/gmhelper * openssl: 升到1.1.1以后,支持sm3,sm4的加解密,还不支持sm2的公私钥加解密,也不支持sm2的签名,得使用原生代码实现,签名中需要实现sm2withsm3, openssl1.1.1只实现了sm2whithsha256 composer.json000064400000001154150736751610007302 0ustar00{ "name": "lpilp/guomi", "description": "国密sm2", "type": "library", "license": "MIT", "authors": [ { "name": "recent", "email": "lpilp@126.com" } ], "minimum-stability": "stable", "require": { "php": ">=7.4", "mdanter/ecc": "0.5.2" }, "autoload": { "psr-4": { "Rtgm\\": "src" }, "files": ["src/overwrite.php"] }, "repositories": { "packagist": { "type": "composer", "url": "https://mirrors.aliyun.com/composer/" } } } composer.lock000064400000014033150736751610007261 0ustar00{ "_readme": [ "This file locks the dependencies of your project to a known state", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], "content-hash": "b42ba7f08f08e21d11eaacf91656c72d", "packages": [ { "name": "fgrosse/phpasn1", "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/fgrosse/PHPASN1.git", "reference": "20299033c35f4300eb656e7e8e88cf52d1d6694e" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/20299033c35f4300eb656e7e8e88cf52d1d6694e", "reference": "20299033c35f4300eb656e7e8e88cf52d1d6694e", "shasum": "", "mirrors": [ { "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", "preferred": true } ] }, "require": { "php": ">=7.0.0" }, "require-dev": { "phpunit/phpunit": "~6.3", "satooshi/php-coveralls": "~2.0" }, "suggest": { "ext-bcmath": "BCmath is the fallback extension for big integer calculations", "ext-curl": "For loading OID information from the web if they have not bee defined statically", "ext-gmp": "GMP is the preferred extension for big integer calculations", "phpseclib/bcmath_compat": "BCmath polyfill for servers where neither GMP nor BCmath is available" }, "type": "library", "extra": { "branch-alias": { "dev-master": "2.0.x-dev" } }, "autoload": { "psr-4": { "FG\\": "lib/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Friedrich Große", "email": "friedrich.grosse@gmail.com", "homepage": "https://github.com/FGrosse", "role": "Author" }, { "name": "All contributors", "homepage": "https://github.com/FGrosse/PHPASN1/contributors" } ], "description": "A PHP Framework that allows you to encode and decode arbitrary ASN.1 structures using the ITU-T X.690 Encoding Rules.", "homepage": "https://github.com/FGrosse/PHPASN1", "keywords": [ "DER", "asn.1", "asn1", "ber", "binary", "decoding", "encoding", "x.509", "x.690", "x509", "x690" ], "time": "2021-04-24T19:01:55+00:00" }, { "name": "mdanter/ecc", "version": "v0.5.2", "source": { "type": "git", "url": "https://github.com/phpecc/phpecc.git", "reference": "b95f25cc1bacc83a9f0ccd375900b7cfd343029e" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpecc/phpecc/zipball/b95f25cc1bacc83a9f0ccd375900b7cfd343029e", "reference": "b95f25cc1bacc83a9f0ccd375900b7cfd343029e", "shasum": "", "mirrors": [ { "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", "preferred": true } ] }, "require": { "ext-gmp": "*", "fgrosse/phpasn1": "^2.0", "php": "^7.0" }, "require-dev": { "phpunit/phpunit": "^6.0", "squizlabs/php_codesniffer": "^2.0", "symfony/yaml": "^2.6|^3.0" }, "type": "library", "autoload": { "psr-4": { "Mdanter\\Ecc\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Matyas Danter", "homepage": "http://matejdanter.com/", "role": "Author" }, { "name": "Thibaud Fabre", "email": "thibaud@aztech.io", "homepage": "http://aztech.io", "role": "Maintainer" }, { "name": "Thomas Kerin", "email": "afk11@users.noreply.github.com", "role": "Maintainer" } ], "description": "PHP Elliptic Curve Cryptography library", "homepage": "https://github.com/phpecc/phpecc", "keywords": [ "Diffie", "ECDSA", "Hellman", "curve", "ecdh", "elliptic", "nistp192", "nistp224", "nistp256", "nistp384", "nistp521", "phpecc", "secp256k1", "secp256r1" ], "time": "2018-12-03T18:17:01+00:00" } ], "packages-dev": [], "aliases": [], "minimum-stability": "stable", "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": [], "platform-dev": [], "plugin-api-version": "1.1.0" } src/ecc/Curves/CurveFactory.php000064400000010103150736751610012467 0ustar00curveSm2(); } $nistFactory = self::getNistFactory($adapter); $secpFactory = self::getSecpFactory($adapter); switch ($name) { case NistCurve::NAME_P192: return $nistFactory->curve192(); case NistCurve::NAME_P224: return $nistFactory->curve224(); case NistCurve::NAME_P256: return $nistFactory->curve256(); case NistCurve::NAME_P384: return $nistFactory->curve384(); case NistCurve::NAME_P521: return $nistFactory->curve521(); case SecgCurve::NAME_SECP_112R1: return $secpFactory->curve112r1(); case SecgCurve::NAME_SECP_192K1: return $secpFactory->curve192k1(); case SecgCurve::NAME_SECP_256K1: return $secpFactory->curve256k1(); case SecgCurve::NAME_SECP_256R1: return $secpFactory->curve256r1(); case SecgCurve::NAME_SECP_384R1: return $secpFactory->curve384r1(); default: $error = new UnsupportedCurveException('Unknown curve.'); $error->setCurveName($name); throw $error; } } /** * @param string $name * @return GeneratorPoint */ public static function getGeneratorByName(string $name): GeneratorPoint { $adapter = MathAdapterFactory::getAdapter(); if($name == Sm2Curve::NAME_PSM2){ return self::getSm2Factory($adapter)->generatorSm2(); } $nistFactory = self::getNistFactory($adapter); $secpFactory = self::getSecpFactory($adapter); switch ($name) { case NistCurve::NAME_P192: return $nistFactory->generator192(); case NistCurve::NAME_P224: return $nistFactory->generator224(); case NistCurve::NAME_P256: return $nistFactory->generator256(); case NistCurve::NAME_P384: return $nistFactory->generator384(); case NistCurve::NAME_P521: return $nistFactory->generator521(); case SecgCurve::NAME_SECP_112R1: return $secpFactory->generator112r1(); case SecgCurve::NAME_SECP_192K1: return $secpFactory->generator192k1(); case SecgCurve::NAME_SECP_256K1: return $secpFactory->generator256k1(); case SecgCurve::NAME_SECP_256R1: return $secpFactory->generator256r1(); case SecgCurve::NAME_SECP_384R1: return $secpFactory->generator384r1(); default: $error = new UnsupportedCurveException('Unknown generator.'); $error->setCurveName($name); throw $error; } } /** * @param GmpMathInterface $math * @return NistCurve */ private static function getNistFactory(GmpMathInterface $math): NistCurve { return new NistCurve($math); } /** * @param GmpMathInterface $math * @return SecgCurve */ private static function getSecpFactory(GmpMathInterface $math): SecgCurve { return new SecgCurve($math); } /** * @param GmpMathInterface $math * @return Sm2 */ private static function getSm2Factory(GmpMathInterface $math): Sm2Curve { return new Sm2Curve($math); } } src/ecc/RtEccFactory.php000064400000002351150736751610011142 0ustar00 self::NIST_P192_OID, NistCurve::NAME_P224 => self::NIST_P224_OID, NistCurve::NAME_P256 => self::NIST_P256_OID, NistCurve::NAME_P384 => self::NIST_P384_OID, NistCurve::NAME_P521 => self::NIST_P521_OID, SecgCurve::NAME_SECP_112R1 => self::SECP_112R1_OID, SecgCurve::NAME_SECP_192K1 => self::SECP_192K1_OID, SecgCurve::NAME_SECP_256K1 => self::SECP_256K1_OID, SecgCurve::NAME_SECP_256R1 => self::SECP_256R1_OID, SecgCurve::NAME_SECP_384R1 => self::SECP_384R1_OID, Sm2Curve::NAME_PSM2 => self::SM2_OID, ); /** * @var array */ private static $sizeMap = array( NistCurve::NAME_P192 => 24, NistCurve::NAME_P224 => 28, NistCurve::NAME_P256 => 32, NistCurve::NAME_P384 => 48, NistCurve::NAME_P521 => 66, SecgCurve::NAME_SECP_112R1 => 14, SecgCurve::NAME_SECP_192K1 => 24, SecgCurve::NAME_SECP_256K1 => 32, SecgCurve::NAME_SECP_256R1 => 32, SecgCurve::NAME_SECP_384R1 => 48, Sm2Curve::NAME_PSM2 =>32, //sm2 也是256位的,32个字节的密码 ); /** * @return array */ public static function getNames(): array { return array_keys(self::$oidMap); } /** * @param CurveFpInterface $curve * @return int */ public static function getByteSize(CurveFpInterface $curve): int { if ($curve instanceof NamedCurveFp && array_key_exists($curve->getName(), self::$sizeMap)) { return self::$sizeMap[$curve->getName()]; } throw new UnsupportedCurveException('Unsupported curve type'); } /** * @param NamedCurveFp $curve * @return ObjectIdentifier */ public static function getCurveOid(NamedCurveFp $curve): ObjectIdentifier { if (array_key_exists($curve->getName(), self::$oidMap)) { $oidString = self::$oidMap[$curve->getName()]; return new ObjectIdentifier($oidString); } throw new UnsupportedCurveException('Unsupported curve type'); } /** * @param ObjectIdentifier $oid * @return NamedCurveFp */ public static function getCurveFromOid(ObjectIdentifier $oid): NamedCurveFp { $oidString = $oid->getContent(); $invertedMap = array_flip(self::$oidMap); if (array_key_exists($oidString, $invertedMap)) { return CurveFactory::getCurveByName($invertedMap[$oidString]); } $error = new UnsupportedCurveException('Invalid data: unsupported curve.'); $error->setOid($oidString); throw $error; } /** * @param ObjectIdentifier $oid * @return GeneratorPoint */ public static function getGeneratorFromOid(ObjectIdentifier $oid): GeneratorPoint { $oidString = $oid->getContent(); $invertedMap = array_flip(self::$oidMap); if (array_key_exists($oidString, $invertedMap)) { return CurveFactory::getGeneratorByName($invertedMap[$oidString]); } $error = new UnsupportedCurveException('Invalid data: unsupported generator.'); $error->setOid($oidString); throw $error; } } src/ecc/Sm2Curve.php000064400000003445150736751610010265 0ustar00adapter = $adapter; // echo "I am sm ecc\n"; } /** * Returns an sm2国密 curve. * * @return NamedCurveFp */ public function curveSm2(): NamedCurveFp { $p = gmp_init('0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', 16); $b = gmp_init('0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93', 16); $a = gmp_init('0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC', 16); $parameters = new CurveParameters(256, $p, $a, $b); return new NamedCurveFp(self::NAME_PSM2, $parameters, $this->adapter); } /** * Returns an sm2 generator. * * @param RandomNumberGeneratorInterface $randomGenerator * @return GeneratorPoint */ public function generatorSm2(RandomNumberGeneratorInterface $randomGenerator = null): GeneratorPoint { $curve = $this->curveSm2(); $order = gmp_init('0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123', 16); $x = gmp_init('0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7', 16); $y = gmp_init('0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0', 16); return $curve->getGenerator($x, $y, $order, $randomGenerator); } } src/ecc/Sm2Signer.php000064400000010312150736751610010417 0ustar00adapter = $adapter; } /** * @param PrivateKeyInterface $key * @param \GMP $truncatedHash - hash truncated for use in ECDSA hash算法然后truncated by 相关的椭圆字节 * @param \GMP $randomK * @return SignatureInterface */ public function sign( PrivateKeyInterface $key, \GMP $truncatedHash, \GMP $randomK ): SignatureInterface { $math = $this->adapter; $generator = $key->getPoint(); // var_dump($generator);die(); $n = $generator->getOrder(); $modMath = $math->getModularArithmetic( $n ); $prikey = $key->getSecret(); //第一二步是userid, msg 生成 trucatedhash , $count = 0; while (true) { $count++; // echo "count: $count\n"; if($count >5){ throw new \RuntimeException( 'Error: sign R or S = 0' ); } // 第三步生成随机数 $k = $math->mod( $randomK, $n ); // 第四步 计算pt1(x1,y1) = [K]G这个点 // 生成一个新的点P = kG $p1 = $generator->mul( $k ); // var_dump($p1);die(); // 第五步 计算 r = (truncatedHash + x1) mod n $r = $modMath->add($truncatedHash,$p1->getX()); // var_dump(gmp_strval($r,16));die(); $zero = gmp_init( 0, 10 ); if ( $math->equals( $r, $zero ) ) { // @todo 如报错,重来 // continue; //报错重来一次 // @todo throw new \RuntimeException( 'Error: random number R = 0' ); } // 第六步 计算 s = ((1 + d)^-1 * (k - rd)) mod n $one = gmp_init(1,10); $s1 = $math->inverseMod($math->add($one, $prikey),$n ); // print_r(gmp_strval($s1,16));die(); $s2 = $math->sub($k,$math->mul($r,$prikey)); // print_r(gmp_strval($s2,16));die(); $s = $modMath->mul($s1,$s2); // var_dump($generator->mul($s));die(); if ( $math->equals( $s, $zero ) ) { // continue; throw new \RuntimeException( 'Error: random number S = 0' ); } return new Signature( $r, $s ); } } /** * @param PublicKeyInterface $key * @param SignatureInterface $signature * @param \GMP $hash * @return bool */ public function verify( PublicKeyInterface $key, SignatureInterface $signature, \GMP $hash ): bool { $generator = $key->getGenerator(); // var_dump($generator);die(); $n = $generator->getOrder(); $r = $signature->getR(); $s = $signature->getS(); $math = $this->adapter; $one = gmp_init( 1, 10 ); if ( $math->cmp( $r, $one ) < 0 || $math->cmp( $r, $math->sub( $n, $one ) ) > 0 ) { return false; } if ( $math->cmp( $s, $one ) < 0 || $math->cmp( $s, $math->sub( $n, $one ) ) > 0 ) { return false; } // 1.2.3.4 sm3 取msg,userid的 hash值,这里直接就传过来了, $modMath = $math->getModularArithmetic( $n ); // 第五步 计算t=(r'+s')mod n $t = $modMath->add($r,$s); // // 第六步 计算(x1,y1) = [s]G + [t]PA $p1 = $generator->mul($s); // p1 = sG 是OK的与签名生成的sG一样 $p2 = $key->getPoint()->mul($t); $xy = $p1->add($p2); // // 第七步 R=(e' + x1') 验证R==r'? $v = $modMath->add($hash, $xy->getX()); return BinaryString::constantTimeCompare( $math->toString( $v ), $math->toString( $r ) ); } } src/overwrite.php000064400000000664150736751610010113 0ustar00 __DIR__ .'/ecc/Serializer/Util/CurveOidMapper.php', 'Mdanter\Ecc\Curves\CurveFactory'=>__DIR__ .'/ecc/Curves/CurveFactory.php', ); if (isset($map[$cls])) { // echo $cls . ' loaded abc '. $map[$cls]. PHP_EOL; include_once $map[$cls]; return true; } }, true, true); src/sm/RtSm2.php000064400000023433150736751610007452 0ustar00adapter = RtEccFactory::getAdapter(); $this->generator = RtEccFactory::getSmCurves()->generatorSm2(); if(in_array($formatSign,$this->arrFormat)){ $this->formatSign = $formatSign; } else { $this->formatSign = 'hex'; } } /** * 随机生成一对16进制明文公私钥 */ public function generatekey() { // $adapter = $this->adapter; $generator = $this->generator; //随机生成一个私钥类 $private = $generator->createPrivateKey(); //取出私钥16进制表示出来 $privateKey = $this->decHex( $private->getSecret() ); //取出公钥的椭圆点 $pubPoint = $private->getPublicKey()->getPoint(); //公钥上的点x, y $pubX = $this->decHex( $pubPoint->getX() ); $pubY = $this->decHex( $pubPoint->getY() ); $publicKey = '04'.$pubX.$pubY; return [$privateKey, $publicKey]; } /** * 随机生成一对PEM编码公私钥 */ public function generatePemkey() { $adapter = $this->adapter; $generator = $this->generator; $private = $generator->createPrivateKey(); $derSerializer = new DerPrivateKeySerializer( $adapter ); // der包 ans1编码 1 版本号 2私钥 3 oid 4 公钥 四组数据 // $der = $derSerializer->serialize( $private ); $pemSerializer = new PemPrivateKeySerializer( $derSerializer ); $privateKeyPem = $pemSerializer->serialize( $private ); $derPubSerializer = new DerPublicKeySerializer( $adapter ); $pemPubSerializer = new PemPublicKeySerializer( $derPubSerializer ); $publicKeyPem = $pemPubSerializer->serialize( $private->getPublicKey() ); return [$privateKeyPem, $publicKeyPem]; } public function doSign( $document, $privateKey, $userId = null ) { if ( empty( $userId ) ) { $userId = $this->userId; } $adapter = $this->adapter; $generator = $this->generator; $algorithm = 'sha256'; $secret = gmp_init( $privateKey, 16 ); $key = new PrivateKey( $adapter, $generator, $secret ); return $this->_dosign( $document, $key, $adapter, $generator, $userId, $algorithm ); } public function doSignOutKey( $document, $privateKeyFile, $userId = null ) { if ( empty( $userId ) ) { $userId = $this->userId; } if ( !file_exists( $privateKeyFile ) ) { throw new \Exception( 'privatekey file not exists' ); } $adapter = $this->adapter; $generator = $this->generator; //这个sha256 只是生成随机数时用到,和主体算法无关 $algorithm = 'sha256'; $pemSerializer = new PemPrivateKeySerializer( new DerPrivateKeySerializer( $adapter ) ); $keyData = file_get_contents( $privateKeyFile ); $key = $pemSerializer->parse( $keyData ); return $this->_dosign( $document, $key, $adapter, $generator, $userId, $algorithm ); } protected function _dosign( $document, $key, $adapter,$generator, $userId, $algorithm = 'sha256' ) { $publickey = $key->getPublicKey(); $obPoint = $key->getPublicKey()->getPoint(); $pubKeyX = $adapter->decHex( $obPoint->getX() ); $pubKeyY = $adapter->decHex( $obPoint->getY() ); $hash = $this->_doS3Hash( $document, $pubKeyX, $pubKeyY, $generator, $userId ); # Derandomized signatures are not necessary, but is avoids # the risk of a low entropy RNG, causing accidental reuse # of a k value for a different message, which leaks the # private key. if ( $this->useDerandomizedSignatures ) { $random = \Mdanter\Ecc\Random\RandomGeneratorFactory::getHmacRandomGenerator( $key, $hash, $algorithm ); } else { $random = \Mdanter\Ecc\Random\RandomGeneratorFactory::getRandomGenerator(); } $randomK = $random->generate( $generator->getOrder() ); $signer = new Sm2Signer( $adapter ); $signature = $signer->sign( $key, $hash, $randomK ); $serializer = new DerSignatureSerializer(); $serializedSig = $serializer->serialize( $signature ); if($this->formatSign == 'hex') { return bin2hex($serializedSig); } else if($this->formatSign == 'base64' ) { return base64_encode( $serializedSig ) . PHP_EOL; } //缺省 hex return bin2hex($serializedSig); } public function verifySign( $document, $sign, $publicKey, $userId = null ) { $adapter = $this->adapter; $generator = $this->generator; if ( empty( $userId ) ) { $userId = $this->userId; } if($this->formatSign == 'hex') { $sigData = hex2bin($sign); } else if($this->formatSign == 'base64' ) { $sigData = base64_decode( $sign ); } else { $sigData = hex2bin($sign); } // Parse signature $sigSerializer = new DerSignatureSerializer(); $sig = $sigSerializer->parse( $sigData ); // get hash list( $pubKeyX, $pubKeyY ) = $this->_getKeyXY( $publicKey ); $hash = $this->_doS3Hash( $document, $pubKeyX, $pubKeyY, $generator, $userId ); // get pubkey parse $key = $this->_getPubKeyObject( $pubKeyX, $pubKeyY ); $signer = new Sm2Signer( $adapter ); return $signer->verify( $key, $sig, $hash ); } public function verifySignOutKey( $document, $sign, $publickeyFile, $userId = null ) { if ( empty( $userId ) ) { $userId = $this->userId; } if ( !file_exists( $publickeyFile ) ) { throw new \Exception( 'publickey file not exists' ); } $adapter = $this->adapter; $generator = $this->generator; if($this->formatSign == 'hex') { $sigData = hex2bin($sign); } else if($this->formatSign == 'base64' ) { $sigData = base64_decode( $sign ); } else { $sigData = hex2bin($sign); } // Parse signature $sigSerializer = new DerSignatureSerializer(); $sig = $sigSerializer->parse( $sigData ); // Parse public key $keyData = file_get_contents( $publickeyFile ); $derSerializer = new DerPublicKeySerializer( $adapter ); $pemSerializer = new PemPublicKeySerializer( $derSerializer ); $key = $pemSerializer->parse( $keyData ); $pubKeyX = $this->decHex( $key->getPoint()->getX() ); $pubKeyY = $this->decHex( $key->getPoint()->getY() ); $hash = $this->_doS3Hash( $document, $pubKeyX, $pubKeyY, $generator, $userId ); $signer = new Sm2Signer( $adapter ); return $signer->verify( $key, $sig, $hash ); } /** * */ protected function _doS3Hash( $document, $pubKeyX, $pubKeyY, $generator, $userId ) { $hasher = new Sm2WithSm3(); $hash = $hasher->getSm3Hash( $document, $pubKeyX, $pubKeyY, $generator, $userId ); return gmp_init( Hex2ByteBuf::ByteArrayToHexString( $hash ), 16 ); } protected function _getKeyXY( $publicKey ) { if ( strlen( $publicKey ) == 128 ) { $pubKeyX = substr( $publicKey, 0, 64 ); $pubKeyY = substr( $publicKey, -64 ); } else if ( strlen( $publicKey ) == 130 && substr( $publicKey, 0, 2 ) == '04' ) { $pubKeyX = substr( $publicKey, 2, 64 ); $pubKeyY = substr( $publicKey, -64 ); } else { throw new \Exception( 'publickey format error' ); } return [$pubKeyX, $pubKeyY]; } protected function _getPubKeyObject( $pubKeyX, $pubKeyY ) { $generator = $this->generator; // __construct( GmpMathInterface $adapter, CurveFpInterface $curve, \GMP $x, \GMP $y, \GMP $order = null, bool $infinity = false ) $x = gmp_init( $pubKeyX, 16 ); $y = gmp_init( $pubKeyY, 16 ); $point = new Point( $this->adapter, $generator->getCurve(), $x, $y ); // __construct( GmpMathInterface $adapter, GeneratorPoint $generator, PointInterface $point ) return new PublicKey( $this->adapter, $this->generator, $point ); } protected function _str2hex($str){ $res = array(); for($i=0; $iBlockUpdate($msgArray, 1, sizeof($msgArray)); $sm3->DoFinal($md, 0); if($format){ return $this->_dec2hex($md); } else { return $md; } } protected function _dec2hex($md){ $res = array(); for($i=0; $ism4 = new Sm4(); } public function encrypt( $key, $data ) { // this is ecb return $this->sm4->encrypt( $key, $data ); } public function decrypt( $key, $data ) { // this is ecb return $this->sm4->decrypt( $key, $data ); } // @todo cbc encrypt and ddecrypt } src/smecc/SM2/Cipher.php000064400000004612150736751610010767 0ustar00sm3keybase = new SM3Digest(); $this->sm3c3 = new SM3Digest(); $p=array(); $gmp_x = $this->p2->GetX(); $x=Hex2ByteBuf::ConvertGmp2ByteArray($gmp_x); $this->sm3keybase->BlockUpdate($x, 0, sizeof($x)); $this->sm3c3->BlockUpdate($x, 0, sizeof($x)); $gmp_y = $this->p2->GetY(); $y=Hex2ByteBuf::ConvertGmp2ByteArray($gmp_y); $this->sm3keybase->BlockUpdate($y, 0, sizeof($y)); $ct = 1; $this->NextKey(); } private function NextKey() { $sm3keycur = new SM3Digest(); $sm3keycur->setSM3Digest($this->sm3keybase); $sm3keycur->Update( ($this->ct >> 24 & 0x00ff)); $sm3keycur->Update( ($this->ct >> 16 & 0x00ff)); $sm3keycur->Update( ($this->ct >> 8 & 0x00ff)); $sm3keycur->Update( ($this->ct & 0x00ff)); $sm3keycur->DoFinal($this->key, 0); $this->keyOff = 0; $this->ct++; } public function Encrypt($data,$len) { $this->sm3c3->BlockUpdate($data, 0, $len); for ($i = 0; $i <$len; $i++) { if ($this->keyOff == sizeof($this->key)) $this->NextKey(); $data[$i] ^= $this->key[$this->keyOff++]; } return $data; } public function Init_dec($userD, $c1) { $this->p2 = $c1->mul($userD); $this->Reset(); } public function Decrypt($data,$len) { for ($i = 0; $i < $len; $i++) { if ($this->keyOff == sizeof($this->key)) $this->NextKey(); $data[$i] ^= $this->key[$this->keyOff++]; } $this->sm3c3->BlockUpdate($data, 0, $len); return $data; } public function Dofinal() { $c3=array(); $gmp_p = $this->p2->GetY(); $p=Hex2ByteBuf::ConvertGmp2ByteArray($gmp_p); $this->sm3c3->BlockUpdate($p, 0, sizeof($p)); $this->sm3c3->DoFinal($c3, 0); //$this->Reset(); return $c3; } } src/smecc/SM2/Hex2ByteBuf.php000064400000003322150736751610011641 0ustar00getPublicKeyFrom($Kx,$Ky,null); $n = 0; $incount = 0; $outcount = 0; $temp_InBuf = array(); $temp_OutBuf = array(); $inlen = strlen($InString) + 1; $outlen = ($inlen / $this::MAX_ENCLEN + 1) * $this::SM2_ADDBYTE + $inlen; $OutBuf = array(); $InBuf = array(); $InBuf=unpack("C*",$InString); $InBuf[$inlen]=0;//这样是为了保挂与其它开发语言一致 $ret = 0; $temp_inlen = 0; while ( $inlen > 0) { if ( $inlen > $this::MAX_ENCLEN) $temp_inlen = $this::MAX_ENCLEN; else $temp_inlen = $inlen; for ( $n = 0; $n < $temp_inlen; $n++) { $temp_InBuf[$n] = $InBuf[$incount + $n + 1];//注意,这里要加1,因为UNPACK后是从1开始 } $temp_OutBuf=$this->sub_EncBufBySoft($temp_InBuf, $temp_inlen, $userKey); for ( $n = 0; $n < ($temp_inlen + $this::SM2_ADDBYTE); $n++) { $OutBuf[ $outcount + $n] = $temp_OutBuf[$n]; } $inlen = $inlen - $this::MAX_ENCLEN; $incount = $incount + $this::MAX_ENCLEN; $outcount = $outcount + $this::MAX_DECLEN; } return Hex2ByteBuf::ByteArrayToHexString( $OutBuf, sizeof($OutBuf)); } private function sub_EncBufBySoft($InBuf, $InBuflen, $userKey) { $n = 0 ; $data = array(); $data = $InBuf; $cipher = new Cipher(); $c1 = $cipher->Init_enc( $userKey); $bc1[0]=4; $gmp_x = $c1->getPoint()->GetX(); $x=Hex2ByteBuf::ConvertGmp2ByteArray($gmp_x); SM3Digest::arraycopy($x,0,$bc1,1,sizeof($x)); $gmp_y = $c1->getPoint()->GetY(); $y=Hex2ByteBuf::ConvertGmp2ByteArray($gmp_y); SM3Digest::arraycopy($y,0,$bc1,1+32,sizeof($y)); $c1_len = sizeof($bc1); $data=$cipher->Encrypt( $data ,$InBuflen); $c3 = array(); $c3=$cipher->Dofinal( ); $OutBuf=array(); for ( $n = 0; $n < $c1_len; $n++) { $OutBuf[$n] = $bc1[ $n]; } for ( $n = 0; $n < $InBuflen; $n++) { $OutBuf[ $n + $c1_len] = $data[ $n]; } for ( $n = 0; $n < 32; $n++) { $OutBuf[ $n + $c1_len + $InBuflen] = $c3[ $n]; } return $OutBuf; } */ } src/smecc/SM2/Sm2WithSm3.php000064400000010664150736751610011441 0ustar00Update( ($len >> 8 & 0x00ff)); $sm3->Update( ($len & 0x00ff)); // userId $sm3->BlockUpdate($id, 1, sizeof($id)); // a,b $gmp_a = $generator->getCurve()->GetA(); $a=Hex2ByteBuf::ConvertGmp2ByteArray($gmp_a); $sm3->BlockUpdate($a, 0, sizeof($a)); $gmp_b = $generator->getCurve()->GetB(); $b=Hex2ByteBuf::ConvertGmp2ByteArray($gmp_b); $sm3->BlockUpdate($b, 0, sizeof($b)); // gx,gy $gmp_gx = $generator->GetX(); $gx=Hex2ByteBuf::ConvertGmp2ByteArray($gmp_gx); $sm3->BlockUpdate($gx, 0, sizeof($gx)); $gmp_gy = $generator->GetY(); $gy=Hex2ByteBuf::ConvertGmp2ByteArray($gmp_gy); $sm3->BlockUpdate($gy, 0, sizeof($gy)); // x,y $bPubKeyX=array(); $bPubKeyX=Hex2ByteBuf::HexStringToByteArray($HexPubKeyX); $sm3->BlockUpdate($bPubKeyX, 0, sizeof($bPubKeyX)); $bPubKeyY=array(); $bPubKeyY=Hex2ByteBuf::HexStringToByteArray($HexPubKeyY); $sm3->BlockUpdate($bPubKeyY, 0, sizeof($bPubKeyY)); $sm3->DoFinal($md, 0); return $md; } private function GetE($z, $HashMsgValue) { $md = array(); $sm3 = new SM3Digest(); $sm3->BlockUpdate($z, 0, sizeof($z)); // byte[] p = Encoding.Default.GetBytes(msg); // sm3.BlockUpdate(p, 0, p.Length); $sm3->BlockUpdate($HashMsgValue, 0, 32); $sm3->DoFinal($md, 0); return $md; } public function GetMsgHash( $msg) { $md = array(); $sm3 = new SM3Digest(); $msgArray=unpack("C*",$msg); $sm3->BlockUpdate($msgArray, 1, sizeof($msgArray)); $sm3->DoFinal($md, 0); return $md; } private function Sm2Verify($md, $PubKeyX, $PubKeyY, $VerfiySign,$generator) { //SM2Result sm2Ret = new SM2Result(); $InSignBuf = array(); $InSignBuf=Hex2ByteBuf::HexStringToByteArray($VerfiySign); $Kx = gmp_init($PubKeyX, 16); $Ky = gmp_init($PubKeyY, 16); $PubKey = $generator->getPublicKeyFrom($Kx,$Ky,null); $r = gmp_init(substr($VerfiySign,0, 64), 16); $s = gmp_init(substr($VerfiySign,64, 64), 16); $ecc_point_g=$generator->getCurve()->getPoint($generator->GetX(), $generator->GetY()); $Sm2Ret=$this->sub_Sm2Verify($md, $PubKey , $r, $s,$ecc_point_g,$generator); if (gmp_cmp($r,$Sm2Ret)==0) { return true; } else return false; } private function sub_Sm2Verify($md, $userKey,$r, $s,$ecc_point_g,$generator) { $generator = $userKey->getGenerator(); $ecc_n = $generator->getOrder(); // e_ $md_gmp=Hex2ByteBuf::ByteArrayToHexString($md,sizeof($md)); $e =gmp_init($md_gmp,16); // t $t=gmp_add($r,$s); $t=gmp_mod($t,$ecc_n); $zero = gmp_init(0, 10); if (gmp_cmp($t,$zero)==0) return null; // x1y1 $x1y1 = $ecc_point_g->mul($s); $x1y1 = $x1y1->add($userKey->getPoint()->mul($t)); // R return gmp_mod(gmp_add($e,$x1y1->GetX()),$ecc_n); } public function YtVerfiyBySoft($id, $msg, $PubKeyX, $PubKeyY, $VerfiySign,$generator) { $Z = array(); $E = array(); $MsgHashValue = array(); $Z = $this->GetZ($id, $PubKeyX, $PubKeyY,$generator); $MsgHashValue = $this->GetMsgHash($msg); $E = $this->GetE($Z, $MsgHashValue); $IsVailSign = $this->Sm2Verify($E, $PubKeyX, $PubKeyY, $VerfiySign,$generator); return $IsVailSign; } public function getSm3Hash($msg,$PubKeyX, $PubKeyY, $generator, $userId="1234567812345678") { // sm3(z+msg) $z = $this->GetZ($userId, $PubKeyX, $PubKeyY,$generator); $md = array(); $sm3 = new SM3Digest(); $sm3->BlockUpdate($z, 0, sizeof($z)); $msgArray=unpack("C*",$msg); $sm3->BlockUpdate($msgArray, 1, sizeof($msgArray)); $sm3->DoFinal($md, 0); return $md; } } src/smecc/SM3/GeneralDigest.php000064400000004347150736751610012300 0ustar00arraycopy($t->xBuf, 0, $this->xBuf, 0, sizeof($t->xBuf)); $this->xBufOff = $t->xBufOff; $this->byteCount = $t->byteCount; } public function __construct( ) { $this->xBuf[0]=0; $this->xBuf[1]=0; $this->xBuf[2]=0; $this->xBuf[3]=0; } public function Update($input) { $this->xBuf[$this->xBufOff++] = $input; if ($this->xBufOff == sizeof($this->xBuf)) { $this->ProcessWord($this->xBuf, 0); $this->xBufOff = 0; } $this->byteCount++; } public function BlockUpdate( $input, $inOff, $length) { // // fill the current word // while (($this->xBufOff != 0) && ($length > 0)) { $this->Update($input[$inOff]); $inOff++; $length--; } // // process whole words. // while ($length > sizeof($this->xBuf)) { $this->ProcessWord($input, $inOff); $inOff += sizeof($this->xBuf); $length -= sizeof($this->xBuf); $this->byteCount += sizeof($this->xBuf); } // // load in the remainder. // while ($length > 0) { $this->Update($input[$inOff]); $inOff++; $length--; } } public function Finish() { // $bitLength = ($this->byteCount << 3); $bitLength = $this->LeftRotateLong($this->byteCount , 3); // // add the pad bytes. // $this->Update(128); while ($this->xBufOff != 0) $this->Update(0); $this->ProcessLength($bitLength); $this->ProcessBlock(); } public function Reset() { $this->byteCount = 0; $this->xBufOff = 0; $this->xBuf[0]=0; $this->xBuf[1]=0; $this->xBuf[2]=0; $this->xBuf[3]=0; } public function GetByteLength():int { return $this::BYTE_LENGTH; } } src/smecc/SM3/SM3Digest.php000064400000021650150736751610011321 0ustar00Reset(); } public function setSM3Digest($t) { parent::setGeneralDigest($t); $this->arraycopy($t->X, 0, $this->X, 0, sizeof($t->X)); $this->xOff = $t->xOff; $this->arraycopy($t->v, 0, $this->v, 0, sizeof($t->v)); } public function Reset() { parent::Reset(); $this->arraycopy(SM3Digest::$v0, 0, $this->v, 0, sizeof(SM3Digest::$v0)); $this->xOff = 0; $this->arraycopy(SM3Digest::$X0, 0, $this->X, 0, sizeof(SM3Digest::$X0)); } public static function arraycopy($InBuf,$InBufPos,&$OutBuf,$OutBufPos,$Len) { for( $n = 0 ;$n< $Len;$n++) { $OutBuf[$n + $OutBufPos] =$InBuf[$n+$InBufPos]; } } public function ProcessBlock() { $ww = $this->X; $ww_ = array(); for ($i = 16; $i < 68; $i++) { $ww[$i] = $this->P1( $ww[ $i - 16] ^ $ww[$i - 9] ^ ($this->ROTATE($ww[$i - 3], 15))) ^ ($this->ROTATE($ww[$i - 13], 7)) ^ $ww[$i - 6]; } for ($i = 0; $i < 64; $i++) { $ww_[$i] = $ww[$i] ^ $ww[$i + 4]; } $vv = $this->v; $vv_ = $this->v_; $this->arraycopy($vv, 0, $vv_, 0, sizeof($vv)); // int SS1, SS2, TT1, TT2, aaa; for ($i = 0; $i < 16; $i++) { $aaa = $this->ROTATE($vv_[0], 12); $SS1 = $this->MyAdd($aaa , $vv_[4]); $SS1 = $this->MyAdd($SS1, $this->ROTATE($this->T_00_15, $i)); $SS1 = $this->ROTATE($SS1, 7); $SS2 = $SS1 ^ $aaa; $TT1=$this->FF_00_15($vv_[0], $vv_[1], $vv_[2]); $TT1=$this->MyAdd($TT1, $vv_[3]); $TT1=$this->MyAdd($TT1, $SS2); $TT1=$this->MyAdd($TT1, $ww_[$i]); $TT2=$this->GG_00_15($vv_[4], $vv_[5], $vv_[6]); $TT2=$this->MyAdd($TT2, $vv_[7]); $TT2=$this->MyAdd($TT2, $SS1); $TT2=$this->MyAdd($TT2, $ww[$i]); $vv_[3] = $vv_[2]; $vv_[2] = $this->ROTATE($vv_[1], 9); $vv_[1] = $vv_[0]; $vv_[0] = $TT1; $vv_[7] = $vv_[6]; $vv_[6] = $this->ROTATE($vv_[5], 19); $vv_[5] = $vv_[4]; $vv_[4] = $this->P0($TT2); } for ($i = 16; $i < 64; $i++) { $aaa = $this->ROTATE($vv_[0], 12); $SS1 = $this->MyAdd($aaa , $vv_[4]); $z= $this->ROTATE($this->T_16_63, $i); $SS1 = $this->MyAdd( $SS1, $this->ROTATE($this->T_16_63, $i)); $SS1 = $this->ROTATE($SS1, 7); $SS2 = $SS1 ^ $aaa; $TT1 = $this->MyAdd($this->FF_16_63($vv_[0], $vv_[1], $vv_[2]) , $vv_[3]); $TT1 = $this->MyAdd( $TT1, $SS2); $TT1 = $this->MyAdd( $TT1, $ww_[$i]); $TT2 = $this->MyAdd($this->GG_16_63($vv_[4], $vv_[5], $vv_[6]) , $vv_[7]); $TT2 = $this->MyAdd( $TT2, $SS1); $TT2 = $this->MyAdd($TT2 , $ww[$i]); $vv_[3] = $vv_[2]; $vv_[2] = $this->ROTATE($vv_[1], 9); $vv_[1] = $vv_[0]; $vv_[0] = $TT1; $vv_[7] = $vv_[6]; $vv_[6] = $this->ROTATE($vv_[5], 19); $vv_[5] = $vv_[4]; $vv_[4] = $this->P0($TT2); } for ($i = 0; $i < 8; $i++) { $vv[$i] ^= $vv_[$i]; } $this->v=$vv; $this->v_=$vv_; // Reset $this->xOff = 0; $this->arraycopy(SM3Digest::$X0, 0, $this->X, 0, sizeof(SM3Digest::$X0)); } public function ProcessWord($in_Renamed, $inOff) { $n = $this->LeftRotateLong($in_Renamed[$inOff] , 24); $n |= $this->LeftRotateLong(($in_Renamed[++$inOff] & 0xff) , 16); $n |= $this->LeftRotateLong(($in_Renamed[++$inOff] & 0xff) , 8); $n |= ($in_Renamed[++$inOff] & 0xff); $this->X[$this->xOff] = $n; if (++$this->xOff == 16) { $this->ProcessBlock(); } } public function ProcessLength($bitLength) { if ($this->xOff > 14) { $this->ProcessBlock(); } $this->X[14] = ($this->RightRotateLong($bitLength, 32)); $this->X[15] = ($bitLength & 0xffffffff); } public function IntToBigEndian($n, &$bs, $off) { $bs[$off] = ($this->RightRotateLong($n, 24)) & 0xff; $bs[++$off] = ($this->RightRotateLong($n, 16)) & 0xff; $bs[++$off] = ($this->RightRotateLong($n, 8)) & 0xff; $bs[++$off] = ($n) & 0xff ; } public function DoFinal(&$out_Renamed, $outOff):int { $this->Finish(); for ($i = 0; $i < 8; $i++) { $this->IntToBigEndian($this->v[$i], $out_Renamed, $outOff + $i * 4); } $this->Reset(); return $this::DIGEST_LENGTH; } private function HandleSign($lValue) { $lValue = $lValue & 0xFFFFFFFF; if($lValue>=0x80000000) { $lValue=$lValue-(0xffffffff+1); } return $lValue; } private function MyAdd($A,$B) { $lValue=$this->HandleSign($A) + $this->HandleSign($B); return $this->HandleSign($lValue); } public function LeftRotateLong($lValue, $lBits ) { $lBits = $lBits % 32; $lValue=$lValue<< $lBits; $lValue=$lValue & 0xffffffff; if($lValue>=0x80000000) { $lValue=$lValue-(0xffffffff+1); } return $lValue; /* $lngSign=0; $intI=0; $mValue=0; $lBits = $lBits % 32; $mValue = $lValue; if($lBits == 0) return $mValue; For ($intI = 1 ;$intI<= $lBits;$intI++) { $lngSign = $mValue & 0x40000000; $mValue = ($mValue & 0x3FFFFFFF) * 2; if($lngSign & 0x40000000) $mValue = $mValue | 0x80000000; } return $mValue;*/ } private function RightRotateLong($lValue , $lBits) { $lngSign=0;$intI=0; $mValue =0; $mValue = $lValue; // $lBits = $lBits % 32; if( $lBits == 0 ) { return $mValue ; } if ($lValue >= 0) { if($lBits<0) $lBits= 32+ $lBits; $r = $lValue >> $lBits; } else { $t=~$lBits; if($t<0) $t= 32+ $t; // $t = $t % 32; $r= ($lValue >> $lBits) + (2 << $t); } return $r; /* For ($intI = 1 ;$intI<= $lBits;$intI++) { $lngSign = $mValue & 0x80000000; $mValue = ($mValue & 0x7FFFFFFF) / 2; if ($lngSign) $mValue = $mValue | 0x40000000; } return $mValue;*/ } private function FFj($X, $Y, $Z, $j) :int { if($j>=0 && $j<=15) { return $this->FF_00_15($X, $Y, $Z); } else { return $this->FF_16_63($X, $Y, $Z); } } private function GGj($X, $Y, $Z, $j) :int { if($j>=0 && $j<=15) { return $this->GG_00_15($X, $Y, $Z); } else { return $this->GG_16_63($X, $Y, $Z); } } private function ROTATE($X, $n):int { // $r=($this->RightRotateLong($X, (32 - $n))); //$r1=$this->LeftRotateLong($X , $n); // $r2=($X << $n); return $this->LeftRotateLong($X , $n) | ($this->RightRotateLong($X, (32 - $n))); } private function P0($X):int { $a=$this->ROTATE(($X), 9); $b= $this->ROTATE(($X), 17); return (($X) ^ $this->ROTATE(($X), 9) ^ $this->ROTATE(($X), 17)); } private function P1($X):int { return (($X) ^ $this->ROTATE(($X), 15) ^ $this->ROTATE(($X), 23)); } private static function FF_00_15($X, $Y, $Z):int { return ($X ^ $Y ^ $Z); } private static function FF_16_63($X, $Y, $Z):int { return (($X & $Y) | ($X & $Z) | ($Y & $Z)); } private static function GG_00_15($X, $Y, $Z):int { return ($X ^ $Y ^ $Z); } private static function GG_16_63($X, $Y, $Z):int { return (($X & $Y) | (~ $X & $Z)); } }src/smecc/SM4/README.md000064400000000043150736751610010317 0ustar00# sm 国密sm3,sm4 ECB加密源码 src/smecc/SM4/SM3.php000064400000011731150736751610010161 0ustar00message = $message; /** @var string hash_value 杂凑值 */ $this->hash_value = $this->sm3(); } /** * 主方法 * * @return string * @throws \ErrorException */ private function sm3() { /** @var string $m 转化后的消息(二进制码) */ // $json = json_encode($this->message); $m = new BitString($this->message, false); //var_dump($m);die(); //11010010 10111011 // 一、填充 $l = strlen($m); // 满足l + 1 + k ≡ 448mod512 的最小的非负整数 $k = $l % 512; $k = $k + 64 >= 512 ? 512 - ($k % 448) - 1 : 512 - 64 - $k - 1; $bin_l = new BitString($l); // 填充后的消息 $m_fill = new BitString( $m # 原始消息m . '1' # 拼个1 . str_pad('', $k, '0') # 拼上k个比特的0 . ( strlen($bin_l) >= 64 ? substr($bin_l, 0, 64) : str_pad($bin_l, 64, '0', STR_PAD_LEFT) ) # 64比特,l的二进制表示 ); // 二、迭代压缩 // 迭代过程 $B = str_split($m_fill, 512); /** @var int $n m'可分为的组数 */ $n = ($l + $k + 65) / 512; if (count($B) !== $n) { throw new ErrorException(); } $V = array( WordConversion::hex2bin(self::IV), ); $extended = new ExtendedCompression(); foreach ($B as $key => $Bi) { // print_r($Bi."\n"."====== $key ========\n".strlen($Bi)."\n"); $V[$key + 1] = $extended->CF($V[$key], $Bi)->getBitString(); } krsort($V); reset($V); $binary = current($V); $rt = WordConversion::bin2hex($binary); return $rt; } /** * 方便直接输出实例化的对象 * * @return string */ public function __toString() { return $this->hash_value; } /** * Whether a offset exists * * @link https://php.net/manual/en/arrayaccess.offsetexists.php * * @param mixed $offset

* An offset to check for. *

* * @return bool true on success or false on failure. *

*

* The return value will be casted to boolean if non-boolean was returned. * @since 5.0.0 */ public function offsetExists($offset) { return isset($this->hash_value[$offset]); } /** * Offset to retrieve * * @link https://php.net/manual/en/arrayaccess.offsetget.php * * @param mixed $offset

* The offset to retrieve. *

* * @return mixed Can return all value types. * @since 5.0.0 */ public function offsetGet($offset) { return $this->hash_value[$offset]; } /** * Offset to set * * @link https://php.net/manual/en/arrayaccess.offsetset.php * * @param mixed $offset

* The offset to assign the value to. *

* @param mixed $value

* The value to set. *

* * @return \SM3\SM3 * @since 5.0.0 */ public function offsetSet($offset, $value) { $this->hash_value[$offset] = $value; return $this; } /** * Offset to unset * * @link https://php.net/manual/en/arrayaccess.offsetunset.php * * @param mixed $offset

* The offset to unset. *

* * @return void * @since 5.0.0 */ public function offsetUnset($offset) { unset($this->hash_value[$offset]); } } src/smecc/SM4/Sm4.php000064400000020052150736751610010216 0ustar00_rk = array(); $this->sM4KeySchedule($key); $bytes = $this->pad($data); $chunks = array_chunk($bytes, $this->_block_size); $ciphertext = ""; foreach ($chunks as $chunk) { $ciphertext .= $this->sM4Encrypt($chunk); } return bin2hex($ciphertext); return base64_encode($ciphertext); } public function decrypt($key, $data) { $this->_rk = array(); // $data = base64_decode($data); $data = hex2bin($data); if (strlen($data) < 0 || strlen($data) % $this->_block_size != 0) { return false; } $this->sM4KeySchedule($key); $bytes = unpack("C*", $data); $chunks = array_chunk($bytes, $this->_block_size); $plaintext = ""; foreach ($chunks as $chunk) { $plaintext .= substr($this->sM4Decrypt($chunk), 0, 16); } $plaintext = $this->un_pad($plaintext); return $plaintext; } private function sM4Decrypt($cipherText) { $x = array(); for ($j = 0; $j < 4; $j++) { $x[$j] = ($cipherText[$j * 4] << 24) | ($cipherText[$j * 4 + 1] << 16) | ($cipherText[$j * 4 + 2] << 8) | ($cipherText[$j * 4 + 3]); } for ($i = 0; $i < 32; $i++) { $tmp = $x[$i + 1] ^ $x[$i + 2] ^ $x[$i + 3] ^ $this->_rk[31 - $i]; $buf = (self::$SM4_SBOX[($tmp >> 24) & 0xFF]) << 24 | (self::$SM4_SBOX[($tmp >> 16) & 0xFF]) << 16 | (self::$SM4_SBOX[($tmp >> 8) & 0xFF]) << 8 | (self::$SM4_SBOX[$tmp & 0xFF]); $x[$i + 4] = $x[$i] ^ ($buf ^ $this->sm4Rotl32(($buf), 2) ^ $this->sm4Rotl32(($buf), 10) ^ $this->sm4Rotl32(($buf), 18) ^ $this->sm4Rotl32(($buf), 24)); } $plainText = array(); for ($k = 0; $k < 4; $k++) { $plainText[4 * $k] = ($x[35 - $k] >> 24) & 0xFF; $plainText[4 * $k + 1] = ($x[35 - $k] >> 16) & 0xFF; $plainText[4 * $k + 2] = ($x[35 - $k] >> 8) & 0xFF; $plainText[4 * $k + 3] = ($x[35 - $k]) & 0xFF; } return $this->bytesToString($plainText); } private function sM4Encrypt($plainText) { $x = array(); for ($j = 0; $j < 4; $j++) { $x[$j] = ($plainText[$j * 4] << 24) | ($plainText[$j * 4 + 1] << 16) | ($plainText[$j * 4 + 2] << 8) | ($plainText[$j * 4 + 3]); } for ($i = 0; $i < 32; $i++) { $tmp = $x[$i + 1] ^ $x[$i + 2] ^ $x[$i + 3] ^ $this->_rk[$i]; $buf = (self::$SM4_SBOX[($tmp >> 24) & 0xFF]) << 24 | (self::$SM4_SBOX[($tmp >> 16) & 0xFF]) << 16 | (self::$SM4_SBOX[($tmp >> 8) & 0xFF]) << 8 | (self::$SM4_SBOX[$tmp & 0xFF]); $x[$i + 4] = $x[$i] ^ ($buf ^ $this->sm4Rotl32(($buf), 2) ^ $this->sm4Rotl32(($buf), 10) ^ $this->sm4Rotl32(($buf), 18) ^ $this->sm4Rotl32(($buf), 24)); } $cipherText = array(); for ($k = 0; $k < 4; $k++) { $cipherText[4 * $k] = ($x[35 - $k] >> 24) & 0xFF; $cipherText[4 * $k + 1] = ($x[35 - $k] >> 16) & 0xFF; $cipherText[4 * $k + 2] = ($x[35 - $k] >> 8) & 0xFF; $cipherText[4 * $k + 3] = ($x[35 - $k]) & 0xFF; } return $this->bytesToString($cipherText); } private function stringToBytes($string) { return unpack('C*', $string); } private function bytesToString($bytes) { return vsprintf(str_repeat('%c', count($bytes)), $bytes); } private function pad($data) { $bytes = $this->stringToBytes($data); $rem = $this->_block_size - count($bytes) % $this->_block_size; for ($i = 0; $i < $rem; $i++) { array_push($bytes, $rem); } return $bytes; } private function un_pad($data) { $bytes = $this->stringToBytes($data); $rem = $bytes[count($bytes)]; $bytes = array_slice($bytes, 0, count($bytes) - $rem); return $this->bytesToString($bytes); } private function sm4Rotl32($buf, $n) { return (($buf << $n) & 0xffffffff) | ($buf >> (32 - $n)); } private function sM4KeySchedule($key) { $this->_rk = array(); $key = array_values(unpack("C*", $key)); $k = array(); // for ($i = 0; $i < 4; $i++) { // $k[$i] = self::$SM4_FK[$i] // ^ ((($key[4 * $i] ?? 0) << 24) // | (($key[4 * $i + 1] ?? 0) << 16) // | (($key[4 * $i + 2] ?? 0) << 8) // | ($key[4 * $i + 3] ?? null)); // } for ($i = 0; $i < 4; $i++) { $k[$i] = self::$SM4_FK[$i] ^ (((isset($key[4 * $i]) ? $key[4 * $i] : 0) << 24) | ((isset($key[4 * $i + 1]) ? $key[4 * $i + 1] : 0) << 16) | ((isset($key[4 * $i + 2]) ? $key[4 * $i + 2] : 0) << 8) | (isset($key[4 * $i + 3]) ? $key[4 * $i + 3] : null)); } for ($j = 0; $j < 32; $j++) { $tmp = $k[$j + 1] ^ $k[$j + 2] ^ $k[$j + 3] ^ self::$SM4_CK[$j]; $buf = (self::$SM4_SBOX[($tmp >> 24) & 0xFF]) << 24 | (self::$SM4_SBOX[($tmp >> 16) & 0xFF]) << 16 | (self::$SM4_SBOX[($tmp >> 8) & 0xFF]) << 8 | (self::$SM4_SBOX[$tmp & 0xFF]); $k[$j + 4] = $k[$j] ^ (($buf) ^ ($this->sm4Rotl32(($buf), 13)) ^ ($this->sm4Rotl32(($buf), 23))); $this->_rk[$j] = $k[$j + 4]; } } } src/smecc/SM4/handler/BigJHandler.php000064400000003227150736751610013306 0ustar00extended($Bi); /** @var array $registers 八个寄存器的名字 */ $registers = array( 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' ); // 将 Vi 的值依次放入八个寄存器中 // 下列注释用于防止IDE报错 /** @var Word $A */ /** @var Word $B */ /** @var Word $C */ /** @var Word $D */ /** @var Word $E */ /** @var Word $F */ /** @var Word $G */ /** @var Word $H */ foreach ($registers as $i => $register) { $$register = new Word(substr($Vi, $i * 32, 32)); } $small_j_handler = new SmallJHandler(); $big_j_handler = new BigJHandler(); for ($j = 0; $j < 64; $j++) { $j_handler = ($j >= SmallJHandler::SMALLEST_J && $j < BigJHandler::SMALLEST_J) ? $small_j_handler : $big_j_handler; $SS1 = WordConversion::shiftLeftConversion( WordConversion::addConversion( array( WordConversion::shiftLeftConversion($A, 12), $E, WordConversion::shiftLeftConversion($j_handler->getT(), $j) ) ), 7 ); $SS2 = WordConversion::xorConversion( array( $SS1, WordConversion::shiftLeftConversion($A, 12) ) ); $TT1 = WordConversion::addConversion( array( $j_handler->FF($A, $B, $C), $D, $SS2, $this->W_s[$j] ) ); $TT2 = WordConversion::addConversion( array( $j_handler->GG($E, $F, $G), $H, $SS1, $this->W[$j] ) ); $D = $C; $C = WordConversion::shiftLeftConversion($B, 9); $B = $A; $A = $TT1; $H = $G; $G = WordConversion::shiftLeftConversion($F, 19); $F = $E; $TT2_object = new Substitution($TT2); $E = $TT2_object->P0(); } return WordConversion::xorConversion( array( join( '', array( (new Word($A)), (new Word($B)), (new Word($C)), (new Word($D)), (new Word($E)), (new Word($F)), (new Word($G)), (new Word($H)) ) ), $Vi ) ); } /** * 消息扩展 * * 将消息分组B(i)按以下方法扩展生成132个字W0, W1, · · · , W67, W′0, W′1, · · · , W′63, * 用于压缩函数CF * * @param $Bi 消息分组中的第i个,最大512位 (\SM3\types\BitString) * * @return void * @throws \ErrorException */ public function extended($Bi) { // 将消息分组B(i)划分为16个字W0, W1, · · · , W15。 $this->W = $this->W_s = array(); $word_per_times = (int)ceil(strlen($Bi) / 16); for ($i = 0; $i < 16; $i++) { $this->W[$i] = new Word( substr($Bi, $i * $word_per_times, $word_per_times) ); } // 计算W for ($j = 16; $j <= 67; $j++) { $param_1 = (new Substitution( WordConversion::xorConversion( array( $this->W[$j - 16], $this->W[$j - 9], WordConversion::shiftLeftConversion($this->W[$j - 3], 15) ) ) )); $this->W[$j] = WordConversion::xorConversion( array( $param_1->P1(), WordConversion::shiftLeftConversion($this->W[$j - 13], 7), $this->W[$j - 6] ) ); } unset($j); // 计算W' for ($j = 0; $j <= 63; $j++) { $this->W_s[$j] = WordConversion::xorConversion( array( $this->W[$j], $this->W[$j + 4] ) ); } } } src/smecc/SM4/handler/JHandler.php000064400000003357150736751610012670 0ustar00setT($T); $this->setSectionJ($smallest, $biggest); } /** * 配置 继承本抽象类的子类可以处理的j的大小 * * @param $smallest int j的最小长度 * @param $biggest int j的最大长度 */ public function setSectionJ($smallest, $biggest) { $this->section_j = array($smallest, $biggest); } /** * 布尔函数 * * @param $X string 长度32的比特串 * @param $Y string * @param $Z string * * @return mixed */ abstract public function FF($X, $Y, $Z); /** * 布尔函数 * * @param $X * @param $Y * @param $Z * * @return mixed */ abstract public function GG($X, $Y, $Z); /** * 读取常量T * @return Word * @throws \ErrorException */ public function getT() { return new Word($this->T); } /** * 配置常量T * * @param string $T */ public function setT($T) { $this->T = WordConversion::hex2bin($T); } } src/smecc/SM4/handler/README.md000064400000000546150736751610011744 0ustar00# *handle/* 目录 本目录包含了加密过程中的核心算法 * `\SM3\handler\JHandler` 根据J的不同,进行不同处理的抽象类 * `\SM3\handler\SmalJHandler` 变量j处于较小值时的处理类 * `\SM3\handler\BigJHandler` 变量j处于较大值时的处理类 * `\SM3\handler\Substitution` 置换函数类src/smecc/SM4/handler/SmallJHandler.php000064400000003307150736751610013654 0ustar00X = $X; } /** * 压缩函数中的置换函数 * * @return \SM3\types\Word 置换结果 */ public function P0() { return $this->substitutionFunction(0); } /** * 置换函数的公共函数 * @param $type * @return Word * @throws \ErrorException */ private function substitutionFunction($type) { if (!in_array($type, array(0, '0', 1, '1'))) { return new Word(''); } $times_name = $type == 1 ? $this->P1_shiftLeft_times : $this->P0_shiftLeft_times; $X_shiftLeft_1 = WordConversion::shiftLeftConversion($this->X, $times_name[0]); $X_shiftLeft_2 = WordConversion::shiftLeftConversion($this->X, $times_name[1]); return WordConversion::xorConversion( array( $this->X, $X_shiftLeft_1, $X_shiftLeft_2 ) ); } /** * 消息扩展中的置换函数 * @return Word * @throws \ErrorException */ public function P1() { return $this->substitutionFunction(1); } } src/smecc/SM4/libs/README.md000064400000000411150736751610011247 0ustar00# *libs/* 目录 本目录包含了 *动态读写配置* 和 *一些底层的基础操作(如:按位运算)* * `\SM3\libs\Config` 配置类,获取和动态设定配置 * `\SM3\libs\WordConversion` 字的位运算类,包含了位的各种运算 src/smecc/SM4/libs/WordConversion.php000064400000015642150736751610013476 0ustar00= strlen($prevent)) { $longest = strlen($current); $longest_value = $current; $shortest = strlen($prevent); } else { $longest = strlen($prevent); $longest_value = $prevent; $shortest = strlen($current); } if ($prevent === '0' || $current === '0') { switch ($type) { // and case 1: return 0; // or case 2: // xor case 3: // add case 5: return $prevent == '0' ? $current : $prevent; default: break; } } $value = array(); /** * 加运算时需要,用来储存需要进几 * * @var int 向前一位进的数字 */ $carry = 0; /** * 大端 * * 这里从大端跑完之后,结果数组的序号是从大到小排列的 * 还需要根据键名排序一次 * * 个人感觉区分不区分大端并没有什么意义 * 如果换成字符串拼接的话更好用 * 但是方便你理解,还是按照大端+数组的方式进行的排列 */ for ($i = $longest - 1; $i >= 0; $i--) { $prevent_number = $prevent[$i]; switch ($type) { // 与 case 1: $value[$i] = ($i >= $shortest) ? $longest_value[$i] : ($prevent_number & $current[$i]); break; // 或 case 2: $value[$i] = ($i >= $shortest) ? ~$longest_value[$i] : ($prevent_number | $current[$i]); break; // 异或 case 3: $value[$i] = $i > $shortest ? 1 : (intval($prevent_number) ^ intval($current[$i])); break; // 非(按位取反) case 4: $value[$i] = $prevent_number === '1' ? '0' : '1'; break; // 加 case 5: $add = $prevent_number + $current[$i] + $carry; $value[$i] = $add % 2; $carry = ($add - $value[$i]) / 2; break; // 特殊情况 default: break; } } ksort($value); return new Word(join('', $value)); } /** * @param $params array 需要进行异或运算的字列表 * @param $type int 位运算类型 * @return Word|null 运算结果 */ private static function conversion($params, $type) { $prevent = null; foreach ($params as $param){ $prevent = self::conversion_func($prevent,$param,$type); } return $prevent; } /** * 字的与运算 * * @param $params array 需要进行与运算的字列表 * * @return Word */ public static function andConversion($params) { return self::conversion($params, 1); } /** * 字的或运算 * * @param $params * * @return Word */ public static function orConversion($params) { return self::conversion($params, 2); } /** * 字的非运算 * * @param $word * * @return Word */ public static function notConversion($word) { return self::conversion(array($word, null), 4); } /** * @param $word Word 待运算的字 * @param $times int 左移的位数 * @return Word * @throws \ErrorException */ public static function shiftLeftConversion($word, $times) { return new Word( substr( $word, ($times % strlen($word)) ) . substr( $word, 0, ($times % strlen($word)) ) ); } /** * 将16进制数串转换为二进制数据 * 使用字符串形式实现,解决了PHP本身进制转换的时候受限于浮点数大小的问题 * * @param int|string $hex * * @return string */ public static function hex2bin($hex) { // 格式化为字符串 $hex = strval($hex); /** 十六进制转二进制,每1位一组 */ defined('HEX_TO_BIN_NUM') || define('HEX_TO_BIN_NUM', 1); /** @var array $hex_array 把指定的十六进制数按位切片为数组 */ $hex_array = str_split($hex, HEX_TO_BIN_NUM); // 最终的二进制数字(为确保长度不丢失,使用字符串类型) $binary = ''; foreach ($hex_array as $number) { $bin_number = strval(base_convert($number, 16, 2)); if (strlen($bin_number) < 4) { $bin_number = str_pad($bin_number, 4, '0', STR_PAD_LEFT); } $binary .= $bin_number; } return $binary; } /** * 二进制转十六进制 * @param $bin * * @return string */ public static function bin2hex($bin) { // 格式化为字符串 $bin = strval($bin); /** 二进制转十六进制,每4位一组 */ defined('BIN_TO_HEX_NUM') || define('BIN_TO_HEX_NUM', 4); /** @var array $bin_array 把指定的二进制数按位切片为数组 */ $bin_array = str_split($bin, BIN_TO_HEX_NUM); // 最终的二进制数字(为确保长度不丢失,使用字符串类型) $hex = ''; foreach ($bin_array as $number) { $hex .= strval(base_convert($number, 2, 16)); } return $hex; } /** * 二进制加运算 * * @param array $params * * @return Word */ public static function addConversion($params) { return self::conversion($params, 5); } } src/smecc/SM4/types/BitString.php000064400000011732150736751610012631 0ustar00getString(); } if ($is_bit_string === false) { // 指定不是比特串的,直接转换 $this->bit_string = "{$this->str2bin($string)}"; } else { // 默认走个验证试试 $this->bit_string = $this->is_bit_string($string) ? $string : "{$this->str2bin($string)}"; } } /** * 字符串转比特串 * * @param $str int|string 普通字符串 * * @return string 转换为比特串 * @throws \ErrorException */ private function str2bin($str) { if (!is_string($str) && !is_int($str)) { throw new ErrorException('输入的类型错误'); } if (is_int($str)) { return decbin($str); } $fileType = mb_detect_encoding($str , array('UTF-8','GBK','LATIN1','BIG5')) ; if( $fileType != 'UTF-8'){ $str = mb_convert_encoding($str ,'utf-8' , $fileType); } $arr = preg_split('/(?getString(); } // 检查是否为字符串 if (!is_string($string)) { return false; } // 检查是否为只有0和1组成的字符串 $array = array_filter(str_split($string)); foreach ($array as $value) { if (!in_array( $value, array( 0, '0', 1, '1' ), true )) { return false; } } return true; } public function __toString() { return $this->getString(); } /** * 获取比特串的值 * * @return string */ public function getString() { return $this->bit_string; } public function offsetGet($offset) { return $this->bit_string[$offset]; } /** * Whether a offset exists * * @link https://php.net/manual/en/arrayaccess.offsetexists.php * * @param mixed $offset

* An offset to check for. *

* * @return bool true on success or false on failure. *

*

* The return value will be casted to boolean if non-boolean was returned. * @since 5.0.0 */ public function offsetExists($offset) { return isset($this->bit_string[$offset]); } /** * Offset to set * * @link https://php.net/manual/en/arrayaccess.offsetset.php * * @param mixed $offset

* The offset to assign the value to. *

* @param mixed $value

* The value to set. *

* * @return BitString * @since 5.0.0 */ public function offsetSet($offset, $value) { $this->bit_string[$offset] = $value; return $this; } /** * Offset to unset * * @link https://php.net/manual/en/arrayaccess.offsetunset.php * * @param mixed $offset

* The offset to unset. *

* * @return void * @since 5.0.0 */ public function offsetUnset($offset) { unset($this->bit_string[$offset]); } } src/smecc/SM4/types/README.md000064400000000232150736751610011463 0ustar00# *types/* 目录 本目录为自定义的扩展类型的目录 * `\SM3\types\BitString` 比特串 类型 * `\SM3\types\Word` 字 类型src/smecc/SM4/types/Word.php000064400000002641150736751610011636 0ustar00bit_string) === self::length) { $this->word = $this->bit_string; } else { $this->word = intval($this->bit_string) === 0 ? 0 : $this->bit_string; if (strlen($this->word) <= self::length) { $this->word = str_pad( $this->word, self::length, '0', STR_PAD_LEFT ); } else { $this->word = substr($this->bit_string, -(self::length)); } } } public function __toString() { return $this->word; } public function offsetGet($offset) { return $this->word[$offset]; } public function getString() { return $this->word; } /** * @return string */ public function getBitString() { return $this->bit_string; } } test/data/rsa.pem000064400000001624150736751610007742 0ustar00-----BEGIN PRIVATE KEY----- MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALjnVY4j/UG0tJ5o HZclp1R1+HsCQmUctzPiN5VO56ZYuFP4T3oDhVkmWReL52WGaKYGrxJymqM6mPt8 C3AXNd/KGTpZtXaoBvjK21nPmgDpo6m5nifi+IQTXmjrwDPErr0yIrAvDMP+3wQl w/WJTXVMJb074bYpytmx9WXL2mRTAgMBAAECgYB8/TuTKvbOTKXvkne2LWjQKjK+ jAdvrBqXQurJzh2/D6gCcw7ebrTcT5TX2uWfdl0VJd2AfeHURw8UqIRe0AHEzj98 yLF4DNgJRbGLCbJm67idyt41E+jnc6zrboLmpOkQ0njYibNulqgbJQ2DaFhnoLI1 1CoPW383WxUfV6LquQJBAPLbtfPs+tKrun7zOaJ0GWMYRZBFxVNKE9EQS4X2pg+g NHo+b3bNPPoE66Ug+D69R1AYKC7QkP/zvXqT8dC1UVcCQQDC6MjeJqX4M4C9sfm6 x75VqmKNX6qaXzv28wrtMk7anSiR7YQUCs0kchHQz8hpYb+SQio4DhRYJyDHnO+f V/tlAkEAl33IbYVpHNs0tZYhYJ4NbAwq8IklQwRVgjco9ULbaankslCaFUCHhepl 2BbN480MXAEFp9ZAbPjtPDZnRGqmdwJARxy1hM/nCAqKcyuHKM2NtSWoNVptHUuX zj7YgrgzKvHiBnP5F3Lla+GufFgDD+fZBFzdmHwSkiMcg5fPmXx5PQJAfKdeiisM 1qDcCIFgHSD8JX3Di/oKPF/zyZ3dgFDC8SfqHh/0UuF3WBNUFHpHCO8CoZS/QioK YKN9KVMfaZThsw== -----END PRIVATE KEY----- test/data/rsapub.pem000064400000000420150736751610010442 0ustar00-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC451WOI/1BtLSeaB2XJadUdfh7 AkJlHLcz4jeVTuemWLhT+E96A4VZJlkXi+dlhmimBq8ScpqjOpj7fAtwFzXfyhk6 WbV2qAb4yttZz5oA6aOpuZ4n4viEE15o68AzxK69MiKwLwzD/t8EJcP1iU11TCW9 O+G2KcrZsfVly9pkUwIDAQAB -----END PUBLIC KEY----- test/data/sm2.pem000064400000000342150736751610007652 0ustar00-----BEGIN EC PRIVATE KEY----- MHcCAQEEIDMLq58c/Ox37b0NA4Ok65BcRRG+OmF1O+LtAIwRvmm8oAoGCCqBHM9V AYItoUQDQgAEyqo4GGHqDU6XIBpDCzEfi7Z2EpUzmU/s46pJioQkd7tNYAb3Em2J JJRFMK4l6WPlGze3zC66NaRZuyBagjDiVQ== -----END EC PRIVATE KEY-----test/data/sm2pub.pem000064400000000261150736751610010361 0ustar00-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEyqo4GGHqDU6XIBpDCzEfi7Z2EpUz mU/s46pJioQkd7tNYAb3Em2JJJRFMK4l6WPlGze3zC66NaRZuyBagjDiVQ== -----END PUBLIC KEY-----test/openssl_encryptsm2.php000064400000001716150736751610012125 0ustar00 OPENSSL_KEYTYPE_EC, "curve_name" => "SM2" ); $sslconf = "/usr/local/php/extras/openssl/openssl.cnf"; $config['config'] = $sslconf; $prikey = openssl_pkey_new($config); openssl_pkey_export($prikey, $prikeypem,null,$config); echo $prikeypem."\n"; $pubkeypem = openssl_pkey_get_details($prikey)["key"]; echo $pubkeypem."\n"; test/openssl_tsm3.php000064400000000104150736751610010673 0ustar00generatekey()); //生成明文密钥 echo "\n----------生成pem密钥对--------------------------\n"; print_r($sm2->generatePemkey()); //生成pem密钥,请放到相应的文件中 } if(SIGN){ echo "\n---------明文密钥签名---------------------------\n"; $sign = $sm2->doSign( $document, $privateKey, $userId); print_r($sign); echo "\n---------明文密钥验签---------------------------\n"; var_dump($sm2->verifySign( $document, $sign, $publicKey, $userId )); } if(SIGNPEM){ echo "\n---------PEM密钥签名---------------------------\n"; $sign = $sm2->doSignOutKey( $document, $privatefile, $userId); print_r($sign); echo "\n---------PEM密钥验签---------------------------\n"; var_dump($sm2->verifySignOutKey( $document, $sign, $publicfile, $userId )); } test/tsm3.php000064400000000221150736751610007130 0ustar00digest($data,1));test/tsm4.php000064400000000425150736751610007137 0ustar00encrypt($key, $data); //ecb echo "encrypt: $enc\n"; $decdata = $sm4->decrypt($key, $enc); echo "decrypt: $decdata\n"; vendor/autoload.php000064400000000262150736751610010375 0ustar00 * Jordi Boggiano * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Composer\Autoload; /** * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. * * $loader = new \Composer\Autoload\ClassLoader(); * * // register classes with namespaces * $loader->add('Symfony\Component', __DIR__.'/component'); * $loader->add('Symfony', __DIR__.'/framework'); * * // activate the autoloader * $loader->register(); * * // to enable searching the include path (eg. for PEAR packages) * $loader->setUseIncludePath(true); * * In this example, if you try to use a class in the Symfony\Component * namespace or one of its children (Symfony\Component\Console for instance), * the autoloader will first look for the class under the component/ * directory, and it will then fallback to the framework/ directory if not * found before giving up. * * This class is loosely based on the Symfony UniversalClassLoader. * * @author Fabien Potencier * @author Jordi Boggiano * @see http://www.php-fig.org/psr/psr-0/ * @see http://www.php-fig.org/psr/psr-4/ */ class ClassLoader { // PSR-4 private $prefixLengthsPsr4 = array(); private $prefixDirsPsr4 = array(); private $fallbackDirsPsr4 = array(); // PSR-0 private $prefixesPsr0 = array(); private $fallbackDirsPsr0 = array(); private $useIncludePath = false; private $classMap = array(); private $classMapAuthoritative = false; private $missingClasses = array(); private $apcuPrefix; public function getPrefixes() { if (!empty($this->prefixesPsr0)) { return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); } return array(); } public function getPrefixesPsr4() { return $this->prefixDirsPsr4; } public function getFallbackDirs() { return $this->fallbackDirsPsr0; } public function getFallbackDirsPsr4() { return $this->fallbackDirsPsr4; } public function getClassMap() { return $this->classMap; } /** * @param array $classMap Class to filename map */ public function addClassMap(array $classMap) { if ($this->classMap) { $this->classMap = array_merge($this->classMap, $classMap); } else { $this->classMap = $classMap; } } /** * Registers a set of PSR-0 directories for a given prefix, either * appending or prepending to the ones previously set for this prefix. * * @param string $prefix The prefix * @param array|string $paths The PSR-0 root directories * @param bool $prepend Whether to prepend the directories */ public function add($prefix, $paths, $prepend = false) { if (!$prefix) { if ($prepend) { $this->fallbackDirsPsr0 = array_merge( (array) $paths, $this->fallbackDirsPsr0 ); } else { $this->fallbackDirsPsr0 = array_merge( $this->fallbackDirsPsr0, (array) $paths ); } return; } $first = $prefix[0]; if (!isset($this->prefixesPsr0[$first][$prefix])) { $this->prefixesPsr0[$first][$prefix] = (array) $paths; return; } if ($prepend) { $this->prefixesPsr0[$first][$prefix] = array_merge( (array) $paths, $this->prefixesPsr0[$first][$prefix] ); } else { $this->prefixesPsr0[$first][$prefix] = array_merge( $this->prefixesPsr0[$first][$prefix], (array) $paths ); } } /** * Registers a set of PSR-4 directories for a given namespace, either * appending or prepending to the ones previously set for this namespace. * * @param string $prefix The prefix/namespace, with trailing '\\' * @param array|string $paths The PSR-4 base directories * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException */ public function addPsr4($prefix, $paths, $prepend = false) { if (!$prefix) { // Register directories for the root namespace. if ($prepend) { $this->fallbackDirsPsr4 = array_merge( (array) $paths, $this->fallbackDirsPsr4 ); } else { $this->fallbackDirsPsr4 = array_merge( $this->fallbackDirsPsr4, (array) $paths ); } } elseif (!isset($this->prefixDirsPsr4[$prefix])) { // Register directories for a new namespace. $length = strlen($prefix); if ('\\' !== $prefix[$length - 1]) { throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); } $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; $this->prefixDirsPsr4[$prefix] = (array) $paths; } elseif ($prepend) { // Prepend directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( (array) $paths, $this->prefixDirsPsr4[$prefix] ); } else { // Append directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix], (array) $paths ); } } /** * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. * * @param string $prefix The prefix * @param array|string $paths The PSR-0 base directories */ public function set($prefix, $paths) { if (!$prefix) { $this->fallbackDirsPsr0 = (array) $paths; } else { $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; } } /** * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * * @param string $prefix The prefix/namespace, with trailing '\\' * @param array|string $paths The PSR-4 base directories * * @throws \InvalidArgumentException */ public function setPsr4($prefix, $paths) { if (!$prefix) { $this->fallbackDirsPsr4 = (array) $paths; } else { $length = strlen($prefix); if ('\\' !== $prefix[$length - 1]) { throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); } $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; $this->prefixDirsPsr4[$prefix] = (array) $paths; } } /** * Turns on searching the include path for class files. * * @param bool $useIncludePath */ public function setUseIncludePath($useIncludePath) { $this->useIncludePath = $useIncludePath; } /** * Can be used to check if the autoloader uses the include path to check * for classes. * * @return bool */ public function getUseIncludePath() { return $this->useIncludePath; } /** * Turns off searching the prefix and fallback directories for classes * that have not been registered with the class map. * * @param bool $classMapAuthoritative */ public function setClassMapAuthoritative($classMapAuthoritative) { $this->classMapAuthoritative = $classMapAuthoritative; } /** * Should class lookup fail if not found in the current class map? * * @return bool */ public function isClassMapAuthoritative() { return $this->classMapAuthoritative; } /** * APCu prefix to use to cache found/not-found classes, if the extension is enabled. * * @param string|null $apcuPrefix */ public function setApcuPrefix($apcuPrefix) { $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; } /** * The APCu prefix in use, or null if APCu caching is not enabled. * * @return string|null */ public function getApcuPrefix() { return $this->apcuPrefix; } /** * Registers this instance as an autoloader. * * @param bool $prepend Whether to prepend the autoloader or not */ public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); } /** * Unregisters this instance as an autoloader. */ public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); } /** * Loads the given class or interface. * * @param string $class The name of the class * @return bool|null True if loaded, null otherwise */ public function loadClass($class) { if ($file = $this->findFile($class)) { includeFile($file); return true; } } /** * Finds the path to the file where the class is defined. * * @param string $class The name of the class * * @return string|false The path if found, false otherwise */ public function findFile($class) { // class map lookup if (isset($this->classMap[$class])) { return $this->classMap[$class]; } if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { return false; } if (null !== $this->apcuPrefix) { $file = apcu_fetch($this->apcuPrefix.$class, $hit); if ($hit) { return $file; } } $file = $this->findFileWithExtension($class, '.php'); // Search for Hack files if we are running on HHVM if (false === $file && defined('HHVM_VERSION')) { $file = $this->findFileWithExtension($class, '.hh'); } if (null !== $this->apcuPrefix) { apcu_add($this->apcuPrefix.$class, $file); } if (false === $file) { // Remember that this class does not exist. $this->missingClasses[$class] = true; } return $file; } private function findFileWithExtension($class, $ext) { // PSR-4 lookup $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; $first = $class[0]; if (isset($this->prefixLengthsPsr4[$first])) { $subPath = $class; while (false !== $lastPos = strrpos($subPath, '\\')) { $subPath = substr($subPath, 0, $lastPos); $search = $subPath . '\\'; if (isset($this->prefixDirsPsr4[$search])) { $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); foreach ($this->prefixDirsPsr4[$search] as $dir) { if (file_exists($file = $dir . $pathEnd)) { return $file; } } } } } // PSR-4 fallback dirs foreach ($this->fallbackDirsPsr4 as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { return $file; } } // PSR-0 lookup if (false !== $pos = strrpos($class, '\\')) { // namespaced class name $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); } else { // PEAR-like class name $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; } if (isset($this->prefixesPsr0[$first])) { foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { if (0 === strpos($class, $prefix)) { foreach ($dirs as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { return $file; } } } } } // PSR-0 fallback dirs foreach ($this->fallbackDirsPsr0 as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { return $file; } } // PSR-0 include paths. if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { return $file; } return false; } } /** * Scope isolated include. * * Prevents access to $this/self from included files. */ function includeFile($file) { // echo "--- $file --\n"; include $file; } vendor/composer/LICENSE000064400000002056150736751610010713 0ustar00 Copyright (c) Nils Adermann, Jordi Boggiano 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. vendor/composer/autoload_classmap.php000064400000000223150736751610014104 0ustar00 array($baseDir . '/src'), 'Mdanter\\Ecc\\' => array($vendorDir . '/mdanter/ecc/src'), 'FG\\' => array($vendorDir . '/fgrosse/phpasn1/lib'), ); vendor/composer/autoload_real.php000064400000004654150736751610013240 0ustar00= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { require_once __DIR__ . '/autoload_static.php'; call_user_func(\Composer\Autoload\ComposerStaticInit2947222f186fee6916557ac7c2bef61b::getInitializer($loader)); } else { $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { $loader->set($namespace, $path); } $map = require __DIR__ . '/autoload_psr4.php'; foreach ($map as $namespace => $path) { $loader->setPsr4($namespace, $path); } $classMap = require __DIR__ . '/autoload_classmap.php'; if ($classMap) { $loader->addClassMap($classMap); } } $loader->register(true); if ($useStaticLoader) { $includeFiles = Composer\Autoload\ComposerStaticInit2947222f186fee6916557ac7c2bef61b::$files; } else { $includeFiles = require __DIR__ . '/autoload_files.php'; } foreach ($includeFiles as $fileIdentifier => $file) { composerRequire2947222f186fee6916557ac7c2bef61b($fileIdentifier, $file); } return $loader; } } function composerRequire2947222f186fee6916557ac7c2bef61b($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { require $file; $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; } } vendor/composer/autoload_static.php000064400000002427150736751610013600 0ustar00 __DIR__ . '/../..' . '/src/overwrite.php', ); public static $prefixLengthsPsr4 = array ( 'R' => array ( 'Rtgm\\' => 5, ), 'M' => array ( 'Mdanter\\Ecc\\' => 12, ), 'F' => array ( 'FG\\' => 3, ), ); public static $prefixDirsPsr4 = array ( 'Rtgm\\' => array ( 0 => __DIR__ . '/../..' . '/src', ), 'Mdanter\\Ecc\\' => array ( 0 => __DIR__ . '/..' . '/mdanter/ecc/src', ), 'FG\\' => array ( 0 => __DIR__ . '/..' . '/fgrosse/phpasn1/lib', ), ); public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { $loader->prefixLengthsPsr4 = ComposerStaticInit2947222f186fee6916557ac7c2bef61b::$prefixLengthsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInit2947222f186fee6916557ac7c2bef61b::$prefixDirsPsr4; }, null, ClassLoader::class); } } vendor/composer/installed.json000064400000012023150736751610012553 0ustar00[ { "name": "fgrosse/phpasn1", "version": "v2.3.0", "version_normalized": "2.3.0.0", "source": { "type": "git", "url": "https://github.com/fgrosse/PHPASN1.git", "reference": "20299033c35f4300eb656e7e8e88cf52d1d6694e" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/20299033c35f4300eb656e7e8e88cf52d1d6694e", "reference": "20299033c35f4300eb656e7e8e88cf52d1d6694e", "shasum": "", "mirrors": [ { "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", "preferred": true } ] }, "require": { "php": ">=7.0.0" }, "require-dev": { "phpunit/phpunit": "~6.3", "satooshi/php-coveralls": "~2.0" }, "suggest": { "ext-bcmath": "BCmath is the fallback extension for big integer calculations", "ext-curl": "For loading OID information from the web if they have not bee defined statically", "ext-gmp": "GMP is the preferred extension for big integer calculations", "phpseclib/bcmath_compat": "BCmath polyfill for servers where neither GMP nor BCmath is available" }, "time": "2021-04-24T19:01:55+00:00", "type": "library", "extra": { "branch-alias": { "dev-master": "2.0.x-dev" } }, "installation-source": "dist", "autoload": { "psr-4": { "FG\\": "lib/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Friedrich Große", "email": "friedrich.grosse@gmail.com", "homepage": "https://github.com/FGrosse", "role": "Author" }, { "name": "All contributors", "homepage": "https://github.com/FGrosse/PHPASN1/contributors" } ], "description": "A PHP Framework that allows you to encode and decode arbitrary ASN.1 structures using the ITU-T X.690 Encoding Rules.", "homepage": "https://github.com/FGrosse/PHPASN1", "keywords": [ "DER", "asn.1", "asn1", "ber", "binary", "decoding", "encoding", "x.509", "x.690", "x509", "x690" ] }, { "name": "mdanter/ecc", "version": "v0.5.2", "version_normalized": "0.5.2.0", "source": { "type": "git", "url": "https://github.com/phpecc/phpecc.git", "reference": "b95f25cc1bacc83a9f0ccd375900b7cfd343029e" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpecc/phpecc/zipball/b95f25cc1bacc83a9f0ccd375900b7cfd343029e", "reference": "b95f25cc1bacc83a9f0ccd375900b7cfd343029e", "shasum": "", "mirrors": [ { "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", "preferred": true } ] }, "require": { "ext-gmp": "*", "fgrosse/phpasn1": "^2.0", "php": "^7.0" }, "require-dev": { "phpunit/phpunit": "^6.0", "squizlabs/php_codesniffer": "^2.0", "symfony/yaml": "^2.6|^3.0" }, "time": "2018-12-03T18:17:01+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "Mdanter\\Ecc\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Matyas Danter", "homepage": "http://matejdanter.com/", "role": "Author" }, { "name": "Thibaud Fabre", "email": "thibaud@aztech.io", "homepage": "http://aztech.io", "role": "Maintainer" }, { "name": "Thomas Kerin", "email": "afk11@users.noreply.github.com", "role": "Maintainer" } ], "description": "PHP Elliptic Curve Cryptography library", "homepage": "https://github.com/phpecc/phpecc", "keywords": [ "Diffie", "ECDSA", "Hellman", "curve", "ecdh", "elliptic", "nistp192", "nistp224", "nistp256", "nistp384", "nistp521", "phpecc", "secp256k1", "secp256r1" ] } ] vendor/fgrosse/phpasn1/CHANGELOG.md000064400000004423150736751610012712 0ustar00#### v2.3.0 (2021-04) * Allow creating an unsigned CSR and adding the signature later https://github.com/fgrosse/PHPASN1/pull/82 #### v2.2.0 (2020-08) * support polyfills for bcmath and gmp, and add a composer.json suggestion for the `phpseclib/bcmath_polyfill` for servers unable to install PHP the gmp or bcmath extensions. #### v.2.1.1 & &v.2.0.2 (2018-12) * add stricter validation around some structures, highlighed by wycheproof test suite #### v.2.1.0 (2018-03) * add support for `bcmath` extension (making `gmp` optional)
https://github.com/fgrosse/PHPASN1/pull/68 #### v.2.0.1 & v.1.5.3 (2017-12) * add .gitattributes file to prevent examples and tests to be installed via composer when --prefer-dist was set #### v.2.0.0 (2017-08) * rename `FG\ASN1\Object` to `FG\ASN1\ASNObject` because `Object` is a special class name in the next major PHP release - when you upgrade you have to adapt all corresponding `use` and `extends` statements as well as type hints and all usages of `Object::fromBinary(…)`. * generally drop PHP 5.6 support #### v.1.5.2 (2016-10-29) * allow empty octet strings #### v.1.5.1 (2015-10-02) * add keywords to composer.json (this is a version on its own so the keywords are found on a stable version at packagist.org) #### v.1.5.0 (2015-10-30) * fix a bug that would prevent you from decoding context specific tags on multiple objects [#57](https://github.com/fgrosse/PHPASN1/issues/57) - `ExplicitlyTaggedObject::__construct` does now accept multiple objects to be tagged with a single tag - `ExplicitlyTaggedObject::getContent` will now always return an array (even if only one object is tagged) #### v.1.4.2 (2015-09-29) * fix a bug that would prevent you from decoding empty tagged objects [#57](https://github.com/fgrosse/PHPASN1/issues/57) #### v.1.4.1 * improve exception messages and general error handling [#55](https://github.com/fgrosse/PHPASN1/pull/55) #### v.1.4.0 * **require PHP 5.6** * support big integers (closes #1 and #37) * enforce one code style via [styleci.io][9] * track code coverage via [coveralls.io][10] * replace obsolete `FG\ASN1\Exception\GeneralException` with `\Exception` * `Construct` (`Sequence`, `Set`) does now implement `ArrayAccess`, `Countable` and `Iterator` so its easier to use * add [`TemplateParser`][11] vendor/fgrosse/phpasn1/LICENSE000064400000002106150736751610012102 0ustar00Copyright (c) 2012-2015 Friedrich Große 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. vendor/fgrosse/phpasn1/README.md000064400000014455150736751610012366 0ustar00PHPASN1 ======= [![Build Status](https://secure.travis-ci.org/fgrosse/PHPASN1.png?branch=master)](http://travis-ci.org/fgrosse/PHPASN1) [![PHP 7 ready](http://php7ready.timesplinter.ch/fgrosse/PHPASN1/badge.svg)](https://travis-ci.org/fgrosse/PHPASN1) [![Coverage Status](https://coveralls.io/repos/fgrosse/PHPASN1/badge.svg?branch=master&service=github)](https://coveralls.io/github/fgrosse/PHPASN1?branch=master) [![Latest Stable Version](https://poser.pugx.org/fgrosse/phpasn1/v/stable.png)](https://packagist.org/packages/fgrosse/phpasn1) [![Total Downloads](https://poser.pugx.org/fgrosse/phpasn1/downloads.png)](https://packagist.org/packages/fgrosse/phpasn1) [![Latest Unstable Version](https://poser.pugx.org/fgrosse/phpasn1/v/unstable.png)](https://packagist.org/packages/fgrosse/phpasn1) [![License](https://poser.pugx.org/fgrosse/phpasn1/license.png)](https://packagist.org/packages/fgrosse/phpasn1) A PHP Framework that allows you to encode and decode arbitrary [ASN.1][3] structures using the [ITU-T X.690 Encoding Rules][4]. This encoding is very frequently used in [X.509 PKI environments][5] or the communication between heterogeneous computer systems. The API allows you to encode ASN.1 structures to create binary data such as certificate signing requests (CSR), X.509 certificates or certificate revocation lists (CRL). PHPASN1 can also read [BER encoded][6] binary data into separate PHP objects that can be manipulated by the user and reencoded afterwards. The **changelog** can now be found at [CHANGELOG.md](CHANGELOG.md). ## Dependencies PHPASN1 requires at least `PHP 7.0` and either the `gmp` or `bcmath` extension. Support for older PHP versions (i.e. PHP 5.6) was dropped starting with `v2.0`. If you must use an outdated PHP version consider using [PHPASN v1.5][13]. For the loading of object identifier names directly from the web [curl][7] is used. ## Installation The preferred way to install this library is to rely on [Composer][2]: ```bash $ composer require fgrosse/phpasn1 ``` ## Usage ### Encoding ASN.1 Structures PHPASN1 offers you a class for each of the implemented ASN.1 universal types. The constructors should be pretty self explanatory so you should have no big trouble getting started. All data will be encoded using [DER encoding][8] ```php use FG\ASN1\OID; use FG\ASN1\Universal\Integer; use FG\ASN1\Universal\Boolean; use FG\ASN1\Universal\Enumerated; use FG\ASN1\Universal\IA5String; use FG\ASN1\Universal\ObjectIdentifier; use FG\ASN1\Universal\PrintableString; use FG\ASN1\Universal\Sequence; use FG\ASN1\Universal\Set; use FG\ASN1\Universal\NullObject; $integer = new Integer(123456); $boolean = new Boolean(true); $enum = new Enumerated(1); $ia5String = new IA5String('Hello world'); $asnNull = new NullObject(); $objectIdentifier1 = new ObjectIdentifier('1.2.250.1.16.9'); $objectIdentifier2 = new ObjectIdentifier(OID::RSA_ENCRYPTION); $printableString = new PrintableString('Foo bar'); $sequence = new Sequence($integer, $boolean, $enum, $ia5String); $set = new Set($sequence, $asnNull, $objectIdentifier1, $objectIdentifier2, $printableString); $myBinary = $sequence->getBinary(); $myBinary .= $set->getBinary(); echo base64_encode($myBinary); ``` ### Decoding binary data Decoding BER encoded binary data is just as easy as encoding it: ```php use FG\ASN1\ASNObject; $base64String = ... $binaryData = base64_decode($base64String); $asnObject = ASNObject::fromBinary($binaryData); // do stuff ``` If you already know exactly how your expected data should look like you can use the `FG\ASN1\TemplateParser`: ```php use FG\ASN1\TemplateParser; // first define your template $template = [ Identifier::SEQUENCE => [ Identifier::SET => [ Identifier::OBJECT_IDENTIFIER, Identifier::SEQUENCE => [ Identifier::INTEGER, Identifier::BITSTRING, ] ] ] ]; // if your binary data is not matching the template you provided this will throw an `\Exception`: $parser = new TemplateParser(); $object = $parser->parseBinary($data, $template); // there is also a convenience function if you parse binary data from base64: $object = $parser->parseBase64($data, $template); ``` You can use this function to make sure your data has exactly the format you are expecting. ### Navigating decoded data All constructed classes (i.e. `Sequence` and `Set`) can be navigated by array access or using an iterator. You can find examples [here](https://github.com/fgrosse/PHPASN1/blob/f6442cadda9d36f3518c737e32f28300a588b777/tests/ASN1/Universal/SequenceTest.php#L148-148), [here](https://github.com/fgrosse/PHPASN1/blob/f6442cadda9d36f3518c737e32f28300a588b777/tests/ASN1/Universal/SequenceTest.php#L121) and [here](https://github.com/fgrosse/PHPASN1/blob/f6442cadda9d36f3518c737e32f28300a588b777/tests/ASN1/TemplateParserTest.php#L45). ### Give me more examples! To see some example usage of the API classes or some generated output check out the [examples](https://github.com/fgrosse/PHPASN1/tree/master/examples). ### How do I contribute? If you found an issue or have a question submit a github issue with detailed information. In case you already know what caused the issue and feel in the mood to fix it, your code contributions are always welcome. Just fork the repository, implement your changes and make sure that you covered everything with tests. Afterwards submit a pull request via github and be a little patient :) I usually try to comment and/or merge as soon as possible. #### Mailing list New features or questions can be discussed in [this google group/mailing list][12]. ### Thanks To [all contributors][1] so far! ## License This library is distributed under the [MIT License](LICENSE). [1]: https://github.com/fgrosse/PHPASN1/graphs/contributors [2]: https://getcomposer.org/ [3]: http://www.itu.int/ITU-T/asn1/ [4]: http://www.itu.int/ITU-T/recommendations/rec.aspx?rec=x.690 [5]: http://en.wikipedia.org/wiki/X.509 [6]: http://en.wikipedia.org/wiki/X.690#BER_encoding [7]: http://php.net/manual/en/book.curl.php [8]: http://en.wikipedia.org/wiki/X.690#DER_encoding [9]: https://styleci.io [10]: https://coveralls.io/github/fgrosse/PHPASN1 [11]: https://github.com/fgrosse/PHPASN1/blob/master/tests/ASN1/TemplateParserTest.php#L16 [12]: https://groups.google.com/d/forum/phpasn1 [13]: https://packagist.org/packages/fgrosse/phpasn1#1.5.2 vendor/fgrosse/phpasn1/composer.json000064400000003045150736751610013622 0ustar00{ "name": "fgrosse/phpasn1", "description": "A PHP Framework that allows you to encode and decode arbitrary ASN.1 structures using the ITU-T X.690 Encoding Rules.", "type": "library", "homepage": "https://github.com/FGrosse/PHPASN1", "license": "MIT", "authors": [ { "name": "Friedrich Große", "email": "friedrich.grosse@gmail.com", "homepage": "https://github.com/FGrosse", "role": "Author" }, { "name": "All contributors", "homepage": "https://github.com/FGrosse/PHPASN1/contributors" } ], "keywords": [ "x690", "x.690", "x.509", "x509", "asn1", "asn.1", "ber", "der", "binary", "encoding", "decoding" ], "require": { "php": ">=7.0.0" }, "require-dev": { "phpunit/phpunit": "~6.3", "satooshi/php-coveralls": "~2.0" }, "suggest": { "ext-gmp": "GMP is the preferred extension for big integer calculations", "ext-bcmath": "BCmath is the fallback extension for big integer calculations", "phpseclib/bcmath_compat": "BCmath polyfill for servers where neither GMP nor BCmath is available", "ext-curl": "For loading OID information from the web if they have not bee defined statically" }, "autoload": { "psr-4": { "FG\\": "lib/" } }, "autoload-dev": { "psr-4": { "FG\\Test\\": "tests/" } }, "extra": { "branch-alias": { "dev-master": "2.0.x-dev" } } } vendor/fgrosse/phpasn1/lib/ASN1/ASNObject.php000064400000031534150736751610014635 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1; use FG\ASN1\Exception\ParserException; use FG\ASN1\Universal\BitString; use FG\ASN1\Universal\Boolean; use FG\ASN1\Universal\Enumerated; use FG\ASN1\Universal\GeneralizedTime; use FG\ASN1\Universal\Integer; use FG\ASN1\Universal\NullObject; use FG\ASN1\Universal\ObjectIdentifier; use FG\ASN1\Universal\RelativeObjectIdentifier; use FG\ASN1\Universal\OctetString; use FG\ASN1\Universal\Sequence; use FG\ASN1\Universal\Set; use FG\ASN1\Universal\UTCTime; use FG\ASN1\Universal\IA5String; use FG\ASN1\Universal\PrintableString; use FG\ASN1\Universal\NumericString; use FG\ASN1\Universal\UTF8String; use FG\ASN1\Universal\UniversalString; use FG\ASN1\Universal\CharacterString; use FG\ASN1\Universal\GeneralString; use FG\ASN1\Universal\VisibleString; use FG\ASN1\Universal\GraphicString; use FG\ASN1\Universal\BMPString; use FG\ASN1\Universal\T61String; use FG\ASN1\Universal\ObjectDescriptor; use FG\Utility\BigInteger; use LogicException; /** * Class ASNObject is the base class for all concrete ASN.1 objects. */ abstract class ASNObject implements Parsable { private $contentLength; private $nrOfLengthOctets; /** * Must return the number of octets of the content part. * * @return int */ abstract protected function calculateContentLength(); /** * Encode the object using DER encoding. * * @see http://en.wikipedia.org/wiki/X.690#DER_encoding * * @return string the binary representation of an objects value */ abstract protected function getEncodedValue(); /** * Return the content of this object in a non encoded form. * This can be used to print the value in human readable form. * * @return mixed */ abstract public function getContent(); /** * Return the object type octet. * This should use the class constants of Identifier. * * @see Identifier * * @return int */ abstract public function getType(); /** * Returns all identifier octets. If an inheriting class models a tag with * the long form identifier format, it MUST reimplement this method to * return all octets of the identifier. * * @throws LogicException If the identifier format is long form * * @return string Identifier as a set of octets */ public function getIdentifier() { $firstOctet = $this->getType(); if (Identifier::isLongForm($firstOctet)) { throw new LogicException(sprintf('Identifier of %s uses the long form and must therefor override "ASNObject::getIdentifier()".', get_class($this))); } return chr($firstOctet); } /** * Encode this object using DER encoding. * * @return string the full binary representation of the complete object */ public function getBinary() { $result = $this->getIdentifier(); $result .= $this->createLengthPart(); $result .= $this->getEncodedValue(); return $result; } private function createLengthPart() { $contentLength = $this->getContentLength(); $nrOfLengthOctets = $this->getNumberOfLengthOctets($contentLength); if ($nrOfLengthOctets == 1) { return chr($contentLength); } else { // the first length octet determines the number subsequent length octets $lengthOctets = chr(0x80 | ($nrOfLengthOctets - 1)); for ($shiftLength = 8 * ($nrOfLengthOctets - 2); $shiftLength >= 0; $shiftLength -= 8) { $lengthOctets .= chr($contentLength >> $shiftLength); } return $lengthOctets; } } protected function getNumberOfLengthOctets($contentLength = null) { if (!isset($this->nrOfLengthOctets)) { if ($contentLength == null) { $contentLength = $this->getContentLength(); } $this->nrOfLengthOctets = 1; if ($contentLength > 127) { do { // long form $this->nrOfLengthOctets++; $contentLength = $contentLength >> 8; } while ($contentLength > 0); } } return $this->nrOfLengthOctets; } protected function getContentLength() { if (!isset($this->contentLength)) { $this->contentLength = $this->calculateContentLength(); } return $this->contentLength; } protected function setContentLength($newContentLength) { $this->contentLength = $newContentLength; $this->getNumberOfLengthOctets($newContentLength); } /** * Returns the length of the whole object (including the identifier and length octets). */ public function getObjectLength() { $nrOfIdentifierOctets = strlen($this->getIdentifier()); $contentLength = $this->getContentLength(); $nrOfLengthOctets = $this->getNumberOfLengthOctets($contentLength); return $nrOfIdentifierOctets + $nrOfLengthOctets + $contentLength; } public function __toString() { return $this->getContent(); } /** * Returns the name of the ASN.1 Type of this object. * * @see Identifier::getName() */ public function getTypeName() { return Identifier::getName($this->getType()); } /** * @param string $binaryData * @param int $offsetIndex * * @throws ParserException * * @return \FG\ASN1\ASNObject */ public static function fromBinary(&$binaryData, &$offsetIndex = 0) { if (strlen($binaryData) <= $offsetIndex) { throw new ParserException('Can not parse binary from data: Offset index larger than input size', $offsetIndex); } $identifierOctet = ord($binaryData[$offsetIndex]); if (Identifier::isContextSpecificClass($identifierOctet) && Identifier::isConstructed($identifierOctet)) { return ExplicitlyTaggedObject::fromBinary($binaryData, $offsetIndex); } switch ($identifierOctet) { case Identifier::BITSTRING: return BitString::fromBinary($binaryData, $offsetIndex); case Identifier::BOOLEAN: return Boolean::fromBinary($binaryData, $offsetIndex); case Identifier::ENUMERATED: return Enumerated::fromBinary($binaryData, $offsetIndex); case Identifier::INTEGER: return Integer::fromBinary($binaryData, $offsetIndex); case Identifier::NULL: return NullObject::fromBinary($binaryData, $offsetIndex); case Identifier::OBJECT_IDENTIFIER: return ObjectIdentifier::fromBinary($binaryData, $offsetIndex); case Identifier::RELATIVE_OID: return RelativeObjectIdentifier::fromBinary($binaryData, $offsetIndex); case Identifier::OCTETSTRING: return OctetString::fromBinary($binaryData, $offsetIndex); case Identifier::SEQUENCE: return Sequence::fromBinary($binaryData, $offsetIndex); case Identifier::SET: return Set::fromBinary($binaryData, $offsetIndex); case Identifier::UTC_TIME: return UTCTime::fromBinary($binaryData, $offsetIndex); case Identifier::GENERALIZED_TIME: return GeneralizedTime::fromBinary($binaryData, $offsetIndex); case Identifier::IA5_STRING: return IA5String::fromBinary($binaryData, $offsetIndex); case Identifier::PRINTABLE_STRING: return PrintableString::fromBinary($binaryData, $offsetIndex); case Identifier::NUMERIC_STRING: return NumericString::fromBinary($binaryData, $offsetIndex); case Identifier::UTF8_STRING: return UTF8String::fromBinary($binaryData, $offsetIndex); case Identifier::UNIVERSAL_STRING: return UniversalString::fromBinary($binaryData, $offsetIndex); case Identifier::CHARACTER_STRING: return CharacterString::fromBinary($binaryData, $offsetIndex); case Identifier::GENERAL_STRING: return GeneralString::fromBinary($binaryData, $offsetIndex); case Identifier::VISIBLE_STRING: return VisibleString::fromBinary($binaryData, $offsetIndex); case Identifier::GRAPHIC_STRING: return GraphicString::fromBinary($binaryData, $offsetIndex); case Identifier::BMP_STRING: return BMPString::fromBinary($binaryData, $offsetIndex); case Identifier::T61_STRING: return T61String::fromBinary($binaryData, $offsetIndex); case Identifier::OBJECT_DESCRIPTOR: return ObjectDescriptor::fromBinary($binaryData, $offsetIndex); default: // At this point the identifier may be >1 byte. if (Identifier::isConstructed($identifierOctet)) { return new UnknownConstructedObject($binaryData, $offsetIndex); } else { $identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex); $lengthOfUnknownObject = self::parseContentLength($binaryData, $offsetIndex); $offsetIndex += $lengthOfUnknownObject; return new UnknownObject($identifier, $lengthOfUnknownObject); } } } protected static function parseIdentifier($identifierOctet, $expectedIdentifier, $offsetForExceptionHandling) { if (is_string($identifierOctet) || is_numeric($identifierOctet) == false) { $identifierOctet = ord($identifierOctet); } if ($identifierOctet != $expectedIdentifier) { $message = 'Can not create an '.Identifier::getName($expectedIdentifier).' from an '.Identifier::getName($identifierOctet); throw new ParserException($message, $offsetForExceptionHandling); } } protected static function parseBinaryIdentifier($binaryData, &$offsetIndex) { if (strlen($binaryData) <= $offsetIndex) { throw new ParserException('Can not parse identifier from data: Offset index larger than input size', $offsetIndex); } $identifier = $binaryData[$offsetIndex++]; if (Identifier::isLongForm(ord($identifier)) == false) { return $identifier; } while (true) { if (strlen($binaryData) <= $offsetIndex) { throw new ParserException('Can not parse identifier (long form) from data: Offset index larger than input size', $offsetIndex); } $nextOctet = $binaryData[$offsetIndex++]; $identifier .= $nextOctet; if ((ord($nextOctet) & 0x80) === 0) { // the most significant bit is 0 to we have reached the end of the identifier break; } } return $identifier; } protected static function parseContentLength(&$binaryData, &$offsetIndex, $minimumLength = 0) { if (strlen($binaryData) <= $offsetIndex) { throw new ParserException('Can not parse content length from data: Offset index larger than input size', $offsetIndex); } $contentLength = ord($binaryData[$offsetIndex++]); if (($contentLength & 0x80) != 0) { // bit 8 is set -> this is the long form $nrOfLengthOctets = $contentLength & 0x7F; $contentLength = BigInteger::create(0x00); for ($i = 0; $i < $nrOfLengthOctets; $i++) { if (strlen($binaryData) <= $offsetIndex) { throw new ParserException('Can not parse content length (long form) from data: Offset index larger than input size', $offsetIndex); } $contentLength = $contentLength->shiftLeft(8)->add(ord($binaryData[$offsetIndex++])); } if ($contentLength->compare(PHP_INT_MAX) > 0) { throw new ParserException("Can not parse content length from data: length > maximum integer", $offsetIndex); } $contentLength = $contentLength->toInteger(); } if ($contentLength < $minimumLength) { throw new ParserException('A '.get_called_class()." should have a content length of at least {$minimumLength}. Extracted length was {$contentLength}", $offsetIndex); } $lenDataRemaining = strlen($binaryData) - $offsetIndex; if ($lenDataRemaining < $contentLength) { throw new ParserException("Content length {$contentLength} exceeds remaining data length {$lenDataRemaining}", $offsetIndex); } return $contentLength; } } vendor/fgrosse/phpasn1/lib/ASN1/AbstractString.php000064400000006505150736751610016017 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1; use Exception; abstract class AbstractString extends ASNObject implements Parsable { /** @var string */ protected $value; private $checkStringForIllegalChars = true; private $allowedCharacters = []; /** * The abstract base class for ASN.1 classes which represent some string of character. * * @param string $string */ public function __construct($string) { $this->value = $string; } public function getContent() { return $this->value; } protected function allowCharacter($character) { $this->allowedCharacters[] = $character; } protected function allowCharacters(...$characters) { foreach ($characters as $character) { $this->allowedCharacters[] = $character; } } protected function allowNumbers() { foreach (range('0', '9') as $char) { $this->allowedCharacters[] = (string) $char; } } protected function allowAllLetters() { $this->allowSmallLetters(); $this->allowCapitalLetters(); } protected function allowSmallLetters() { foreach (range('a', 'z') as $char) { $this->allowedCharacters[] = $char; } } protected function allowCapitalLetters() { foreach (range('A', 'Z') as $char) { $this->allowedCharacters[] = $char; } } protected function allowSpaces() { $this->allowedCharacters[] = ' '; } protected function allowAll() { $this->checkStringForIllegalChars = false; } protected function calculateContentLength() { return strlen($this->value); } protected function getEncodedValue() { if ($this->checkStringForIllegalChars) { $this->checkString(); } return $this->value; } protected function checkString() { $stringLength = $this->getContentLength(); for ($i = 0; $i < $stringLength; $i++) { if (in_array($this->value[$i], $this->allowedCharacters) == false) { $typeName = Identifier::getName($this->getType()); throw new Exception("Could not create a {$typeName} from the character sequence '{$this->value}'."); } } } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { $parsedObject = new static(''); self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++); $contentLength = self::parseContentLength($binaryData, $offsetIndex); $string = substr($binaryData, $offsetIndex, $contentLength); $offsetIndex += $contentLength; $parsedObject->value = $string; $parsedObject->setContentLength($contentLength); return $parsedObject; } public static function isValid($string) { $testObject = new static($string); try { $testObject->checkString(); return true; } catch (Exception $exception) { return false; } } } vendor/fgrosse/phpasn1/lib/ASN1/AbstractTime.php000064400000004421150736751610015442 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1; use DateInterval; use DateTime; use DateTimeZone; use Exception; abstract class AbstractTime extends ASNObject { /** @var DateTime */ protected $value; public function __construct($dateTime = null, $dateTimeZone = 'UTC') { if ($dateTime == null || is_string($dateTime)) { $timeZone = new DateTimeZone($dateTimeZone); $dateTimeObject = new DateTime($dateTime, $timeZone); if ($dateTimeObject == false) { $errorMessage = $this->getLastDateTimeErrors(); $className = Identifier::getName($this->getType()); throw new Exception(sprintf("Could not create %s from date time string '%s': %s", $className, $dateTime, $errorMessage)); } $dateTime = $dateTimeObject; } elseif (!$dateTime instanceof DateTime) { throw new Exception('Invalid first argument for some instance of AbstractTime constructor'); } $this->value = $dateTime; } public function getContent() { return $this->value; } protected function getLastDateTimeErrors() { $messages = ''; $lastErrors = DateTime::getLastErrors(); foreach ($lastErrors['errors'] as $errorMessage) { $messages .= "{$errorMessage}, "; } return substr($messages, 0, -2); } public function __toString() { return $this->value->format("Y-m-d\tH:i:s"); } protected static function extractTimeZoneData(&$binaryData, &$offsetIndex, DateTime $dateTime) { $sign = $binaryData[$offsetIndex++]; $timeOffsetHours = intval(substr($binaryData, $offsetIndex, 2)); $timeOffsetMinutes = intval(substr($binaryData, $offsetIndex + 2, 2)); $offsetIndex += 4; $interval = new DateInterval("PT{$timeOffsetHours}H{$timeOffsetMinutes}M"); if ($sign == '+') { $dateTime->sub($interval); } else { $dateTime->add($interval); } return $dateTime; } } vendor/fgrosse/phpasn1/lib/ASN1/Base128.php000064400000002715150736751610014171 0ustar00modulus(0x80)->toInteger()); $value = $value->shiftRight(7); while ($value->compare(0) > 0) { $octets .= chr(0x80 | $value->modulus(0x80)->toInteger()); $value = $value->shiftRight(7); } return strrev($octets); } /** * @param string $octets * * @throws InvalidArgumentException if the given octets represent a malformed base-128 value or the decoded value would exceed the the maximum integer length * * @return int */ public static function decode($octets) { $bitsPerOctet = 7; $value = BigInteger::create(0); $i = 0; while (true) { if (!isset($octets[$i])) { throw new InvalidArgumentException(sprintf('Malformed base-128 encoded value (0x%s).', strtoupper(bin2hex($octets)) ?: '0')); } $octet = ord($octets[$i++]); $l1 = $value->shiftLeft($bitsPerOctet); $r1 = $octet & 0x7f; $value = $l1->add($r1); if (0 === ($octet & 0x80)) { break; } } return (string)$value; } } vendor/fgrosse/phpasn1/lib/ASN1/Composite/AttributeTypeAndValue.php000064400000001626150736751610021253 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Composite; use FG\ASN1\ASNObject; use FG\ASN1\Universal\Sequence; use FG\ASN1\Universal\ObjectIdentifier; class AttributeTypeAndValue extends Sequence { /** * @param ObjectIdentifier|string $objIdentifier * @param \FG\ASN1\ASNObject $value */ public function __construct($objIdentifier, ASNObject $value) { if ($objIdentifier instanceof ObjectIdentifier == false) { $objIdentifier = new ObjectIdentifier($objIdentifier); } parent::__construct($objIdentifier, $value); } public function __toString() { return $this->children[0].': '.$this->children[1]; } } vendor/fgrosse/phpasn1/lib/ASN1/Composite/RDNString.php000064400000002010150736751610016624 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Composite; use FG\ASN1\Universal\PrintableString; use FG\ASN1\Universal\IA5String; use FG\ASN1\Universal\UTF8String; class RDNString extends RelativeDistinguishedName { /** * @param string|\FG\ASN1\Universal\ObjectIdentifier $objectIdentifierString * @param string|\FG\ASN1\ASNObject $value */ public function __construct($objectIdentifierString, $value) { if (PrintableString::isValid($value)) { $value = new PrintableString($value); } else { if (IA5String::isValid($value)) { $value = new IA5String($value); } else { $value = new UTF8String($value); } } parent::__construct($objectIdentifierString, $value); } } vendor/fgrosse/phpasn1/lib/ASN1/Composite/RelativeDistinguishedName.php000064400000003152150736751610022122 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Composite; use FG\ASN1\Exception\NotImplementedException; use FG\ASN1\ASNObject; use FG\ASN1\Universal\Set; class RelativeDistinguishedName extends Set { /** * @param string|\FG\ASN1\Universal\ObjectIdentifier $objIdentifierString * @param \FG\ASN1\ASNObject $value */ public function __construct($objIdentifierString, ASNObject $value) { // TODO: This does only support one element in the RelativeDistinguishedName Set but it it is defined as follows: // RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue parent::__construct(new AttributeTypeAndValue($objIdentifierString, $value)); } public function getContent() { /** @var \FG\ASN1\ASNObject $firstObject */ $firstObject = $this->children[0]; return $firstObject->__toString(); } /** * At the current version this code can not work since the implementation of Construct requires * the class to support a constructor without arguments. * * @deprecated this function is not yet implemented! Feel free to submit a pull request on github * @param string $binaryData * @param int $offsetIndex * @throws NotImplementedException */ public static function fromBinary(&$binaryData, &$offsetIndex = 0) { throw new NotImplementedException(); } } vendor/fgrosse/phpasn1/lib/ASN1/Construct.php000064400000010471150736751610015046 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1; use ArrayAccess; use ArrayIterator; use Countable; use FG\ASN1\Exception\ParserException; use Iterator; abstract class Construct extends ASNObject implements Countable, ArrayAccess, Iterator, Parsable { /** @var \FG\ASN1\ASNObject[] */ protected $children; private $iteratorPosition; /** * @param \FG\ASN1\ASNObject[] $children the variadic type hint is commented due to https://github.com/facebook/hhvm/issues/4858 */ public function __construct(/* HH_FIXME[4858]: variadic + strict */ ...$children) { $this->children = $children; $this->iteratorPosition = 0; } public function getContent() { return $this->children; } public function rewind() { $this->iteratorPosition = 0; } public function current() { return $this->children[$this->iteratorPosition]; } public function key() { return $this->iteratorPosition; } public function next() { $this->iteratorPosition++; } public function valid() { return isset($this->children[$this->iteratorPosition]); } public function offsetExists($offset) { return array_key_exists($offset, $this->children); } public function offsetGet($offset) { return $this->children[$offset]; } public function offsetSet($offset, $value) { if ($offset === null) { $offset = count($this->children); } $this->children[$offset] = $value; } public function offsetUnset($offset) { unset($this->children[$offset]); } protected function calculateContentLength() { $length = 0; foreach ($this->children as $component) { $length += $component->getObjectLength(); } return $length; } protected function getEncodedValue() { $result = ''; foreach ($this->children as $component) { $result .= $component->getBinary(); } return $result; } public function addChild(ASNObject $child) { $this->children[] = $child; } public function addChildren(array $children) { foreach ($children as $child) { $this->addChild($child); } } public function __toString() { $nrOfChildren = $this->getNumberOfChildren(); $childString = $nrOfChildren == 1 ? 'child' : 'children'; return "[{$nrOfChildren} {$childString}]"; } public function getNumberOfChildren() { return count($this->children); } /** * @return \FG\ASN1\ASNObject[] */ public function getChildren() { return $this->children; } /** * @return \FG\ASN1\ASNObject */ public function getFirstChild() { return $this->children[0]; } /** * @param string $binaryData * @param int $offsetIndex * * @throws Exception\ParserException * * @return Construct|static */ public static function fromBinary(&$binaryData, &$offsetIndex = 0) { $parsedObject = new static(); self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++); $contentLength = self::parseContentLength($binaryData, $offsetIndex); $startIndex = $offsetIndex; $children = []; $octetsToRead = $contentLength; while ($octetsToRead > 0) { $newChild = ASNObject::fromBinary($binaryData, $offsetIndex); $octetsToRead -= $newChild->getObjectLength(); $children[] = $newChild; } if ($octetsToRead !== 0) { throw new ParserException("Sequence length incorrect", $startIndex); } $parsedObject->addChildren($children); $parsedObject->setContentLength($contentLength); return $parsedObject; } public function count($mode = COUNT_NORMAL) { return count($this->children, $mode); } public function getIterator() { return new ArrayIterator($this->children); } } vendor/fgrosse/phpasn1/lib/ASN1/Exception/NotImplementedException.php000064400000000521150736751610021616 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Exception; class NotImplementedException extends \Exception { } vendor/fgrosse/phpasn1/lib/ASN1/Exception/ParserException.php000064400000001277150736751610020137 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Exception; class ParserException extends \Exception { private $errorMessage; private $offset; public function __construct($errorMessage, $offset) { $this->errorMessage = $errorMessage; $this->offset = $offset; parent::__construct("ASN.1 Parser Exception at offset {$this->offset}: {$this->errorMessage}"); } public function getOffset() { return $this->offset; } } vendor/fgrosse/phpasn1/lib/ASN1/ExplicitlyTaggedObject.php000064400000010325150736751610017451 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1; use FG\ASN1\Exception\ParserException; /** * Class ExplicitlyTaggedObject decorate an inner object with an additional tag that gives information about * its context specific meaning. * * Explanation taken from A Layman's Guide to a Subset of ASN.1, BER, and DER: * >>> An RSA Laboratories Technical Note * >>> Burton S. Kaliski Jr. * >>> Revised November 1, 1993 * * [...] * Explicitly tagged types are derived from other types by adding an outer tag to the underlying type. * In effect, explicitly tagged types are structured types consisting of one component, the underlying type. * Explicit tagging is denoted by the ASN.1 keywords [class number] EXPLICIT (see Section 5.2). * [...] * * @see http://luca.ntop.org/Teaching/Appunti/asn1.html */ class ExplicitlyTaggedObject extends ASNObject { /** @var \FG\ASN1\ASNObject[] */ private $decoratedObjects; private $tag; /** * @param int $tag * @param \FG\ASN1\ASNObject $objects,... */ public function __construct($tag, /* HH_FIXME[4858]: variadic + strict */ ...$objects) { $this->tag = $tag; $this->decoratedObjects = $objects; } protected function calculateContentLength() { $length = 0; foreach ($this->decoratedObjects as $object) { $length += $object->getObjectLength(); } return $length; } protected function getEncodedValue() { $encoded = ''; foreach ($this->decoratedObjects as $object) { $encoded .= $object->getBinary(); } return $encoded; } public function getContent() { return $this->decoratedObjects; } public function __toString() { switch ($length = count($this->decoratedObjects)) { case 0: return "Context specific empty object with tag [{$this->tag}]"; case 1: $decoratedType = Identifier::getShortName($this->decoratedObjects[0]->getType()); return "Context specific $decoratedType with tag [{$this->tag}]"; default: return "$length context specific objects with tag [{$this->tag}]"; } } public function getType() { return ord($this->getIdentifier()); } public function getIdentifier() { $identifier = Identifier::create(Identifier::CLASS_CONTEXT_SPECIFIC, true, $this->tag); return is_int($identifier) ? chr($identifier) : $identifier; } public function getTag() { return $this->tag; } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { $identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex); $firstIdentifierOctet = ord($identifier); assert(Identifier::isContextSpecificClass($firstIdentifierOctet), 'identifier octet should indicate context specific class'); assert(Identifier::isConstructed($firstIdentifierOctet), 'identifier octet should indicate constructed object'); $tag = Identifier::getTagNumber($identifier); $totalContentLength = self::parseContentLength($binaryData, $offsetIndex); $remainingContentLength = $totalContentLength; $offsetIndexOfDecoratedObject = $offsetIndex; $decoratedObjects = []; while ($remainingContentLength > 0) { $nextObject = ASNObject::fromBinary($binaryData, $offsetIndex); $remainingContentLength -= $nextObject->getObjectLength(); $decoratedObjects[] = $nextObject; } if ($remainingContentLength != 0) { throw new ParserException("Context-Specific explicitly tagged object [$tag] starting at offset $offsetIndexOfDecoratedObject specifies a length of $totalContentLength octets but $remainingContentLength remain after parsing the content", $offsetIndexOfDecoratedObject); } $parsedObject = new self($tag, ...$decoratedObjects); $parsedObject->setContentLength($totalContentLength); return $parsedObject; } } vendor/fgrosse/phpasn1/lib/ASN1/Identifier.php000064400000025106150736751610015145 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1; use Exception; /** * The Identifier encodes the ASN.1 tag (class and number) of the type of a data value. * * Every identifier whose number is in the range 0 to 30 has the following structure: * * Bits: 8 7 6 5 4 3 2 1 * | Class | P/C | Tag number | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Bits 8 and 7 define the class of this type ( Universal, Application, Context-specific or Private). * Bit 6 encoded whether this type is primitive or constructed * The remaining bits 5 - 1 encode the tag number */ class Identifier { const CLASS_UNIVERSAL = 0x00; const CLASS_APPLICATION = 0x01; const CLASS_CONTEXT_SPECIFIC = 0x02; const CLASS_PRIVATE = 0x03; const EOC = 0x00; // unsupported for now const BOOLEAN = 0x01; const INTEGER = 0x02; const BITSTRING = 0x03; const OCTETSTRING = 0x04; const NULL = 0x05; const OBJECT_IDENTIFIER = 0x06; const OBJECT_DESCRIPTOR = 0x07; const EXTERNAL = 0x08; // unsupported for now const REAL = 0x09; // unsupported for now const ENUMERATED = 0x0A; const EMBEDDED_PDV = 0x0B; // unsupported for now const UTF8_STRING = 0x0C; const RELATIVE_OID = 0x0D; // value 0x0E and 0x0F are reserved for future use const SEQUENCE = 0x30; const SET = 0x31; const NUMERIC_STRING = 0x12; const PRINTABLE_STRING = 0x13; const T61_STRING = 0x14; // sometimes referred to as TeletextString const VIDEOTEXT_STRING = 0x15; const IA5_STRING = 0x16; const UTC_TIME = 0x17; const GENERALIZED_TIME = 0x18; const GRAPHIC_STRING = 0x19; const VISIBLE_STRING = 0x1A; const GENERAL_STRING = 0x1B; const UNIVERSAL_STRING = 0x1C; const CHARACTER_STRING = 0x1D; // Unrestricted character type const BMP_STRING = 0x1E; const LONG_FORM = 0x1F; const IS_CONSTRUCTED = 0x20; /** * Creates an identifier. Short form identifiers are returned as integers * for BC, long form identifiers will be returned as a string of octets. * * @param int $class * @param bool $isConstructed * @param int $tagNumber * * @throws Exception if the given arguments are invalid * * @return int|string */ public static function create($class, $isConstructed, $tagNumber) { if (!is_numeric($class) || $class < self::CLASS_UNIVERSAL || $class > self::CLASS_PRIVATE) { throw new Exception(sprintf('Invalid class %d given', $class)); } if (!is_bool($isConstructed)) { throw new Exception("\$isConstructed must be a boolean value ($isConstructed given)"); } $tagNumber = self::makeNumeric($tagNumber); if ($tagNumber < 0) { throw new Exception(sprintf('Invalid $tagNumber %d given. You can only use positive integers.', $tagNumber)); } if ($tagNumber < self::LONG_FORM) { return ($class << 6) | ($isConstructed << 5) | $tagNumber; } $firstOctet = ($class << 6) | ($isConstructed << 5) | self::LONG_FORM; // Tag numbers formatted in long form are base-128 encoded. See X.609#8.1.2.4 return chr($firstOctet).Base128::encode($tagNumber); } public static function isConstructed($identifierOctet) { return ($identifierOctet & self::IS_CONSTRUCTED) === self::IS_CONSTRUCTED; } public static function isLongForm($identifierOctet) { return ($identifierOctet & self::LONG_FORM) === self::LONG_FORM; } /** * Return the name of the mapped ASN.1 type with a preceding "ASN.1 ". * * Example: ASN.1 Octet String * * @see Identifier::getShortName() * * @param int|string $identifier * * @return string */ public static function getName($identifier) { $identifierOctet = self::makeNumeric($identifier); $typeName = static::getShortName($identifier); if (($identifierOctet & self::LONG_FORM) < self::LONG_FORM) { $typeName = "ASN.1 {$typeName}"; } return $typeName; } /** * Return the short version of the type name. * * If the given identifier octet can be mapped to a known universal type this will * return its name. Else Identifier::getClassDescription() is used to retrieve * information about the identifier. * * @see Identifier::getName() * @see Identifier::getClassDescription() * * @param int|string $identifier * * @return string */ public static function getShortName($identifier) { $identifierOctet = self::makeNumeric($identifier); switch ($identifierOctet) { case self::EOC: return 'End-of-contents octet'; case self::BOOLEAN: return 'Boolean'; case self::INTEGER: return 'Integer'; case self::BITSTRING: return 'Bit String'; case self::OCTETSTRING: return 'Octet String'; case self::NULL: return 'NULL'; case self::OBJECT_IDENTIFIER: return 'Object Identifier'; case self::OBJECT_DESCRIPTOR: return 'Object Descriptor'; case self::EXTERNAL: return 'External Type'; case self::REAL: return 'Real'; case self::ENUMERATED: return 'Enumerated'; case self::EMBEDDED_PDV: return 'Embedded PDV'; case self::UTF8_STRING: return 'UTF8 String'; case self::RELATIVE_OID: return 'Relative OID'; case self::SEQUENCE: return 'Sequence'; case self::SET: return 'Set'; case self::NUMERIC_STRING: return 'Numeric String'; case self::PRINTABLE_STRING: return 'Printable String'; case self::T61_STRING: return 'T61 String'; case self::VIDEOTEXT_STRING: return 'Videotext String'; case self::IA5_STRING: return 'IA5 String'; case self::UTC_TIME: return 'UTC Time'; case self::GENERALIZED_TIME: return 'Generalized Time'; case self::GRAPHIC_STRING: return 'Graphic String'; case self::VISIBLE_STRING: return 'Visible String'; case self::GENERAL_STRING: return 'General String'; case self::UNIVERSAL_STRING: return 'Universal String'; case self::CHARACTER_STRING: return 'Character String'; case self::BMP_STRING: return 'BMP String'; case 0x0E: return 'RESERVED (0x0E)'; case 0x0F: return 'RESERVED (0x0F)'; case self::LONG_FORM: default: $classDescription = self::getClassDescription($identifier); if (is_int($identifier)) { $identifier = chr($identifier); } return "$classDescription (0x".strtoupper(bin2hex($identifier)).')'; } } /** * Returns a textual description of the information encoded in a given identifier octet. * * The first three (most significant) bytes are evaluated to determine if this is a * constructed or primitive type and if it is either universal, application, context-specific or * private. * * Example: * Constructed context-specific * Primitive universal * * @param int|string $identifier * * @return string */ public static function getClassDescription($identifier) { $identifierOctet = self::makeNumeric($identifier); if (self::isConstructed($identifierOctet)) { $classDescription = 'Constructed '; } else { $classDescription = 'Primitive '; } $classBits = $identifierOctet >> 6; switch ($classBits) { case self::CLASS_UNIVERSAL: $classDescription .= 'universal'; break; case self::CLASS_APPLICATION: $classDescription .= 'application'; break; case self::CLASS_CONTEXT_SPECIFIC: $tagNumber = self::getTagNumber($identifier); $classDescription = "[$tagNumber] Context-specific"; break; case self::CLASS_PRIVATE: $classDescription .= 'private'; break; default: return "INVALID IDENTIFIER OCTET: {$identifierOctet}"; } return $classDescription; } /** * @param int|string $identifier * * @return int */ public static function getTagNumber($identifier) { $firstOctet = self::makeNumeric($identifier); $tagNumber = $firstOctet & self::LONG_FORM; if ($tagNumber < self::LONG_FORM) { return $tagNumber; } if (is_numeric($identifier)) { $identifier = chr($identifier); } return Base128::decode(substr($identifier, 1)); } public static function isUniversalClass($identifier) { $identifier = self::makeNumeric($identifier); return $identifier >> 6 == self::CLASS_UNIVERSAL; } public static function isApplicationClass($identifier) { $identifier = self::makeNumeric($identifier); return $identifier >> 6 == self::CLASS_APPLICATION; } public static function isContextSpecificClass($identifier) { $identifier = self::makeNumeric($identifier); return $identifier >> 6 == self::CLASS_CONTEXT_SPECIFIC; } public static function isPrivateClass($identifier) { $identifier = self::makeNumeric($identifier); return $identifier >> 6 == self::CLASS_PRIVATE; } private static function makeNumeric($identifierOctet) { if (!is_numeric($identifierOctet)) { return ord($identifierOctet); } else { return $identifierOctet; } } } vendor/fgrosse/phpasn1/lib/ASN1/OID.php000064400000020156150736751610013476 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1; class OID { const RSA_ENCRYPTION = '1.2.840.113549.1.1.1'; const MD5_WITH_RSA_ENCRYPTION = '1.2.840.113549.1.1.4'; const SHA1_WITH_RSA_SIGNATURE = '1.2.840.113549.1.1.5'; const SHA256_WITH_RSA_SIGNATURE = '1.2.840.113549.1.1.11'; const PKCS9_EMAIL = '1.2.840.113549.1.9.1'; const PKCS9_UNSTRUCTURED_NAME = '1.2.840.113549.1.9.2'; const PKCS9_CONTENT_TYPE = '1.2.840.113549.1.9.3'; const PKCS9_MESSAGE_DIGEST = '1.2.840.113549.1.9.4'; const PKCS9_SIGNING_TIME = '1.2.840.113549.1.9.5'; const PKCS9_EXTENSION_REQUEST = '1.2.840.113549.1.9.14'; // certificate extension identifier const CERT_EXT_SUBJECT_DIRECTORY_ATTR = '2.5.29.9'; const CERT_EXT_SUBJECT_KEY_IDENTIFIER = '2.5.29.14'; const CERT_EXT_KEY_USAGE = '2.5.29.15'; const CERT_EXT_PRIVATE_KEY_USAGE_PERIOD = '2.5.29.16'; const CERT_EXT_SUBJECT_ALT_NAME = '2.5.29.17'; const CERT_EXT_ISSUER_ALT_NAME = '2.5.29.18'; const CERT_EXT_BASIC_CONSTRAINTS = '2.5.29.19'; const CERT_EXT_CRL_NUMBER = '2.5.29.20'; const CERT_EXT_REASON_CODE = '2.5.29.21'; const CERT_EXT_INVALIDITY_DATE = '2.5.29.24'; const CERT_EXT_DELTA_CRL_INDICATOR = '2.5.29.27'; const CERT_EXT_ISSUING_DIST_POINT = '2.5.29.28'; const CERT_EXT_CERT_ISSUER = '2.5.29.29'; const CERT_EXT_NAME_CONSTRAINTS = '2.5.29.30'; const CERT_EXT_CRL_DISTRIBUTION_POINTS = '2.5.29.31'; const CERT_EXT_CERT_POLICIES = '2.5.29.32'; const CERT_EXT_AUTHORITY_KEY_IDENTIFIER = '2.5.29.35'; const CERT_EXT_EXTENDED_KEY_USAGE = '2.5.29.37'; // standard certificate files const COMMON_NAME = '2.5.4.3'; const SURNAME = '2.5.4.4'; const SERIAL_NUMBER = '2.5.4.5'; const COUNTRY_NAME = '2.5.4.6'; const LOCALITY_NAME = '2.5.4.7'; const STATE_OR_PROVINCE_NAME = '2.5.4.8'; const STREET_ADDRESS = '2.5.4.9'; const ORGANIZATION_NAME = '2.5.4.10'; const OU_NAME = '2.5.4.11'; const TITLE = '2.5.4.12'; const DESCRIPTION = '2.5.4.13'; const POSTAL_ADDRESS = '2.5.4.16'; const POSTAL_CODE = '2.5.4.17'; const AUTHORITY_REVOCATION_LIST = '2.5.4.38'; const AUTHORITY_INFORMATION_ACCESS = '1.3.6.1.5.5.7.1.1'; /** * Returns the name of the given object identifier. * * Some OIDs are saved as class constants in this class. * If the wanted oidString is not among them, this method will * query http://oid-info.com for the right name. * This behavior can be suppressed by setting the second method parameter to false. * * @param string $oidString * @param bool $loadFromWeb * * @see self::loadFromWeb($oidString) * * @return string */ public static function getName($oidString, $loadFromWeb = true) { switch ($oidString) { case self::RSA_ENCRYPTION: return 'RSA Encryption'; case self::MD5_WITH_RSA_ENCRYPTION: return 'MD5 with RSA Encryption'; case self::SHA1_WITH_RSA_SIGNATURE: return 'SHA-1 with RSA Signature'; case self::PKCS9_EMAIL: return 'PKCS #9 Email Address'; case self::PKCS9_UNSTRUCTURED_NAME: return 'PKCS #9 Unstructured Name'; case self::PKCS9_CONTENT_TYPE: return 'PKCS #9 Content Type'; case self::PKCS9_MESSAGE_DIGEST: return 'PKCS #9 Message Digest'; case self::PKCS9_SIGNING_TIME: return 'PKCS #9 Signing Time'; case self::COMMON_NAME: return 'Common Name'; case self::SURNAME: return 'Surname'; case self::SERIAL_NUMBER: return 'Serial Number'; case self::COUNTRY_NAME: return 'Country Name'; case self::LOCALITY_NAME: return 'Locality Name'; case self::STATE_OR_PROVINCE_NAME: return 'State or Province Name'; case self::STREET_ADDRESS: return 'Street Address'; case self::ORGANIZATION_NAME: return 'Organization Name'; case self::OU_NAME: return 'Organization Unit Name'; case self::TITLE: return 'Title'; case self::DESCRIPTION: return 'Description'; case self::POSTAL_ADDRESS: return 'Postal Address'; case self::POSTAL_CODE: return 'Postal Code'; case self::AUTHORITY_REVOCATION_LIST: return 'Authority Revocation List'; case self::CERT_EXT_SUBJECT_DIRECTORY_ATTR: return 'Subject directory attributes'; case self::CERT_EXT_SUBJECT_KEY_IDENTIFIER: return 'Subject key identifier'; case self::CERT_EXT_KEY_USAGE: return 'Key usage certificate extension'; case self::CERT_EXT_PRIVATE_KEY_USAGE_PERIOD: return 'Private key usage'; case self::CERT_EXT_SUBJECT_ALT_NAME: return 'Subject alternative name (SAN)'; case self::CERT_EXT_ISSUER_ALT_NAME: return 'Issuer alternative name'; case self::CERT_EXT_BASIC_CONSTRAINTS: return 'Basic constraints'; case self::CERT_EXT_CRL_NUMBER: return 'CRL number'; case self::CERT_EXT_REASON_CODE: return 'Reason code'; case self::CERT_EXT_INVALIDITY_DATE: return 'Invalidity code'; case self::CERT_EXT_DELTA_CRL_INDICATOR: return 'Delta CRL indicator'; case self::CERT_EXT_ISSUING_DIST_POINT: return 'Issuing distribution point'; case self::CERT_EXT_CERT_ISSUER: return 'Certificate issuer'; case self::CERT_EXT_NAME_CONSTRAINTS: return 'Name constraints'; case self::CERT_EXT_CRL_DISTRIBUTION_POINTS: return 'CRL distribution points'; case self::CERT_EXT_CERT_POLICIES: return 'Certificate policies '; case self::CERT_EXT_AUTHORITY_KEY_IDENTIFIER: return 'Authority key identifier'; case self::CERT_EXT_EXTENDED_KEY_USAGE: return 'Extended key usage'; case self::AUTHORITY_INFORMATION_ACCESS: return 'Certificate Authority Information Access (AIA)'; default: if ($loadFromWeb) { return self::loadFromWeb($oidString); } else { return $oidString; } } } public static function loadFromWeb($oidString) { $ch = curl_init("http://oid-info.com/get/{$oidString}"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HEADER, 0); $contents = curl_exec($ch); curl_close($ch); // This pattern needs to be updated as soon as the website layout of oid-info.com changes preg_match_all('#(.+)\(\d+\)#si', $contents, $oidName); if (empty($oidName[1])) { return "{$oidString} (unknown)"; } $oidName = ucfirst(strtolower(preg_replace('/([A-Z][a-z])/', ' $1', $oidName[1][0]))); $oidName = str_replace('-', ' ', $oidName); return "{$oidName} ({$oidString})"; } } vendor/fgrosse/phpasn1/lib/ASN1/Parsable.php000064400000001771150736751610014616 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1; use FG\ASN1\Exception\ParserException; /** * The Parsable interface describes classes that can be parsed from their binary DER representation. */ interface Parsable { /** * Parse an instance of this class from its binary DER encoded representation. * * @param string $binaryData * @param int $offsetIndex the offset at which parsing of the $binaryData is started. This parameter ill be modified * to contain the offset index of the next object after this object has been parsed * * @throws ParserException if the given binary data is either invalid or not currently supported * * @return static */ public static function fromBinary(&$binaryData, &$offsetIndex = null); } vendor/fgrosse/phpasn1/lib/ASN1/TemplateParser.php000064400000003577150736751610016023 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1; use Exception; use FG\ASN1\Exception\ParserException; use FG\ASN1\Universal\Sequence; class TemplateParser { /** * @param string $data * @param array $template * @return \FG\ASN1\ASNObject|Sequence * @throws ParserException if there was an issue parsing */ public function parseBase64($data, array $template) { // TODO test with invalid data return $this->parseBinary(base64_decode($data), $template); } /** * @param string $binary * @param array $template * @return \FG\ASN1\ASNObject|Sequence * @throws ParserException if there was an issue parsing */ public function parseBinary($binary, array $template) { $parsedObject = ASNObject::fromBinary($binary); foreach ($template as $key => $value) { $this->validate($parsedObject, $key, $value); } return $parsedObject; } private function validate(ASNObject $object, $key, $value) { if (is_array($value)) { $this->assertTypeId($key, $object); /* @var Construct $object */ foreach ($value as $key => $child) { $this->validate($object->current(), $key, $child); $object->next(); } } else { $this->assertTypeId($value, $object); } } private function assertTypeId($expectedTypeId, ASNObject $object) { $actualType = $object->getType(); if ($expectedTypeId != $actualType) { throw new Exception("Expected type ($expectedTypeId) does not match actual type ($actualType"); } } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/BMPString.php000064400000002071150736751610016634 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\AbstractString; use FG\ASN1\Identifier; class BMPString extends AbstractString { /** * Creates a new ASN.1 BMP String. * * BMPString is a subtype of UniversalString that has its own * unique tag and contains only the characters in the * Basic Multilingual Plane (those corresponding to the first * 64K-2 cells, less cells whose encoding is used to address * characters outside the Basic Multilingual Plane) of ISO/IEC 10646-1. * * TODO The encodable characters of this type are not yet checked. * * @param string $string */ public function __construct($string) { $this->value = $string; $this->allowAll(); } public function getType() { return Identifier::BMP_STRING; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/BitString.php000064400000005465150736751610016746 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use Exception; use FG\ASN1\Exception\ParserException; use FG\ASN1\Parsable; use FG\ASN1\Identifier; class BitString extends OctetString implements Parsable { private $nrOfUnusedBits; /** * Creates a new ASN.1 BitString object. * * @param string|int $value Either the hexadecimal value as a string (spaces are allowed - leading 0x is optional) or a numeric value * @param int $nrOfUnusedBits the number of unused bits in the last octet [optional]. * * @throws Exception if the second parameter is no positive numeric value */ public function __construct($value, $nrOfUnusedBits = 0) { parent::__construct($value); if (!is_numeric($nrOfUnusedBits) || $nrOfUnusedBits < 0) { throw new Exception('BitString: second parameter needs to be a positive number (or zero)!'); } $this->nrOfUnusedBits = $nrOfUnusedBits; } public function getType() { return Identifier::BITSTRING; } protected function calculateContentLength() { // add one to the length for the first octet which encodes the number of unused bits in the last octet return parent::calculateContentLength() + 1; } protected function getEncodedValue() { // the first octet determines the number of unused bits $nrOfUnusedBitsOctet = chr($this->nrOfUnusedBits); $actualContent = parent::getEncodedValue(); return $nrOfUnusedBitsOctet.$actualContent; } public function getNumberOfUnusedBits() { return $this->nrOfUnusedBits; } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { self::parseIdentifier($binaryData[$offsetIndex], Identifier::BITSTRING, $offsetIndex++); $contentLength = self::parseContentLength($binaryData, $offsetIndex, 2); $nrOfUnusedBits = ord($binaryData[$offsetIndex]); $value = substr($binaryData, $offsetIndex + 1, $contentLength - 1); if ($nrOfUnusedBits > 7 || // no less than 1 used, otherwise non-minimal ($contentLength - 1) == 1 && $nrOfUnusedBits > 0 || // content length only 1, no (ord($value[strlen($value)-1])&((1<<$nrOfUnusedBits)-1)) != 0 // unused bits set ) { throw new ParserException("Can not parse bit string with invalid padding", $offsetIndex); } $offsetIndex += $contentLength; $parsedObject = new self(bin2hex($value), $nrOfUnusedBits); $parsedObject->setContentLength($contentLength); return $parsedObject; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/Boolean.php000064400000003403150736751610016406 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\ASNObject; use FG\ASN1\Parsable; use FG\ASN1\Identifier; use FG\ASN1\Exception\ParserException; class Boolean extends ASNObject implements Parsable { private $value; /** * @param bool $value */ public function __construct($value) { $this->value = $value; } public function getType() { return Identifier::BOOLEAN; } protected function calculateContentLength() { return 1; } protected function getEncodedValue() { if ($this->value == false) { return chr(0x00); } else { return chr(0xFF); } } public function getContent() { if ($this->value == true) { return 'TRUE'; } else { return 'FALSE'; } } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { self::parseIdentifier($binaryData[$offsetIndex], Identifier::BOOLEAN, $offsetIndex++); $contentLength = self::parseContentLength($binaryData, $offsetIndex); if ($contentLength != 1) { throw new ParserException("An ASN.1 Boolean should not have a length other than one. Extracted length was {$contentLength}", $offsetIndex); } $value = ord($binaryData[$offsetIndex++]); $booleanValue = $value == 0xFF ? true : false; $parsedObject = new self($booleanValue); $parsedObject->setContentLength($contentLength); return $parsedObject; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/CharacterString.php000064400000001112150736751610020105 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\AbstractString; use FG\ASN1\Identifier; class CharacterString extends AbstractString { public function __construct($string) { $this->value = $string; $this->allowAll(); } public function getType() { return Identifier::CHARACTER_STRING; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/Enumerated.php000064400000000653150736751610017124 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\Identifier; class Enumerated extends Integer { public function getType() { return Identifier::ENUMERATED; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/GeneralString.php000064400000001353150736751610017575 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\AbstractString; use FG\ASN1\Identifier; class GeneralString extends AbstractString { /** * Creates a new ASN.1 GeneralString. * TODO The encodable characters of this type are not yet checked. * * @param string $string */ public function __construct($string) { $this->value = $string; $this->allowAll(); } public function getType() { return Identifier::GENERAL_STRING; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/GeneralizedTime.php000064400000011422150736751610020077 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\AbstractTime; use FG\ASN1\Parsable; use FG\ASN1\Identifier; use FG\ASN1\Exception\ParserException; /** * This ASN.1 universal type contains date and time information according to ISO 8601. * * The type consists of values representing: * a) a calendar date, as defined in ISO 8601; and * b) a time of day, to any of the precisions defined in ISO 8601, except for the hours value 24 which shall not be used; and * c) the local time differential factor as defined in ISO 8601. * * Decoding of this type will accept the Basic Encoding Rules (BER) * The encoding will comply with the Distinguished Encoding Rules (DER). */ class GeneralizedTime extends AbstractTime implements Parsable { private $microseconds; public function __construct($dateTime = null, $dateTimeZone = 'UTC') { parent::__construct($dateTime, $dateTimeZone); $this->microseconds = $this->value->format('u'); if ($this->containsFractionalSecondsElement()) { // DER requires us to remove trailing zeros $this->microseconds = preg_replace('/([1-9]+)0+$/', '$1', $this->microseconds); } } public function getType() { return Identifier::GENERALIZED_TIME; } protected function calculateContentLength() { $contentSize = 15; // YYYYMMDDHHmmSSZ if ($this->containsFractionalSecondsElement()) { $contentSize += 1 + strlen($this->microseconds); } return $contentSize; } public function containsFractionalSecondsElement() { return intval($this->microseconds) > 0; } protected function getEncodedValue() { $encodedContent = $this->value->format('YmdHis'); if ($this->containsFractionalSecondsElement()) { $encodedContent .= ".{$this->microseconds}"; } return $encodedContent.'Z'; } public function __toString() { if ($this->containsFractionalSecondsElement()) { return $this->value->format("Y-m-d\tH:i:s.uP"); } else { return $this->value->format("Y-m-d\tH:i:sP"); } } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { self::parseIdentifier($binaryData[$offsetIndex], Identifier::GENERALIZED_TIME, $offsetIndex++); $lengthOfMinimumTimeString = 14; // YYYYMMDDHHmmSS $contentLength = self::parseContentLength($binaryData, $offsetIndex, $lengthOfMinimumTimeString); $maximumBytesToRead = $contentLength; $format = 'YmdGis'; $content = substr($binaryData, $offsetIndex, $contentLength); $dateTimeString = substr($content, 0, $lengthOfMinimumTimeString); $offsetIndex += $lengthOfMinimumTimeString; $maximumBytesToRead -= $lengthOfMinimumTimeString; if ($contentLength == $lengthOfMinimumTimeString) { $localTimeZone = new \DateTimeZone(date_default_timezone_get()); $dateTime = \DateTime::createFromFormat($format, $dateTimeString, $localTimeZone); } else { if ($binaryData[$offsetIndex] == '.') { $maximumBytesToRead--; // account for the '.' $nrOfFractionalSecondElements = 1; // account for the '.' while ($maximumBytesToRead > 0 && $binaryData[$offsetIndex + $nrOfFractionalSecondElements] != '+' && $binaryData[$offsetIndex + $nrOfFractionalSecondElements] != '-' && $binaryData[$offsetIndex + $nrOfFractionalSecondElements] != 'Z') { $nrOfFractionalSecondElements++; $maximumBytesToRead--; } $dateTimeString .= substr($binaryData, $offsetIndex, $nrOfFractionalSecondElements); $offsetIndex += $nrOfFractionalSecondElements; $format .= '.u'; } $dateTime = \DateTime::createFromFormat($format, $dateTimeString, new \DateTimeZone('UTC')); if ($maximumBytesToRead > 0) { if ($binaryData[$offsetIndex] == '+' || $binaryData[$offsetIndex] == '-') { $dateTime = static::extractTimeZoneData($binaryData, $offsetIndex, $dateTime); } elseif ($binaryData[$offsetIndex++] != 'Z') { throw new ParserException('Invalid ISO 8601 Time String', $offsetIndex); } } } $parsedObject = new self($dateTime); $parsedObject->setContentLength($contentLength); return $parsedObject; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/GraphicString.php000064400000001354150736751610017576 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\AbstractString; use FG\ASN1\Identifier; class GraphicString extends AbstractString { /** * Creates a new ASN.1 Graphic String. * TODO The encodable characters of this type are not yet checked. * * @param string $string */ public function __construct($string) { $this->value = $string; $this->allowAll(); } public function getType() { return Identifier::GRAPHIC_STRING; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/IA5String.php000064400000001437150736751610016601 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\AbstractString; use FG\ASN1\Identifier; /** * The International Alphabet No.5 (IA5) references the encoding of the ASCII characters. * * Each character in the data is encoded as 1 byte. */ class IA5String extends AbstractString { public function __construct($string) { parent::__construct($string); for ($i = 1; $i < 128; $i++) { $this->allowCharacter(chr($i)); } } public function getType() { return Identifier::IA5_STRING; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/Integer.php000064400000007446150736751610016437 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use Exception; use FG\Utility\BigInteger; use FG\ASN1\Exception\ParserException; use FG\ASN1\ASNObject; use FG\ASN1\Parsable; use FG\ASN1\Identifier; class Integer extends ASNObject implements Parsable { /** @var int */ private $value; /** * @param int $value * * @throws Exception if the value is not numeric */ public function __construct($value) { if (is_numeric($value) == false) { throw new Exception("Invalid VALUE [{$value}] for ASN1_INTEGER"); } $this->value = $value; } public function getType() { return Identifier::INTEGER; } public function getContent() { return $this->value; } protected function calculateContentLength() { return strlen($this->getEncodedValue()); } protected function getEncodedValue() { $value = BigInteger::create($this->value, 10); $negative = $value->compare(0) < 0; if ($negative) { $value = $value->absoluteValue(); $limit = 0x80; } else { $limit = 0x7f; } $mod = 0xff+1; $values = []; while($value->compare($limit) > 0) { $values[] = $value->modulus($mod)->toInteger(); $value = $value->shiftRight(8); } $values[] = $value->modulus($mod)->toInteger(); $numValues = count($values); if ($negative) { for ($i = 0; $i < $numValues; $i++) { $values[$i] = 0xff - $values[$i]; } for ($i = 0; $i < $numValues; $i++) { $values[$i] += 1; if ($values[$i] <= 0xff) { break; } assert($i != $numValues - 1); $values[$i] = 0; } if ($values[$numValues - 1] == 0x7f) { $values[] = 0xff; } } $values = array_reverse($values); $r = pack("C*", ...$values); return $r; } private static function ensureMinimalEncoding($binaryData, $offsetIndex) { // All the first nine bits cannot equal 0 or 1, which would // be non-minimal encoding for positive and negative integers respectively if ((ord($binaryData[$offsetIndex]) == 0x00 && (ord($binaryData[$offsetIndex+1]) & 0x80) == 0) || (ord($binaryData[$offsetIndex]) == 0xff && (ord($binaryData[$offsetIndex+1]) & 0x80) == 0x80)) { throw new ParserException("Integer not minimally encoded", $offsetIndex); } } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { $parsedObject = new static(0); self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++); $contentLength = self::parseContentLength($binaryData, $offsetIndex, 1); if ($contentLength > 1) { self::ensureMinimalEncoding($binaryData, $offsetIndex); } $isNegative = (ord($binaryData[$offsetIndex]) & 0x80) != 0x00; $number = BigInteger::create(ord($binaryData[$offsetIndex++]) & 0x7F); for ($i = 0; $i < $contentLength - 1; $i++) { $number = $number->multiply(0x100)->add(ord($binaryData[$offsetIndex++])); } if ($isNegative) { $number = $number->subtract(BigInteger::create(2)->toPower(8 * $contentLength - 1)); } $parsedObject = new static((string)$number); $parsedObject->setContentLength($contentLength); return $parsedObject; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/NullObject.php000064400000002440150736751610017070 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\ASNObject; use FG\ASN1\Parsable; use FG\ASN1\Identifier; use FG\ASN1\Exception\ParserException; class NullObject extends ASNObject implements Parsable { public function getType() { return Identifier::NULL; } protected function calculateContentLength() { return 0; } protected function getEncodedValue() { return null; } public function getContent() { return 'NULL'; } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { self::parseIdentifier($binaryData[$offsetIndex], Identifier::NULL, $offsetIndex++); $contentLength = self::parseContentLength($binaryData, $offsetIndex); if ($contentLength != 0) { throw new ParserException("An ASN.1 Null should not have a length other than zero. Extracted length was {$contentLength}", $offsetIndex); } $parsedObject = new self(); $parsedObject->setContentLength(0); return $parsedObject; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/NumericString.php000064400000001511150736751610017616 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\AbstractString; use FG\ASN1\Identifier; class NumericString extends AbstractString { /** * Creates a new ASN.1 NumericString. * * The following characters are permitted: * Digits 0,1, ... 9 * SPACE (space) * * @param string $string */ public function __construct($string) { $this->value = $string; $this->allowNumbers(); $this->allowSpaces(); } public function getType() { return Identifier::NUMERIC_STRING; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/ObjectDescriptor.php000064400000001060150736751610020271 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\Identifier; class ObjectDescriptor extends GraphicString { public function __construct($objectDescription) { parent::__construct($objectDescription); } public function getType() { return Identifier::OBJECT_DESCRIPTOR; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/ObjectIdentifier.php000064400000007477150736751610020257 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use Exception; use FG\ASN1\Base128; use FG\ASN1\OID; use FG\ASN1\ASNObject; use FG\ASN1\Parsable; use FG\ASN1\Identifier; use FG\ASN1\Exception\ParserException; class ObjectIdentifier extends ASNObject implements Parsable { protected $subIdentifiers; protected $value; public function __construct($value) { $this->subIdentifiers = explode('.', $value); $nrOfSubIdentifiers = count($this->subIdentifiers); for ($i = 0; $i < $nrOfSubIdentifiers; $i++) { if (is_numeric($this->subIdentifiers[$i])) { // enforce the integer type $this->subIdentifiers[$i] = intval($this->subIdentifiers[$i]); } else { throw new Exception("[{$value}] is no valid object identifier (sub identifier ".($i + 1).' is not numeric)!'); } } // Merge the first to arcs of the OID registration tree (per ASN definition!) if ($nrOfSubIdentifiers >= 2) { $this->subIdentifiers[1] = ($this->subIdentifiers[0] * 40) + $this->subIdentifiers[1]; unset($this->subIdentifiers[0]); } $this->value = $value; } public function getContent() { return $this->value; } public function getType() { return Identifier::OBJECT_IDENTIFIER; } protected function calculateContentLength() { $length = 0; foreach ($this->subIdentifiers as $subIdentifier) { do { $subIdentifier = $subIdentifier >> 7; $length++; } while ($subIdentifier > 0); } return $length; } protected function getEncodedValue() { $encodedValue = ''; foreach ($this->subIdentifiers as $subIdentifier) { $encodedValue .= Base128::encode($subIdentifier); } return $encodedValue; } public function __toString() { return OID::getName($this->value); } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { self::parseIdentifier($binaryData[$offsetIndex], Identifier::OBJECT_IDENTIFIER, $offsetIndex++); $contentLength = self::parseContentLength($binaryData, $offsetIndex, 1); $firstOctet = ord($binaryData[$offsetIndex++]); $oidString = floor($firstOctet / 40).'.'.($firstOctet % 40); $oidString .= '.'.self::parseOid($binaryData, $offsetIndex, $contentLength - 1); $parsedObject = new self($oidString); $parsedObject->setContentLength($contentLength); return $parsedObject; } /** * Parses an object identifier except for the first octet, which is parsed * differently. This way relative object identifiers can also be parsed * using this. * * @param $binaryData * @param $offsetIndex * @param $octetsToRead * * @throws ParserException * * @return string */ protected static function parseOid(&$binaryData, &$offsetIndex, $octetsToRead) { $oid = ''; while ($octetsToRead > 0) { $octets = ''; do { if (0 === $octetsToRead) { throw new ParserException('Malformed ASN.1 Object Identifier', $offsetIndex - 1); } $octetsToRead--; $octet = $binaryData[$offsetIndex++]; $octets .= $octet; } while (ord($octet) & 0x80); $oid .= sprintf('%d.', Base128::decode($octets)); } // Remove trailing '.' return substr($oid, 0, -1) ?: ''; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/OctetString.php000064400000004411150736751610017274 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use Exception; use FG\ASN1\ASNObject; use FG\ASN1\Parsable; use FG\ASN1\Identifier; class OctetString extends ASNObject implements Parsable { protected $value; public function __construct($value) { if (is_string($value)) { // remove gaps between hex digits $value = preg_replace('/\s|0x/', '', $value); } elseif (is_numeric($value)) { $value = dechex($value); } elseif ($value === null) { return; } else { throw new Exception('OctetString: unrecognized input type!'); } if (strlen($value) % 2 != 0) { // transform values like 1F2 to 01F2 $value = '0'.$value; } $this->value = $value; } public function getType() { return Identifier::OCTETSTRING; } protected function calculateContentLength() { return strlen($this->value) / 2; } protected function getEncodedValue() { $value = $this->value; $result = ''; //Actual content while (strlen($value) >= 2) { // get the hex value byte by byte from the string and and add it to binary result $result .= chr(hexdec(substr($value, 0, 2))); $value = substr($value, 2); } return $result; } public function getContent() { return strtoupper($this->value); } public function getBinaryContent() { return $this->getEncodedValue(); } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { self::parseIdentifier($binaryData[$offsetIndex], Identifier::OCTETSTRING, $offsetIndex++); $contentLength = self::parseContentLength($binaryData, $offsetIndex); $value = substr($binaryData, $offsetIndex, $contentLength); $offsetIndex += $contentLength; $parsedObject = new self(bin2hex($value)); $parsedObject->setContentLength($contentLength); return $parsedObject; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/PrintableString.php000064400000002577150736751610020151 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\AbstractString; use FG\ASN1\Identifier; class PrintableString extends AbstractString { /** * Creates a new ASN.1 PrintableString. * * The ITU-T X.680 Table 8 permits the following characters: * Latin capital letters A,B, ... Z * Latin small letters a,b, ... z * Digits 0,1, ... 9 * SPACE (space) * APOSTROPHE ' * LEFT PARENTHESIS ( * RIGHT PARENTHESIS ) * PLUS SIGN + * COMMA , * HYPHEN-MINUS - * FULL STOP . * SOLIDUS / * COLON : * EQUALS SIGN = * QUESTION MARK ? * * @param string $string */ public function __construct($string) { $this->value = $string; $this->allowNumbers(); $this->allowAllLetters(); $this->allowSpaces(); $this->allowCharacters("'", '(', ')', '+', '-', '.', ',', '/', ':', '=', '?'); } public function getType() { return Identifier::PRINTABLE_STRING; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/RelativeObjectIdentifier.php000064400000003460150736751610021737 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use Exception; use FG\ASN1\Parsable; use FG\ASN1\Identifier; use FG\ASN1\Exception\ParserException; class RelativeObjectIdentifier extends ObjectIdentifier implements Parsable { public function __construct($subIdentifiers) { $this->value = $subIdentifiers; $this->subIdentifiers = explode('.', $subIdentifiers); $nrOfSubIdentifiers = count($this->subIdentifiers); for ($i = 0; $i < $nrOfSubIdentifiers; $i++) { if (is_numeric($this->subIdentifiers[$i])) { // enforce the integer type $this->subIdentifiers[$i] = intval($this->subIdentifiers[$i]); } else { throw new Exception("[{$subIdentifiers}] is no valid object identifier (sub identifier ".($i + 1).' is not numeric)!'); } } } public function getType() { return Identifier::RELATIVE_OID; } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { self::parseIdentifier($binaryData[$offsetIndex], Identifier::RELATIVE_OID, $offsetIndex++); $contentLength = self::parseContentLength($binaryData, $offsetIndex, 1); try { $oidString = self::parseOid($binaryData, $offsetIndex, $contentLength); } catch (ParserException $e) { throw new ParserException('Malformed ASN.1 Relative Object Identifier', $e->getOffset()); } $parsedObject = new self($oidString); $parsedObject->setContentLength($contentLength); return $parsedObject; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/Sequence.php000064400000000752150736751610016603 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\Construct; use FG\ASN1\Parsable; use FG\ASN1\Identifier; class Sequence extends Construct implements Parsable { public function getType() { return Identifier::SEQUENCE; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/Set.php000064400000000636150736751610015567 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\Identifier; class Set extends Sequence { public function getType() { return Identifier::SET; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/T61String.php000064400000001431150736751610016567 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\AbstractString; use FG\ASN1\Identifier; class T61String extends AbstractString { /** * Creates a new ASN.1 T61 String. * TODO The encodable characters of this type are not yet checked. * * @see http://en.wikipedia.org/wiki/ITU_T.61 * * @param string $string */ public function __construct($string) { $this->value = $string; $this->allowAll(); } public function getType() { return Identifier::T61_STRING; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/UTCTime.php000064400000004601150736751610016302 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\AbstractTime; use FG\ASN1\Parsable; use FG\ASN1\Identifier; use FG\ASN1\Exception\ParserException; /** * This ASN.1 universal type contains the calendar date and time. * * The precision is one minute or one second and optionally a * local time differential from coordinated universal time. * * Decoding of this type will accept the Basic Encoding Rules (BER) * The encoding will comply with the Distinguished Encoding Rules (DER). */ class UTCTime extends AbstractTime implements Parsable { public function getType() { return Identifier::UTC_TIME; } protected function calculateContentLength() { return 13; // Content is a string o the following format: YYMMDDhhmmssZ (13 octets) } protected function getEncodedValue() { return $this->value->format('ymdHis').'Z'; } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { self::parseIdentifier($binaryData[$offsetIndex], Identifier::UTC_TIME, $offsetIndex++); $contentLength = self::parseContentLength($binaryData, $offsetIndex, 11); $format = 'ymdGi'; $dateTimeString = substr($binaryData, $offsetIndex, 10); $offsetIndex += 10; // extract optional seconds part if ($binaryData[$offsetIndex] != 'Z' && $binaryData[$offsetIndex] != '+' && $binaryData[$offsetIndex] != '-') { $dateTimeString .= substr($binaryData, $offsetIndex, 2); $offsetIndex += 2; $format .= 's'; } $dateTime = \DateTime::createFromFormat($format, $dateTimeString, new \DateTimeZone('UTC')); // extract time zone settings if ($binaryData[$offsetIndex] == '+' || $binaryData[$offsetIndex] == '-') { $dateTime = static::extractTimeZoneData($binaryData, $offsetIndex, $dateTime); } elseif ($binaryData[$offsetIndex++] != 'Z') { throw new ParserException('Invalid UTC String', $offsetIndex); } $parsedObject = new self($dateTime); $parsedObject->setContentLength($contentLength); return $parsedObject; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/UTF8String.php000064400000001350150736751610016743 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\AbstractString; use FG\ASN1\Identifier; class UTF8String extends AbstractString { /** * Creates a new ASN.1 Universal String. * TODO The encodable characters of this type are not yet checked. * * @param string $string */ public function __construct($string) { $this->value = $string; $this->allowAll(); } public function getType() { return Identifier::UTF8_STRING; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/UniversalString.php000064400000001472150736751610020172 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\AbstractString; use FG\ASN1\Identifier; class UniversalString extends AbstractString { /** * Creates a new ASN.1 Universal String. * TODO The encodable characters of this type are not yet checked. * * @see http://en.wikipedia.org/wiki/Universal_Character_Set * * @param string $string */ public function __construct($string) { $this->value = $string; $this->allowAll(); } public function getType() { return Identifier::UNIVERSAL_STRING; } } vendor/fgrosse/phpasn1/lib/ASN1/Universal/VisibleString.php000064400000001354150736751610017616 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1\Universal; use FG\ASN1\AbstractString; use FG\ASN1\Identifier; class VisibleString extends AbstractString { /** * Creates a new ASN.1 Visible String. * TODO The encodable characters of this type are not yet checked. * * @param string $string */ public function __construct($string) { $this->value = $string; $this->allowAll(); } public function getType() { return Identifier::VISIBLE_STRING; } } vendor/fgrosse/phpasn1/lib/ASN1/UnknownConstructedObject.php000064400000002621150736751610020064 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1; class UnknownConstructedObject extends Construct { private $identifier; private $contentLength; /** * @param string $binaryData * @param int $offsetIndex * * @throws \FG\ASN1\Exception\ParserException */ public function __construct($binaryData, &$offsetIndex) { $this->identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex); $this->contentLength = self::parseContentLength($binaryData, $offsetIndex); $children = []; $octetsToRead = $this->contentLength; while ($octetsToRead > 0) { $newChild = ASNObject::fromBinary($binaryData, $offsetIndex); $octetsToRead -= $newChild->getObjectLength(); $children[] = $newChild; } parent::__construct(...$children); } public function getType() { return ord($this->identifier); } public function getIdentifier() { return $this->identifier; } protected function calculateContentLength() { return $this->contentLength; } protected function getEncodedValue() { return ''; } } vendor/fgrosse/phpasn1/lib/ASN1/UnknownObject.php000064400000002421150736751610015644 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\ASN1; class UnknownObject extends ASNObject { /** @var string */ private $value; private $identifier; /** * @param string|int $identifier Either the first identifier octet as int or all identifier bytes as a string * @param int $contentLength */ public function __construct($identifier, $contentLength) { if (is_int($identifier)) { $identifier = chr($identifier); } $this->identifier = $identifier; $this->value = "Unparsable Object ({$contentLength} bytes)"; $this->setContentLength($contentLength); } public function getContent() { return $this->value; } public function getType() { return ord($this->identifier[0]); } public function getIdentifier() { return $this->identifier; } protected function calculateContentLength() { return $this->getContentLength(); } protected function getEncodedValue() { return ''; } } vendor/fgrosse/phpasn1/lib/Utility/BigInteger.php000064400000012133150736751610016037 0ustar00_fromInteger($val); } else { // convert to string, if not already one $val = (string)$val; // validate string if (!preg_match('/^-?[0-9]+$/', $val)) { throw new \InvalidArgumentException('Expects a string representation of an integer.'); } $ret->_fromString($val); } return $ret; } /** * BigInteger constructor. * Prevent directly instantiating object, use BigInteger::create instead. */ protected function __construct() { } /** * Subclasses must provide clone functionality. * @return BigInteger */ abstract public function __clone(); /** * Assign the instance value from base 10 string. * @param string $str */ abstract protected function _fromString($str); /** * Assign the instance value from an integer type. * @param int $integer */ abstract protected function _fromInteger($integer); /** * Must provide string implementation that returns base 10 number. * @return string */ abstract public function __toString(); /* INFORMATIONAL FUNCTIONS */ /** * Return integer, if possible. Throws an exception if the number can not be represented as a native integer. * @return int * @throws \OverflowException */ abstract public function toInteger(); /** * Is represented integer negative? * @return bool */ abstract public function isNegative(); /** * Compare the integer with $number, returns a negative integer if $this is less than number, returns 0 if $this is * equal to number and returns a positive integer if $this is greater than number. * @param BigInteger|string|int $number * @return int */ abstract public function compare($number); /* MODIFY */ /** * Add another integer $b and returns the result. * @param BigInteger|string|int $b * @return BigInteger */ abstract public function add($b); /** * Subtract $b from $this and returns the result. * @param BigInteger|string|int $b * @return BigInteger */ abstract public function subtract($b); /** * Multiply value. * @param BigInteger|string|int $b * @return BigInteger */ abstract public function multiply($b); /** * The value $this modulus $b. * @param BigInteger|string|int $b * @return BigInteger */ abstract public function modulus($b); /** * Raise $this to the power of $b and returns the result. * @param BigInteger|string|int $b * @return BigInteger */ abstract public function toPower($b); /** * Shift the value to the right by a set number of bits and returns the result. * @param int $bits * @return BigInteger */ abstract public function shiftRight($bits = 8); /** * Shift the value to the left by a set number of bits and returns the result. * @param int $bits * @return BigInteger */ abstract public function shiftLeft($bits = 8); /** * Returns the absolute value. * @return BigInteger */ abstract public function absoluteValue(); } vendor/fgrosse/phpasn1/lib/Utility/BigIntegerBcmath.php000064400000005743150736751610017167 0ustar00_str = (string)$str; } protected function _fromInteger($integer) { $this->_str = (string)$integer; } public function __toString() { return $this->_str; } public function toInteger() { if ($this->compare(PHP_INT_MAX) > 0 || $this->compare(PHP_INT_MIN) < 0) { throw new \OverflowException(sprintf('Can not represent %s as integer.', $this->_str)); } return (int)$this->_str; } public function isNegative() { return bccomp($this->_str, '0', 0) < 0; } protected function _unwrap($number) { if ($number instanceof self) { return $number->_str; } return $number; } public function compare($number) { return bccomp($this->_str, $this->_unwrap($number), 0); } public function add($b) { $ret = new self(); $ret->_str = bcadd($this->_str, $this->_unwrap($b), 0); return $ret; } public function subtract($b) { $ret = new self(); $ret->_str = bcsub($this->_str, $this->_unwrap($b), 0); return $ret; } public function multiply($b) { $ret = new self(); $ret->_str = bcmul($this->_str, $this->_unwrap($b), 0); return $ret; } public function modulus($b) { $ret = new self(); if ($this->isNegative()) { // bcmod handles negative numbers differently $b = $this->_unwrap($b); $ret->_str = bcsub($b, bcmod(bcsub('0', $this->_str, 0), $b), 0); } else { $ret->_str = bcmod($this->_str, $this->_unwrap($b)); } return $ret; } public function toPower($b) { $ret = new self(); $ret->_str = bcpow($this->_str, $this->_unwrap($b), 0); return $ret; } public function shiftRight($bits = 8) { $ret = new self(); $ret->_str = bcdiv($this->_str, bcpow('2', $bits)); return $ret; } public function shiftLeft($bits = 8) { $ret = new self(); $ret->_str = bcmul($this->_str, bcpow('2', $bits)); return $ret; } public function absoluteValue() { $ret = new self(); if (-1 === bccomp($this->_str, '0', 0)) { $ret->_str = bcsub('0', $this->_str, 0); } else { $ret->_str = $this->_str; } return $ret; } } vendor/fgrosse/phpasn1/lib/Utility/BigIntegerGmp.php000064400000005672150736751610016515 0ustar00_rh = gmp_add($this->_rh, 0); } protected function _fromString($str) { $this->_rh = gmp_init($str, 10); } protected function _fromInteger($integer) { $this->_rh = gmp_init($integer, 10); } public function __toString() { return gmp_strval($this->_rh, 10); } public function toInteger() { if ($this->compare(PHP_INT_MAX) > 0 || $this->compare(PHP_INT_MIN) < 0) { throw new \OverflowException(sprintf('Can not represent %s as integer.', $this)); } return gmp_intval($this->_rh); } public function isNegative() { return gmp_sign($this->_rh) === -1; } protected function _unwrap($number) { if ($number instanceof self) { return $number->_rh; } return $number; } public function compare($number) { return gmp_cmp($this->_rh, $this->_unwrap($number)); } public function add($b) { $ret = new self(); $ret->_rh = gmp_add($this->_rh, $this->_unwrap($b)); return $ret; } public function subtract($b) { $ret = new self(); $ret->_rh = gmp_sub($this->_rh, $this->_unwrap($b)); return $ret; } public function multiply($b) { $ret = new self(); $ret->_rh = gmp_mul($this->_rh, $this->_unwrap($b)); return $ret; } public function modulus($b) { $ret = new self(); $ret->_rh = gmp_mod($this->_rh, $this->_unwrap($b)); return $ret; } public function toPower($b) { if ($b instanceof self) { // gmp_pow accepts just an integer if ($b->compare(PHP_INT_MAX) > 0) { throw new \UnexpectedValueException('Unable to raise to power greater than PHP_INT_MAX.'); } $b = gmp_intval($b->_rh); } $ret = new self(); $ret->_rh = gmp_pow($this->_rh, $b); return $ret; } public function shiftRight($bits=8) { $ret = new self(); $ret->_rh = gmp_div($this->_rh, gmp_pow(2, $bits)); return $ret; } public function shiftLeft($bits=8) { $ret = new self(); $ret->_rh = gmp_mul($this->_rh, gmp_pow(2, $bits)); return $ret; } public function absoluteValue() { $ret = new self(); $ret->_rh = gmp_abs($this->_rh); return $ret; } } vendor/fgrosse/phpasn1/lib/X509/AlgorithmIdentifier.php000064400000001053150736751610016752 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\X509; use FG\ASN1\Universal\NullObject; use FG\ASN1\Composite\AttributeTypeAndValue; class AlgorithmIdentifier extends AttributeTypeAndValue { public function __construct($objectIdentifierString) { parent::__construct($objectIdentifierString, new NullObject()); } } vendor/fgrosse/phpasn1/lib/X509/CSR/Attributes.php000064400000004445150736751610015606 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\X509\CSR; use FG\ASN1\ASNObject; use FG\X509\CertificateExtensions; use FG\ASN1\OID; use FG\ASN1\Parsable; use FG\ASN1\Construct; use FG\ASN1\Identifier; use FG\ASN1\Universal\Set; use FG\ASN1\Universal\Sequence; use FG\ASN1\Universal\ObjectIdentifier; class Attributes extends Construct implements Parsable { public function getType() { return 0xA0; } public function addAttribute($objectIdentifier, Set $attribute) { if (is_string($objectIdentifier)) { $objectIdentifier = new ObjectIdentifier($objectIdentifier); } $attributeSequence = new Sequence($objectIdentifier, $attribute); $attributeSequence->getNumberOfLengthOctets(); // length and number of length octets is calculated $this->addChild($attributeSequence); } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { self::parseIdentifier($binaryData[$offsetIndex], 0xA0, $offsetIndex++); $contentLength = self::parseContentLength($binaryData, $offsetIndex); $octetsToRead = $contentLength; $parsedObject = new self(); while ($octetsToRead > 0) { $initialOffset = $offsetIndex; // used to calculate how much bits have been read self::parseIdentifier($binaryData[$offsetIndex], Identifier::SEQUENCE, $offsetIndex++); self::parseContentLength($binaryData, $offsetIndex); $objectIdentifier = ObjectIdentifier::fromBinary($binaryData, $offsetIndex); $oidString = $objectIdentifier->getContent(); if ($oidString == OID::PKCS9_EXTENSION_REQUEST) { $attribute = CertificateExtensions::fromBinary($binaryData, $offsetIndex); } else { $attribute = ASNObject::fromBinary($binaryData, $offsetIndex); } $parsedObject->addAttribute($objectIdentifier, $attribute); $octetsToRead -= ($offsetIndex - $initialOffset); } $parsedObject->setContentLength($contentLength); return $parsedObject; } } vendor/fgrosse/phpasn1/lib/X509/CSR/CSR.php000064400000010140150736751610014074 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\X509\CSR; use FG\ASN1\OID; use FG\ASN1\Universal\Integer; use FG\ASN1\Universal\BitString; use FG\ASN1\Universal\Sequence; use FG\X509\CertificateSubject; use FG\X509\AlgorithmIdentifier; use FG\X509\PublicKey; class CSR extends Sequence { const CSR_VERSION_NR = 0; protected $subject; protected $publicKey; protected $signature; protected $signatureAlgorithm; protected $startSequence; /** * @param string $commonName * @param string $email * @param string $organization * @param string $locality * @param string $state * @param string $country * @param string $organizationalUnit * @param string $publicKey * @param string $signature * @param string $signatureAlgorithm */ public function __construct($commonName, $email, $organization, $locality, $state, $country, $organizationalUnit, $publicKey, $signature = null, $signatureAlgorithm = OID::SHA1_WITH_RSA_SIGNATURE) { $this->subject = new CertificateSubject( $commonName, $email, $organization, $locality, $state, $country, $organizationalUnit ); $this->publicKey = $publicKey; $this->signature = $signature; $this->signatureAlgorithm = $signatureAlgorithm; if (isset($signature)) { $this->createCSRSequence(); } } protected function createCSRSequence() { $versionNr = new Integer(self::CSR_VERSION_NR); $publicKey = new PublicKey($this->publicKey); $signature = new BitString($this->signature); $signatureAlgorithm = new AlgorithmIdentifier($this->signatureAlgorithm); $certRequestInfo = new Sequence($versionNr, $this->subject, $publicKey); // Clear the underlying Construct $this->rewind(); $this->children = []; $this->addChild($certRequestInfo); $this->addChild($signatureAlgorithm); $this->addChild($signature); } public function getSignatureSubject() { $versionNr = new Integer(self::CSR_VERSION_NR); $publicKey = new PublicKey($this->publicKey); $certRequestInfo = new Sequence($versionNr, $this->subject, $publicKey); return $certRequestInfo->getBinary(); } public function setSignature($signature, $signatureAlgorithm = OID::SHA1_WITH_RSA_SIGNATURE) { $this->signature = $signature; $this->signatureAlgorithm = $signatureAlgorithm; $this->createCSRSequence(); } public function __toString() { $tmp = base64_encode($this->getBinary()); for ($i = 0; $i < strlen($tmp); $i++) { if (($i + 2) % 65 == 0) { $tmp = substr($tmp, 0, $i + 1)."\n".substr($tmp, $i + 1); } } $result = '-----BEGIN CERTIFICATE REQUEST-----'.PHP_EOL; $result .= $tmp.PHP_EOL; $result .= '-----END CERTIFICATE REQUEST-----'; return $result; } public function getVersion() { return self::CSR_VERSION_NR; } public function getOrganizationName() { return $this->subject->getOrganization(); } public function getLocalName() { return $this->subject->getLocality(); } public function getState() { return $this->subject->getState(); } public function getCountry() { return $this->subject->getCountry(); } public function getOrganizationalUnit() { return $this->subject->getOrganizationalUnit(); } public function getPublicKey() { return $this->publicKey; } public function getSignature() { return $this->signature; } public function getSignatureAlgorithm() { return $this->signatureAlgorithm; } } vendor/fgrosse/phpasn1/lib/X509/CertificateExtensions.php000064400000007117150736751610017332 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\X509; use FG\ASN1\Exception\ParserException; use FG\ASN1\OID; use FG\ASN1\ASNObject; use FG\ASN1\Parsable; use FG\ASN1\Identifier; use FG\ASN1\Universal\OctetString; use FG\ASN1\Universal\Set; use FG\ASN1\Universal\Sequence; use FG\ASN1\Universal\ObjectIdentifier; use FG\X509\SAN\SubjectAlternativeNames; class CertificateExtensions extends Set implements Parsable { private $innerSequence; private $extensions = []; public function __construct() { $this->innerSequence = new Sequence(); parent::__construct($this->innerSequence); } public function addSubjectAlternativeNames(SubjectAlternativeNames $sans) { $this->addExtension(OID::CERT_EXT_SUBJECT_ALT_NAME, $sans); } private function addExtension($oidString, ASNObject $extension) { $sequence = new Sequence(); $sequence->addChild(new ObjectIdentifier($oidString)); $sequence->addChild($extension); $this->innerSequence->addChild($sequence); $this->extensions[] = $extension; } public function getContent() { return $this->extensions; } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { self::parseIdentifier($binaryData[$offsetIndex], Identifier::SET, $offsetIndex++); self::parseContentLength($binaryData, $offsetIndex); $tmpOffset = $offsetIndex; $extensions = Sequence::fromBinary($binaryData, $offsetIndex); $tmpOffset += 1 + $extensions->getNumberOfLengthOctets(); $parsedObject = new self(); foreach ($extensions as $extension) { if ($extension->getType() != Identifier::SEQUENCE) { //FIXME wrong offset index throw new ParserException('Could not parse Certificate Extensions: Expected ASN.1 Sequence but got '.$extension->getTypeName(), $offsetIndex); } $tmpOffset += 1 + $extension->getNumberOfLengthOctets(); $children = $extension->getChildren(); if (count($children) < 2) { throw new ParserException('Could not parse Certificate Extensions: Needs at least two child elements per extension sequence (object identifier and octet string)', $tmpOffset); } /** @var \FG\ASN1\ASNObject $objectIdentifier */ $objectIdentifier = $children[0]; /** @var OctetString $octetString */ $octetString = $children[1]; if ($objectIdentifier->getType() != Identifier::OBJECT_IDENTIFIER) { throw new ParserException('Could not parse Certificate Extensions: Expected ASN.1 Object Identifier but got '.$extension->getTypeName(), $tmpOffset); } $tmpOffset += $objectIdentifier->getObjectLength(); if ($objectIdentifier->getContent() == OID::CERT_EXT_SUBJECT_ALT_NAME) { $sans = SubjectAlternativeNames::fromBinary($binaryData, $tmpOffset); $parsedObject->addSubjectAlternativeNames($sans); } else { // can now only parse SANs. There might be more in the future $tmpOffset += $octetString->getObjectLength(); } } $parsedObject->getBinary(); // Determine the number of content octets and object sizes once (just to let the equality unit tests pass :/ ) return $parsedObject; } } vendor/fgrosse/phpasn1/lib/X509/CertificateSubject.php000064400000005626150736751610016575 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\X509; use FG\ASN1\Composite\RelativeDistinguishedName; use FG\ASN1\Identifier; use FG\ASN1\OID; use FG\ASN1\Parsable; use FG\ASN1\Composite\RDNString; use FG\ASN1\Universal\Sequence; class CertificateSubject extends Sequence implements Parsable { private $commonName; private $email; private $organization; private $locality; private $state; private $country; private $organizationalUnit; /** * @param string $commonName * @param string $email * @param string $organization * @param string $locality * @param string $state * @param string $country * @param string $organizationalUnit */ public function __construct($commonName, $email, $organization, $locality, $state, $country, $organizationalUnit) { parent::__construct( new RDNString(OID::COUNTRY_NAME, $country), new RDNString(OID::STATE_OR_PROVINCE_NAME, $state), new RDNString(OID::LOCALITY_NAME, $locality), new RDNString(OID::ORGANIZATION_NAME, $organization), new RDNString(OID::OU_NAME, $organizationalUnit), new RDNString(OID::COMMON_NAME, $commonName), new RDNString(OID::PKCS9_EMAIL, $email) ); $this->commonName = $commonName; $this->email = $email; $this->organization = $organization; $this->locality = $locality; $this->state = $state; $this->country = $country; $this->organizationalUnit = $organizationalUnit; } public function getCommonName() { return $this->commonName; } public function getEmail() { return $this->email; } public function getOrganization() { return $this->organization; } public function getLocality() { return $this->locality; } public function getState() { return $this->state; } public function getCountry() { return $this->country; } public function getOrganizationalUnit() { return $this->organizationalUnit; } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { self::parseIdentifier($binaryData[$offsetIndex], Identifier::SEQUENCE, $offsetIndex++); $contentLength = self::parseContentLength($binaryData, $offsetIndex); $names = []; $octetsToRead = $contentLength; while ($octetsToRead > 0) { $relativeDistinguishedName = RelativeDistinguishedName::fromBinary($binaryData, $offsetIndex); $octetsToRead -= $relativeDistinguishedName->getObjectLength(); $names[] = $relativeDistinguishedName; } } } vendor/fgrosse/phpasn1/lib/X509/PrivateKey.php000064400000001603150736751610015105 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\X509; use FG\ASN1\OID; use FG\ASN1\Universal\NullObject; use FG\ASN1\Universal\Sequence; use FG\ASN1\Universal\BitString; use FG\ASN1\Universal\ObjectIdentifier; class PrivateKey extends Sequence { /** * @param string $hexKey * @param \FG\ASN1\ASNObject|string $algorithmIdentifierString */ public function __construct($hexKey, $algorithmIdentifierString = OID::RSA_ENCRYPTION) { parent::__construct( new Sequence( new ObjectIdentifier($algorithmIdentifierString), new NullObject() ), new BitString($hexKey) ); } } vendor/fgrosse/phpasn1/lib/X509/PublicKey.php000064400000001602150736751610014710 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\X509; use FG\ASN1\OID; use FG\ASN1\Universal\NullObject; use FG\ASN1\Universal\Sequence; use FG\ASN1\Universal\BitString; use FG\ASN1\Universal\ObjectIdentifier; class PublicKey extends Sequence { /** * @param string $hexKey * @param \FG\ASN1\ASNObject|string $algorithmIdentifierString */ public function __construct($hexKey, $algorithmIdentifierString = OID::RSA_ENCRYPTION) { parent::__construct( new Sequence( new ObjectIdentifier($algorithmIdentifierString), new NullObject() ), new BitString($hexKey) ); } } vendor/fgrosse/phpasn1/lib/X509/SAN/DNSName.php000064400000001171150736751610014670 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\X509\SAN; use FG\ASN1\Universal\GeneralString; class DNSName extends GeneralString { const IDENTIFIER = 0x82; // not sure yet why this is the identifier used in SAN extensions public function __construct($dnsNameString) { parent::__construct($dnsNameString); } public function getType() { return self::IDENTIFIER; } } vendor/fgrosse/phpasn1/lib/X509/SAN/IPAddress.php000064400000003727150736751610015272 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\X509\SAN; use FG\ASN1\ASNObject; use FG\ASN1\Parsable; use FG\ASN1\Exception\ParserException; class IPAddress extends ASNObject implements Parsable { const IDENTIFIER = 0x87; // not sure yet why this is the identifier used in SAN extensions /** @var string */ private $value; public function __construct($ipAddressString) { $this->value = $ipAddressString; } public function getType() { return self::IDENTIFIER; } public function getContent() { return $this->value; } protected function calculateContentLength() { return 4; } protected function getEncodedValue() { $ipParts = explode('.', $this->value); $binary = chr($ipParts[0]); $binary .= chr($ipParts[1]); $binary .= chr($ipParts[2]); $binary .= chr($ipParts[3]); return $binary; } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { self::parseIdentifier($binaryData[$offsetIndex], self::IDENTIFIER, $offsetIndex++); $contentLength = self::parseContentLength($binaryData, $offsetIndex); if ($contentLength != 4) { throw new ParserException("A FG\\X509\SAN\IPAddress should have a content length of 4. Extracted length was {$contentLength}", $offsetIndex); } $ipAddressString = ord($binaryData[$offsetIndex++]).'.'; $ipAddressString .= ord($binaryData[$offsetIndex++]).'.'; $ipAddressString .= ord($binaryData[$offsetIndex++]).'.'; $ipAddressString .= ord($binaryData[$offsetIndex++]); $parsedObject = new self($ipAddressString); $parsedObject->getObjectLength(); return $parsedObject; } } vendor/fgrosse/phpasn1/lib/X509/SAN/SubjectAlternativeNames.php000064400000006247150736751610020236 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace FG\X509\SAN; use FG\ASN1\Exception\ParserException; use FG\ASN1\ASNObject; use FG\ASN1\OID; use FG\ASN1\Parsable; use FG\ASN1\Identifier; use FG\ASN1\Universal\Sequence; /** * See section 8.3.2.1 of ITU-T X.509. */ class SubjectAlternativeNames extends ASNObject implements Parsable { private $alternativeNamesSequence; public function __construct() { $this->alternativeNamesSequence = new Sequence(); } protected function calculateContentLength() { return $this->alternativeNamesSequence->getObjectLength(); } public function getType() { return Identifier::OCTETSTRING; } public function addDomainName(DNSName $domainName) { $this->alternativeNamesSequence->addChild($domainName); } public function addIP(IPAddress $ip) { $this->alternativeNamesSequence->addChild($ip); } public function getContent() { return $this->alternativeNamesSequence->getContent(); } protected function getEncodedValue() { return $this->alternativeNamesSequence->getBinary(); } public static function fromBinary(&$binaryData, &$offsetIndex = 0) { self::parseIdentifier($binaryData[$offsetIndex], Identifier::OCTETSTRING, $offsetIndex++); $contentLength = self::parseContentLength($binaryData, $offsetIndex); if ($contentLength < 2) { throw new ParserException('Can not parse Subject Alternative Names: The Sequence within the octet string after the Object identifier '.OID::CERT_EXT_SUBJECT_ALT_NAME." is too short ({$contentLength} octets)", $offsetIndex); } $offsetOfSequence = $offsetIndex; $sequence = Sequence::fromBinary($binaryData, $offsetIndex); $offsetOfSequence += $sequence->getNumberOfLengthOctets() + 1; if ($sequence->getObjectLength() != $contentLength) { throw new ParserException('Can not parse Subject Alternative Names: The Sequence length does not match the length of the surrounding octet string', $offsetIndex); } $parsedObject = new self(); /** @var \FG\ASN1\ASNObject $object */ foreach ($sequence as $object) { if ($object->getType() == DNSName::IDENTIFIER) { $domainName = DNSName::fromBinary($binaryData, $offsetOfSequence); $parsedObject->addDomainName($domainName); } elseif ($object->getType() == IPAddress::IDENTIFIER) { $ip = IPAddress::fromBinary($binaryData, $offsetOfSequence); $parsedObject->addIP($ip); } else { throw new ParserException('Could not parse Subject Alternative Name: Only DNSName and IP SANs are currently supported', $offsetIndex); } } $parsedObject->getBinary(); // Determine the number of content octets and object sizes once (just to let the equality unit tests pass :/ ) return $parsedObject; } } vendor/mdanter/ecc/.gitattributes000064400000000146150736751610013134 0ustar00/doc export-ignore /examples export-ignore /tests export-ignore vendor/mdanter/ecc/.gitignore000064400000000044150736751610012226 0ustar00tests/output vendor/ composer.lock vendor/mdanter/ecc/.gitmodules000064400000000162150736751610012414 0ustar00[submodule "tests/import/wycheproof"] path = tests/import/wycheproof url = https://github.com/google/wycheproof vendor/mdanter/ecc/.scrutinizer.yml000064400000004771150736751610013433 0ustar00build: nodes: php-scrutinizer-run: project_setup: override: true tests: override: [php-scrutinizer-run] environment: mysql: false redis: false postgresql: false php: version: 7.2 ini: 'zend.assertions': '1' 'assert.exception': '1' dependencies: override: - command: 'composer install' tests: override: true project_setup: override: true filter: paths: - src/* excluded_paths: - examples/* - tests/* - vendor/* tools: php_cpd: true php_pdepend: true php_analyzer: true php_sim: true php_changetracking: true php_mess_detector: true php_code_sniffer: true sensiolabs_security_checker: true php_code_coverage: true php_pdepend: excluded_dirs: [vendor, doc, examples, build, tests] external_code_coverage: timeout: 1300 runs: 1 changetracking: bug_patterns: ["\bfix(?:es|ed)?\b"] feature_patterns: ["\badd(?:s|ed)?\b", "\bimplement(?:s|ed)?\b"] build_failure_conditions: # No new critical issue is introduced (existing ones are tolerated) - 'issues.severity(>= CRITICAL).new.exists' # Code Coverage drops below 60% - 'project.metric("scrutinizer.test_coverage", < 0.80)' # Code Coverage decreased from previous inspection by more than 1% - 'project.metric_change("scrutinizer.test_coverage", < -0.01)' checks: php: simplify_boolean_return: true return_doc_comments: true return_doc_comment_if_not_inferrable: true remove_extra_empty_lines: true properties_in_camelcaps: true phpunit_assertions: true parameters_in_camelcaps: true parameter_doc_comments: true param_doc_comment_if_not_inferrable: true overriding_parameter: true no_short_variable_names: minimum: '3' no_short_method_names: minimum: '3' no_long_variable_names: maximum: '20' no_goto: true fix_use_statements: remove_unused: true preserve_multiple: false preserve_blanklines: false order_alphabetically: false fix_line_ending: true check_method_contracts: verify_interface_like_constraints: true verify_documented_constraints: true verify_parent_constraints: true vendor/mdanter/ecc/.travis.yml000064400000002466150736751610012361 0ustar00language: php php: - 7.0 - 7.1 - 7.2 - nightly env: # The default env behaviour: phpunit, no coverage, no style checks - PHPUNIT=true matrix: fast_finish: true exclude: # Disable standard phpunit test on 7.0, reenable with FULL, and with COVERAGE - php: 7.2 env: PHPUNIT=true include: # This reenables php7.0/phpunit test with COVERAGE - php: 7.2 env: PHPUNIT=true COVERAGE_SHARDS=5 COVERAGE=true # This reenables php7.0/phpunit test with extended tests (wycheproof) - php: 7.2 env: FULL=true # This runs phpcs on php7.0 - only code style and examples - php: 7.0 env: CODESTYLE=true EXAMPLES=true sudo: false before_script: - travis_retry composer selfupdate - travis_retry composer install --prefer-source - if [ "${COVERAGE}" != "true" ] && [ "${TRAVIS_PHP_VERSION}" != "nightly" ]; then phpenv config-rm xdebug.ini && echo "xdebug disabled"; fi script: - if [ "${PHPUNIT}" = "true" ]; then make phpunit-ci; fi - if [ "${FULL}" = "true" ]; then make phpunit-full-ci; fi - if [ "${CODESTYLE}" = "true" ]; then make phpcs && echo "PHPCS OK"; fi - if [ "${EXAMPLES}" = "true" ]; then make test-examples && echo "Examples OK"; fi after_success: - if [ "${COVERAGE}" = "true" ]; then make scrutinizer; fi vendor/mdanter/ecc/Makefile000064400000002516150736751610011704 0ustar00test: phpunit phpcs .PHONY: test phpunit phpcs pretest: if [ ! -d vendor ] || [ ! -f composer.lock ]; then composer install; else echo "Already have dependencies"; fi phpunit: pretest mkdir -p tests/output vendor/bin/phpunit --coverage-text --coverage-clover=tests/output/coverage.clover --coverage-html=tests/output/Results test-examples: ./validate_examples.sh phpunit-ci: pretest vendor/bin/phpunit --coverage-text --coverage-clover=tests/output/coverage.clover phpunit-full-ci: pretest vendor/bin/phpunit -c phpunit.full.xml --coverage-text --coverage-clover=tests/output/coverage.clover ifndef STRICT STRICT = 0 endif ifeq "$(STRICT)" "1" phpcs: pretest vendor/bin/phpcs --standard=PSR2 src tests/unit/ else phpcs: pretest vendor/bin/phpcs --standard=PSR2 -n src tests/unit/ endif phpcbf: pretest vendor/bin/phpcbf --standard=PSR2 -n src tests/unit/ ocular: wget https://scrutinizer-ci.com/ocular.phar ifdef OCULAR_TOKEN scrutinizer: ocular @php ocular.phar code-coverage:upload --format=php-clover tests/output/coverage.clover --access-token=$(OCULAR_TOKEN); else scrutinizer: ocular php ocular.phar code-coverage:upload --format=php-clover tests/output/coverage.clover; endif clean: clean-env clean-deps clean-env: rm -rf coverage.clover rm -rf ocular.phar rm -rf tests/output/ clean-deps: rm -rf vendor/ vendor/mdanter/ecc/README.md000064400000005217150736751610011524 0ustar00## Pure PHP Elliptic Curve DSA and DH [![Build Status](https://travis-ci.org/phpecc/phpecc.svg?branch=master)](https://travis-ci.org/phpecc/phpecc) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/phpecc/phpecc/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/phpecc/phpecc?branch=master) [![Code Coverage](https://scrutinizer-ci.com/g/phpecc/phpecc/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/phpecc/phpecc/?branch=master) [![Latest Stable Version](https://poser.pugx.org/mdanter/ecc/v/stable.png)](https://packagist.org/packages/mdanter/ecc) [![Total Downloads](https://poser.pugx.org/mdanter/ecc/downloads.png)](https://packagist.org/packages/mdanter/ecc) [![Latest Unstable Version](https://poser.pugx.org/mdanter/ecc/v/unstable.png)](https://packagist.org/packages/mdanter/ecc) [![License](https://poser.pugx.org/mdanter/ecc/license.png)](https://packagist.org/packages/mdanter/ecc) ### Information This library is a rewrite/update of Matyas Danter's ECC library. All credit goes to him. For more information on Elliptic Curve Cryptography please read [this fine article](http://www.matyasdanter.com/2010/12/elliptic-curve-php-oop-dsa-and-diffie-hellman/). The library supports the following curves: - secp112r1 - secp256k1 - nistp192 - nistp224 - nistp256 / secp256r1 - nistp384 / secp384r1 - nistp521 During ECDSA, a random value `k` is required. It is acceptable to use a true RNG to generate this value, but should the same `k` value ever be repeatedly used for a key, an attacker can recover that signing key. The HMAC random generator can derive a deterministic k value from the message hash and private key, voiding this concern. The library uses a non-branching Montgomery ladder for scalar multiplication, as it's constant time and avoids secret dependant branches. ### License This package is released under the MIT license. ### Requirements * PHP 7.0+ * composer * ext-gmp For PHP5.6 compatibility, use the v0.4.x releases. ### Installation You can install this library via Composer : `composer require mdanter/ecc` ### Contribute When sending in pull requests, please make sure to run the `make` command. The default target runs all PHPUnit and PHPCS tests. All tests must validate for your contribution to be accepted. It's also always a good idea to check the results of the [Scrutinizer analysis](https://scrutinizer-ci.com/g/phpecc/phpecc/) for your pull requests. ### Usage Examples: * [Key generation](./examples/key_generation.php) * [ECDH exchange](./examples/ecdh_exchange.php) * [Signature creation](./examples/creating_signature.php) * [Signature verification](./examples/verify_signature.php) vendor/mdanter/ecc/composer.json000064400000002513150736751610012763 0ustar00{ "name": "mdanter/ecc", "description": "PHP Elliptic Curve Cryptography library", "type": "library", "homepage": "https://github.com/phpecc/phpecc", "keywords": ["secp256k1", "secp256r1", "nistp192", "nistp224", "nistp256", "nistp384", "nistp521", "ECDSA", "diffie", "hellman", "ECDH", "elliptic", "curve", "phpecc"], "license": "MIT", "authors": [ { "name": "Matyas Danter", "homepage": "http://matejdanter.com/", "role": "Author" }, { "name": "Thibaud Fabre", "email": "thibaud@aztech.io", "homepage": "http://aztech.io", "role": "Maintainer" }, { "name": "Thomas Kerin", "email": "afk11@users.noreply.github.com", "role": "Maintainer" } ], "require": { "php": "^7.0", "ext-gmp": "*", "fgrosse/phpasn1": "^2.0" }, "require-dev": { "phpunit/phpunit": "^6.0", "squizlabs/php_codesniffer": "^2.0", "symfony/yaml": "^2.6|^3.0" }, "autoload": { "psr-4": { "Mdanter\\Ecc\\": "src/" } }, "autoload-dev": { "psr-4": { "Mdanter\\Ecc\\Tests\\": "tests/unit", "Mdanter\\Ecc\\WycheProof\\": "tests/wycheproof" } } } vendor/mdanter/ecc/phpunit.full.xml000064400000002242150736751610013412 0ustar00 ./tests/wycheproof ./tests/unit src/ vendor/mdanter/ecc/phpunit.xml000064400000001657150736751610012462 0ustar00 ./tests/unit src/ vendor/mdanter/ecc/src/Crypto/EcDH/EcDH.php000064400000011775150736751610014341 0ustar00adapter = $adapter; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Crypto\EcDH\EcDHInterface::calculateSharedKey() */ public function calculateSharedKey(): \GMP { $this->calculateKey(); return $this->secretKey->getPoint()->getX(); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Crypto\EcDH\EcDHInterface::createMultiPartyKey() */ public function createMultiPartyKey(): PublicKeyInterface { $this->calculateKey(); return $this->secretKey; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Crypto\EcDH\EcDHInterface::setRecipientKey() */ public function setRecipientKey(PublicKeyInterface $key = null) { $this->recipientKey = $key; return $this; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Crypto\EcDH\EcDHInterface::setSenderKey() */ public function setSenderKey(PrivateKeyInterface $key) { $this->senderKey = $key; return $this; } /** * */ private function calculateKey() { $this->checkExchangeState(); if ($this->secretKey === null) { try { // Multiply our secret with recipients public key $point = $this->recipientKey->getPoint()->mul($this->senderKey->getSecret()); // Ensure we completed a valid exchange, ensure we can create a // public key instance for the shared secret using our generator. $this->secretKey = $this->senderKey->getPoint()->getPublicKeyFrom($point->getX(), $point->getY()); } catch (\Exception $e) { throw new ExchangeException("Invalid ECDH exchange", 0, $e); } } } /** * Verifies that the shared secret is known, or that the required keys are available * to calculate the shared secret. * @throws \RuntimeException when the exchange has not been made. */ private function checkExchangeState() { if ($this->secretKey !== null) { return; } if ($this->senderKey === null) { throw new ExchangeException('Sender key not set.'); } if ($this->recipientKey === null) { throw new ExchangeException('Recipient key not set.'); } // Check the point exists on our curve. $point = $this->recipientKey->getPoint(); if (!$this->senderKey->getPoint()->getCurve()->contains($point->getX(), $point->getY())) { throw new ExchangeException("Invalid ECDH exchange - Point does not exist on our curve"); } } } vendor/mdanter/ecc/src/Crypto/EcDH/EcDHInterface.php000064400000004124150736751610016150 0ustar00adapter = $adapter; $this->generator = $generator; $this->secretMultiplier = $secretMultiplier; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Crypto\Key\PrivateKeyInterface::getPublicKey() */ public function getPublicKey(): PublicKeyInterface { return new PublicKey($this->adapter, $this->generator, $this->generator->mul($this->secretMultiplier)); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Crypto\Key\PrivateKeyInterface::getPoint() */ public function getPoint(): GeneratorPoint { return $this->generator; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Crypto\Key\PrivateKeyInterface::getCurve() */ public function getCurve(): CurveFpInterface { return $this->generator->getCurve(); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Crypto\Key\PrivateKeyInterface::getSecret() */ public function getSecret(): \GMP { return $this->secretMultiplier; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Crypto\Key\PrivateKeyInterface::createExchange() */ public function createExchange(PublicKeyInterface $recipient = null): EcDHInterface { $ecdh = new EcDH($this->adapter); $ecdh ->setSenderKey($this) ->setRecipientKey($recipient); return $ecdh; } } vendor/mdanter/ecc/src/Crypto/Key/PrivateKeyInterface.php000064400000003666150736751610017467 0ustar00curve = $generator->getCurve(); $this->generator = $generator; $this->point = $point; $this->adapter = $adapter; // step 1: not point at infinity. if ($point->isInfinity()) { throw new PublicKeyException($generator, $point, "Cannot use point at infinity for public key"); } // step 2 full & partial public key validation routine if ($adapter->cmp($point->getX(), gmp_init(0, 10)) < 0 || $adapter->cmp($this->curve->getPrime(), $point->getX()) < 0 || $adapter->cmp($point->getY(), gmp_init(0, 10)) < 0 || $adapter->cmp($this->curve->getPrime(), $point->getY()) < 0 ) { throw new PublicKeyException($generator, $point, "Point has x and y out of range."); } // Sanity check. Point (x,y) values are qualified against it's // generator and curve. Here we ensure the Point and Generator // are the same. if (!$generator->getCurve()->equals($point->getCurve())) { throw new PublicKeyException($generator, $point, "Curve for given point not in common with GeneratorPoint"); } } /** * {@inheritDoc} * @see \Mdanter\Ecc\Crypto\Key\PublicKeyInterface::getCurve() */ public function getCurve(): CurveFpInterface { return $this->curve; } /** * {$inheritDoc} * @see \Mdanter\Ecc\Crypto\Key\PublicKeyInterface::getGenerator() */ public function getGenerator(): GeneratorPoint { return $this->generator; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Crypto\Key\PublicKeyInterface::getPoint() */ public function getPoint(): PointInterface { return $this->point; } } vendor/mdanter/ecc/src/Crypto/Key/PublicKeyInterface.php000064400000003504150736751610017262 0ustar00 20, 'sha224' => 28, 'sha256' => 32, 'sha384' => 48, 'sha512' => 64, ]; /** * @var GmpMathInterface */ private $adapter; /** * @var string */ private $algorithm; /** * SignHasher constructor. * @param string $algorithm * @param GmpMathInterface|null $math */ public function __construct(string $algorithm, GmpMathInterface $math = null) { if (!array_key_exists($algorithm, self::$sizeMap)) { throw new \InvalidArgumentException("Unsupported hashing algorithm"); } $this->algorithm = $algorithm; $this->adapter = $math ?: EccFactory::getAdapter(); } /** * @return string */ public function getAlgorithm(): string { return $this->algorithm; } /** * @return int */ public function getLengthInBytes(): int { return self::$sizeMap[$this->algorithm]; } /** * @param string $data * @return string */ public function makeRawHash(string $data): string { return hash($this->algorithm, $data, false); } /** * @param \GMP $hash * @param GeneratorPoint $G * @return \GMP */ public function truncateForECDSA(\GMP $hash, GeneratorPoint $G) { $hashBits = gmp_strval($hash, 2); if (BinaryString::length($hashBits) < self::$sizeMap[$this->algorithm] * 8) { $hashBits = str_pad($hashBits, self::$sizeMap[$this->algorithm] * 8, '0', STR_PAD_LEFT); } return gmp_init(BinaryString::substring($hashBits, 0, NumberSize::bnNumBits($this->adapter, $G->getOrder())), 2); } /** * @param string $data * @param GeneratorPoint $G * @return \GMP */ public function makeHash(string $data, GeneratorPoint $G): \GMP { $hash = gmp_init($this->makeRawHash($data), 16); return $this->truncateForECDSA($hash, $G); } } vendor/mdanter/ecc/src/Crypto/Signature/Signature.php000064400000004140150736751610016721 0ustar00r = $r; $this->s = $s; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Crypto\Signature\SignatureInterface::getR() */ public function getR(): \GMP { return $this->r; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Crypto\Signature\SignatureInterface::getS() */ public function getS(): \GMP { return $this->s; } } vendor/mdanter/ecc/src/Crypto/Signature/SignatureInterface.php000064400000003245150736751610020547 0ustar00adapter = $adapter; } /** * @param PrivateKeyInterface $key * @param \GMP $truncatedHash - hash truncated for use in ECDSA * @param \GMP $randomK * @return SignatureInterface */ public function sign(PrivateKeyInterface $key, \GMP $truncatedHash, \GMP $randomK): SignatureInterface { $math = $this->adapter; $generator = $key->getPoint(); $modMath = $math->getModularArithmetic($generator->getOrder()); $k = $math->mod($randomK, $generator->getOrder()); $p1 = $generator->mul($k); $r = $p1->getX(); $zero = gmp_init(0, 10); if ($math->equals($r, $zero)) { throw new \RuntimeException("Error: random number R = 0"); } $s = $modMath->div($modMath->add($truncatedHash, $math->mul($key->getSecret(), $r)), $k); if ($math->equals($s, $zero)) { throw new \RuntimeException("Error: random number S = 0"); } return new Signature($r, $s); } /** * @param PublicKeyInterface $key * @param SignatureInterface $signature * @param \GMP $hash * @return bool */ public function verify(PublicKeyInterface $key, SignatureInterface $signature, \GMP $hash): bool { $generator = $key->getGenerator(); $n = $generator->getOrder(); $r = $signature->getR(); $s = $signature->getS(); $math = $this->adapter; $one = gmp_init(1, 10); if ($math->cmp($r, $one) < 0 || $math->cmp($r, $math->sub($n, $one)) > 0) { return false; } if ($math->cmp($s, $one) < 0 || $math->cmp($s, $math->sub($n, $one)) > 0) { return false; } $modMath = $math->getModularArithmetic($n); $c = $math->inverseMod($s, $n); $u1 = $modMath->mul($hash, $c); $u2 = $modMath->mul($r, $c); $xy = $generator->mul($u1)->add($key->getPoint()->mul($u2)); $v = $math->mod($xy->getX(), $n); return BinaryString::constantTimeCompare($math->toString($v), $math->toString($r)); } } vendor/mdanter/ecc/src/Curves/CurveFactory.php000064400000007115150736751610015427 0ustar00curve192(); case NistCurve::NAME_P224: return $nistFactory->curve224(); case NistCurve::NAME_P256: return $nistFactory->curve256(); case NistCurve::NAME_P384: return $nistFactory->curve384(); case NistCurve::NAME_P521: return $nistFactory->curve521(); case SecgCurve::NAME_SECP_112R1: return $secpFactory->curve112r1(); case SecgCurve::NAME_SECP_192K1: return $secpFactory->curve192k1(); case SecgCurve::NAME_SECP_256K1: return $secpFactory->curve256k1(); case SecgCurve::NAME_SECP_256R1: return $secpFactory->curve256r1(); case SecgCurve::NAME_SECP_384R1: return $secpFactory->curve384r1(); default: $error = new UnsupportedCurveException('Unknown curve.'); $error->setCurveName($name); throw $error; } } /** * @param string $name * @return GeneratorPoint */ public static function getGeneratorByName(string $name): GeneratorPoint { $adapter = MathAdapterFactory::getAdapter(); $nistFactory = self::getNistFactory($adapter); $secpFactory = self::getSecpFactory($adapter); switch ($name) { case NistCurve::NAME_P192: return $nistFactory->generator192(); case NistCurve::NAME_P224: return $nistFactory->generator224(); case NistCurve::NAME_P256: return $nistFactory->generator256(); case NistCurve::NAME_P384: return $nistFactory->generator384(); case NistCurve::NAME_P521: return $nistFactory->generator521(); case SecgCurve::NAME_SECP_112R1: return $secpFactory->generator112r1(); case SecgCurve::NAME_SECP_192K1: return $secpFactory->generator192k1(); case SecgCurve::NAME_SECP_256K1: return $secpFactory->generator256k1(); case SecgCurve::NAME_SECP_256R1: return $secpFactory->generator256r1(); case SecgCurve::NAME_SECP_384R1: return $secpFactory->generator384r1(); default: $error = new UnsupportedCurveException('Unknown generator.'); $error->setCurveName($name); throw $error; } } /** * @param GmpMathInterface $math * @return NistCurve */ private static function getNistFactory(GmpMathInterface $math): NistCurve { return new NistCurve($math); } /** * @param GmpMathInterface $math * @return SecgCurve */ private static function getSecpFactory(GmpMathInterface $math): SecgCurve { return new SecgCurve($math); } } vendor/mdanter/ecc/src/Curves/NamedCurveFp.php000064400000001326150736751610015330 0ustar00name = $name; parent::__construct($parameters, $adapter); } /** * @return string */ public function getName(): string { return $this->name; } } vendor/mdanter/ecc/src/Curves/NistCurve.php000064400000020373150736751610014736 0ustar00adapter = $adapter; } /** * Returns an NIST P-192 curve. * * @return NamedCurveFp */ public function curve192(): NamedCurveFp { $p = gmp_init('6277101735386680763835789423207666416083908700390324961279', 10); $b = gmp_init('64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1', 16); $parameters = new CurveParameters(192, $p, gmp_init('-3', 10), $b); return new NamedCurveFp(self::NAME_P192, $parameters, $this->adapter); } /** * Returns an NIST P-192 generator. * * @param RandomNumberGeneratorInterface $randomGenerator * @return GeneratorPoint */ public function generator192(RandomNumberGeneratorInterface $randomGenerator = null): GeneratorPoint { $curve = $this->curve192(); $order = gmp_init('6277101735386680763835789423176059013767194773182842284081', 10); $x = gmp_init('188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012', 16); $y = gmp_init('07192b95ffc8da78631011ed6b24cdd573f977a11e794811', 16); return $curve->getGenerator($x, $y, $order, $randomGenerator); } /** * Returns an NIST P-224 curve * * @return NamedCurveFp */ public function curve224(): NamedCurveFp { $p = gmp_init('26959946667150639794667015087019630673557916260026308143510066298881', 10); $b = gmp_init('b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4', 16); $parameters = new CurveParameters(224, $p, gmp_init(-3, 10), $b); return new NamedCurveFp(self::NAME_P224, $parameters, $this->adapter); } /** * Returns an NIST P-224 generator. * * @param RandomNumberGeneratorInterface $randomGenerator * @return GeneratorPoint */ public function generator224(RandomNumberGeneratorInterface $randomGenerator = null): GeneratorPoint { $curve = $this->curve224(); $order = gmp_init('26959946667150639794667015087019625940457807714424391721682722368061', 10); $x = gmp_init('b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21', 16); $y = gmp_init('bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34', 16); return $curve->getGenerator($x, $y, $order, $randomGenerator); } /** * Returns an NIST P-256 curve. * * @return NamedCurveFp */ public function curve256(): NamedCurveFp { $p = gmp_init('115792089210356248762697446949407573530086143415290314195533631308867097853951', 10); $b = gmp_init('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b', 16); $parameters = new CurveParameters(256, $p, gmp_init(-3, 10), $b); return new NamedCurveFp(self::NAME_P256, $parameters, $this->adapter); } /** * Returns an NIST P-256 generator. * * @param RandomNumberGeneratorInterface $randomGenerator * @return GeneratorPoint */ public function generator256(RandomNumberGeneratorInterface $randomGenerator = null): GeneratorPoint { $curve = $this->curve256(); $order = gmp_init('115792089210356248762697446949407573529996955224135760342422259061068512044369', 10); $x = gmp_init('0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296', 16); $y = gmp_init('0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5', 16); return $curve->getGenerator($x, $y, $order, $randomGenerator); } /** * Returns an NIST P-384 curve. * * @return NamedCurveFp */ public function curve384(): NamedCurveFp { $p = gmp_init('39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319', 10); $b = gmp_init('0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef', 16); $parameters = new CurveParameters(384, $p, gmp_init(-3, 10), $b); return new NamedCurveFp(self::NAME_P384, $parameters, $this->adapter); } /** * Returns an NIST P-384 generator. * * @param RandomNumberGeneratorInterface $randomGenerator * @return GeneratorPoint */ public function generator384(RandomNumberGeneratorInterface $randomGenerator = null): GeneratorPoint { $curve = $this->curve384(); $order = gmp_init('39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643', 10); $x = gmp_init('0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7', 16); $y = gmp_init('0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f', 16); return $curve->getGenerator($x, $y, $order, $randomGenerator); } /** * Returns an NIST P-521 curve. * * @return NamedCurveFp */ public function curve521(): NamedCurveFp { $p = gmp_init('6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151', 10); $b = gmp_init('0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00', 16); $parameters = new CurveParameters(521, $p, gmp_init(-3, 10), $b); return new NamedCurveFp(self::NAME_P521, $parameters, $this->adapter); } /** * Returns an NIST P-521 generator. * * @param RandomNumberGeneratorInterface $randomGenerator * @return GeneratorPoint */ public function generator521(RandomNumberGeneratorInterface $randomGenerator = null): GeneratorPoint { $curve = $this->curve521(); $order = gmp_init('6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449', 10); $x = gmp_init('0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66', 16); $y = gmp_init('0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650', 16); return $curve->getGenerator($x, $y, $order, $randomGenerator); } } vendor/mdanter/ecc/src/Curves/SecgCurve.php000064400000016550150736751610014704 0ustar00adapter = $adapter; } /** * @return NamedCurveFp */ public function curve112r1(): NamedCurveFp { $p = gmp_init('0xDB7C2ABF62E35E668076BEAD208B', 16); $a = gmp_init('0xDB7C2ABF62E35E668076BEAD2088', 16); $b = gmp_init('0x659EF8BA043916EEDE8911702B22', 16); $parameters = new CurveParameters(112, $p, $a, $b); return new NamedCurveFp(self::NAME_SECP_112R1, $parameters, $this->adapter); } /** * @param RandomNumberGeneratorInterface $randomGenerator * @return GeneratorPoint */ public function generator112r1(RandomNumberGeneratorInterface $randomGenerator = null): GeneratorPoint { $curve = $this->curve112r1(); $order = gmp_init('0xDB7C2ABF62E35E7628DFAC6561C5', 16); $x = gmp_init('0x09487239995A5EE76B55F9C2F098', 16); $y = gmp_init('0xA89CE5AF8724C0A23E0E0FF77500', 16); return $curve->getGenerator($x, $y, $order, $randomGenerator); } /** * @return NamedCurveFp */ public function curve192k1(): NamedCurveFp { $p = gmp_init('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37', 16); $a = gmp_init(0, 10); $b = gmp_init(3, 10); $parameters = new CurveParameters(192, $p, $a, $b); return new NamedCurveFp(self::NAME_SECP_192K1, $parameters, $this->adapter); } /** * @param RandomNumberGeneratorInterface $randomGenerator * @return \Mdanter\Ecc\Primitives\GeneratorPoint */ public function generator192k1(RandomNumberGeneratorInterface $randomGenerator = null): GeneratorPoint { $curve = $this->curve192k1(); $order = gmp_init('0xFFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D', 16); $x = gmp_init('0xDB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D', 16); $y = gmp_init('0x9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D', 16); return $curve->getGenerator($x, $y, $order, $randomGenerator); } /** * @return NamedCurveFp */ public function curve256k1(): NamedCurveFp { $p = gmp_init('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F', 16); $a = gmp_init(0, 10); $b = gmp_init(7, 10); $parameters = new CurveParameters(256, $p, $a, $b); return new NamedCurveFp(self::NAME_SECP_256K1, $parameters, $this->adapter); } /** * @param RandomNumberGeneratorInterface $randomGenerator * @return GeneratorPoint */ public function generator256k1(RandomNumberGeneratorInterface $randomGenerator = null): GeneratorPoint { $curve = $this->curve256k1(); $order = gmp_init('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141', 16); $x = gmp_init('0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798', 16); $y = gmp_init('0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8', 16); return $curve->getGenerator($x, $y, $order, $randomGenerator); } /** * @return NamedCurveFp */ public function curve256r1(): NamedCurveFp { $p = gmp_init('0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF', 16); $a = gmp_init('0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC', 16); $b = gmp_init('0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B', 16); $parameters = new CurveParameters(256, $p, $a, $b); return new NamedCurveFp(self::NAME_SECP_256R1, $parameters, $this->adapter); } /** * @param RandomNumberGeneratorInterface $randomGenerator * @return GeneratorPoint */ public function generator256r1(RandomNumberGeneratorInterface $randomGenerator = null): GeneratorPoint { $curve = $this->curve256r1(); $order = gmp_init('0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551', 16); $x = gmp_init('0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296', 16); $y = gmp_init('0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5', 16); return $curve->getGenerator($x, $y, $order, $randomGenerator); } /** * @return NamedCurveFp */ public function curve384r1(): NamedCurveFp { $p = gmp_init('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF', 16); $a = gmp_init('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC', 16); $b = gmp_init('0xB3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF', 16); $parameters = new CurveParameters(384, $p, $a, $b); return new NamedCurveFp(self::NAME_SECP_384R1, $parameters, $this->adapter); } /** * @param RandomNumberGeneratorInterface $randomGenerator * @return GeneratorPoint */ public function generator384r1(RandomNumberGeneratorInterface $randomGenerator = null): GeneratorPoint { $curve = $this->curve384r1(); $order = gmp_init('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973', 16); $x = gmp_init('0xAA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7', 16); $y = gmp_init('0x3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F', 16); return $curve->getGenerator($x, $y, $order, $randomGenerator); } } vendor/mdanter/ecc/src/EccFactory.php000064400000005103150736751610013561 0ustar00G = $G; $this->point = $point; parent::__construct($message, $code, $previous); } public function getGenerator(): GeneratorPoint { return $this->G; } public function getPoint(): PointInterface { return $this->point; } } vendor/mdanter/ecc/src/Exception/SignatureDecodeException.php000064400000000201150736751610020413 0ustar00curveName = $curveName; return $this; } public function setOid(string $oid) { $this->oid = $oid; return $this; } public function hasCurveName(): bool { return is_string($this->curveName); } public function hasOid(): bool { return is_string($this->oid); } public function getCurveName(): string { return $this->curveName; } public function getOid(): string { return $this->oid; } } vendor/mdanter/ecc/src/Math/DebugDecorator.php000064400000030705150736751610015327 0ustar00adapter = $adapter; $this->writer = $callback ?: function ($message) { echo $message; }; } /** * * @param string $message */ private function write($message) { call_user_func($this->writer, $message); } /** * * @param string $func * @param array $args * @return mixed */ private function call($func, $args) { $strArgs = array_map( function ($arg) { if ($arg instanceof \GMP) { return var_export($this->adapter->toString($arg), true); } else { return var_export($arg, true); } }, $args ); if (strpos($func, '::')) { list(, $func) = explode('::', $func); } $this->write($func.'('.implode(', ', $strArgs).')'); $res = call_user_func_array([ $this->adapter, $func ], $args); if ($res instanceof \GMP) { $this->write(' => ' . var_export($this->adapter->toString($res), true) . PHP_EOL); } else { $this->write(' => ' . var_export($res, true) . PHP_EOL); } return $res; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::cmp() */ public function cmp(\GMP $first, \GMP $other): int { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::cmp() */ public function equals(\GMP $first, \GMP $other): bool { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::mod() */ public function mod(\GMP $number, \GMP $modulus): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::add() */ public function add(\GMP $augend, \GMP $addend): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::sub() */ public function sub(\GMP $minuend, \GMP $subtrahend): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::mul() */ public function mul(\GMP $multiplier, \GMP $multiplicand): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::div() */ public function div(\GMP $dividend, \GMP $divisor): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::pow() */ public function pow(\GMP $base, int $exponent): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::bitwiseAnd() */ public function bitwiseAnd(\GMP $first, \GMP $other): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\MathAdapter::toString() */ public function toString(\GMP $value): string { return $this->adapter->toString($value); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::hexDec() */ public function hexDec(string $hexString): string { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::decHex() */ public function decHex(string $decString): string { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::powmod() */ public function powmod(\GMP $base, \GMP $exponent, \GMP $modulus): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::isPrime() */ public function isPrime(\GMP $n): bool { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::nextPrime() */ public function nextPrime(\GMP $currentPrime): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::inverseMod() */ public function inverseMod(\GMP $a, \GMP $m): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::jacobi() */ public function jacobi(\GMP $a, \GMP $p): int { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::intToString() */ public function intToFixedSizeString(\GMP $x, int $byteSize): string { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::intToString() */ public function intToString(\GMP $x): string { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::stringToInt() */ public function stringToInt(string $s): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::digestInteger() */ public function digestInteger(\GMP $m): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::gcd2() */ public function gcd2(\GMP $a, \GMP $m): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::rightShift() */ public function rightShift(\GMP $number, int $positions): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::leftShift() */ public function leftShift(\GMP $number, int $positions): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call', ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::bitwiseXor() */ public function bitwiseXor(\GMP $first, \GMP $other): \GMP { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call' ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::baseConvert() */ public function baseConvert(string $value, int $fromBase, int $toBase): string { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call' ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::getEcMath() */ public function getEcMath(GeneratorPoint $generatorPoint, $input) { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call' ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::getModularArithmetic() */ public function getModularArithmetic(\GMP $modulus): ModularArithmetic { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call' ), $func, $args ); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Math\GmpMathInterface::getNumberTheory() */ public function getNumberTheory(): NumberTheory { $func = __METHOD__; $args = func_get_args(); return call_user_func( array( $this, 'call' ), $func, $args ); } } vendor/mdanter/ecc/src/Math/GmpMath.php000064400000016724150736751610014000 0ustar00cmp($exponent, gmp_init(0, 10)) < 0) { throw new \InvalidArgumentException("Negative exponents (" . $this->toString($exponent) . ") not allowed."); } return gmp_powm($base, $exponent, $modulus); } /** * {@inheritDoc} * @see GmpMathInterface::isPrime() */ public function isPrime(\GMP $n): bool { $prob = gmp_prob_prime($n); if ($prob > 0) { return true; } return false; } /** * {@inheritDoc} * @see GmpMathInterface::nextPrime() */ public function nextPrime(\GMP $starting_value): \GMP { return gmp_nextprime($starting_value); } /** * {@inheritDoc} * @see GmpMathInterface::inverseMod() */ public function inverseMod(\GMP $a, \GMP $m): \GMP { return gmp_invert($a, $m); } /** * {@inheritDoc} * @see GmpMathInterface::jacobi() */ public function jacobi(\GMP $a, \GMP $n): int { return gmp_jacobi($a, $n); } /** * @param \GMP $x * @param int $byteSize * @return string */ public function intToFixedSizeString(\GMP $x, int $byteSize): string { if ($byteSize < 0) { throw new \RuntimeException("Byte size cannot be negative"); } if (gmp_cmp($x, 0) < 0) { throw new \RuntimeException("x was negative - not yet supported"); } $two = gmp_init(2); $range = gmp_pow($two, $byteSize * 8); if (NumberSize::bnNumBits($this, $x) >= NumberSize::bnNumBits($this, $range)) { throw new \RuntimeException("Number overflows byte size"); } $maskShift = gmp_pow($two, 8); $mask = gmp_mul(gmp_init(255), $range); $binary = ''; for ($i = $byteSize - 1; $i >= 0; $i--) { $mask = gmp_div($mask, $maskShift); $binary .= pack('C', gmp_strval(gmp_div(gmp_and($x, $mask), gmp_pow($two, $i * 8)), 10)); } return $binary; } /** * {@inheritDoc} * @see GmpMathInterface::intToString() */ public function intToString(\GMP $x): string { if (gmp_cmp($x, 0) < 0) { throw new \InvalidArgumentException('Unable to convert negative integer to string'); } $hex = gmp_strval($x, 16); if (BinaryString::length($hex) % 2 != 0) { $hex = '0'.$hex; } return pack('H*', $hex); } /** * {@inheritDoc} * @see GmpMathInterface::stringToInt() */ public function stringToInt(string $s): \GMP { $result = gmp_init(0, 10); $sLen = BinaryString::length($s); for ($c = 0; $c < $sLen; $c ++) { $result = gmp_add(gmp_mul(256, $result), gmp_init(ord($s[$c]), 10)); } return $result; } /** * {@inheritDoc} * @see GmpMathInterface::digestInteger() */ public function digestInteger(\GMP $m): \GMP { return $this->stringToInt(hash('sha1', $this->intToString($m), true)); } /** * {@inheritDoc} * @see GmpMathInterface::gcd2() */ public function gcd2(\GMP $a, \GMP $b): \GMP { while ($this->cmp($a, gmp_init(0)) > 0) { $temp = $a; $a = $this->mod($b, $a); $b = $temp; } return $b; } /** * {@inheritDoc} * @see GmpMathInterface::baseConvert() */ public function baseConvert(string $number, int $from, int $to): string { return gmp_strval(gmp_init($number, $from), $to); } /** * {@inheritDoc} * @see GmpMathInterface::getNumberTheory() */ public function getNumberTheory(): NumberTheory { return new NumberTheory($this); } /** * @param \GMP $modulus * @return ModularArithmetic */ public function getModularArithmetic(\GMP $modulus): ModularArithmetic { return new ModularArithmetic($this, $modulus); } } vendor/mdanter/ecc/src/Math/GmpMathInterface.php000064400000012153150736751610015611 0ustar00adapter = $adapter; $this->modulus = $modulus; } /** * @param \GMP $augend * @param \GMP $addend * @return \GMP */ public function add(\GMP $augend, \GMP $addend): \GMP { return $this->adapter->mod($this->adapter->add($augend, $addend), $this->modulus); } /** * @param \GMP $minuend * @param \GMP $subtrahend * @return \GMP */ public function sub(\GMP $minuend, \GMP $subtrahend): \GMP { return $this->adapter->mod($this->adapter->sub($minuend, $subtrahend), $this->modulus); } /** * @param \GMP $multiplier * @param \GMP $muliplicand * @return \GMP */ public function mul(\GMP $multiplier, \GMP $muliplicand): \GMP { return $this->adapter->mod($this->adapter->mul($multiplier, $muliplicand), $this->modulus); } /** * @param \GMP $dividend * @param \GMP $divisor * @return \GMP */ public function div(\GMP $dividend, \GMP $divisor): \GMP { return $this->mul($dividend, $this->adapter->inverseMod($divisor, $this->modulus)); } /** * @param \GMP $base * @param \GMP $exponent * @return \GMP */ public function pow(\GMP $base, \GMP $exponent): \GMP { return $this->adapter->powmod($base, $exponent, $this->modulus); } } vendor/mdanter/ecc/src/Math/NumberTheory.php000064400000021351150736751610015056 0ustar00adapter = $adapter; $this->zero = gmp_init(0, 10); $this->one = gmp_init(1, 10); $this->two = gmp_init(2, 10); } /** * @param \GMP[] $poly * @param \GMP[] $polymod * @param \GMP $p * @return \GMP[] */ public function polynomialReduceMod(array $poly, array $polymod, \GMP $p): array { $adapter = $this->adapter; // Only enter if last value is set, implying count > 0 if ((($last = end($polymod)) instanceof \GMP) && $adapter->equals($last, $this->one)) { $count_polymod = count($polymod); while (count($poly) >= $count_polymod) { if (!$adapter->equals(end($poly), $this->zero)) { for ($i = 2; $i < $count_polymod + 1; $i++) { $poly[count($poly) - $i] = $adapter->mod( $adapter->sub( $poly[count($poly) - $i], $adapter->mul( end($poly), $polymod[$count_polymod - $i] ) ), $p ); } } $poly = array_slice($poly, 0, count($poly) - 1); } return $poly; } throw new NumberTheoryException('Unable to calculate polynomialReduceMod'); } /** * @param \GMP[] $m1 * @param \GMP[] $m2 * @param \GMP[] $polymod * @param \GMP $p * @return \GMP[] */ public function polynomialMultiplyMod(array $m1, array $m2, array $polymod, \GMP $p): array { $prod = array(); $cm1 = count($m1); $cm2 = count($m2); for ($i = 0; $i < $cm1; $i++) { for ($j = 0; $j < $cm2; $j++) { $index = $i + $j; if (!isset($prod[$index])) { $prod[$index] = $this->zero; } $prod[$index] = $this->adapter->mod( $this->adapter->add( $prod[$index], $this->adapter->mul( $m1[$i], $m2[$j] ) ), $p ); } } return $this->polynomialReduceMod($prod, $polymod, $p); } /** * @param \GMP[] $base * @param \GMP $exponent * @param \GMP[] $polymod * @param \GMP $p * @return \GMP[] */ public function polynomialPowMod(array $base, \GMP $exponent, array $polymod, \GMP $p): array { $adapter = $this->adapter; if ($adapter->cmp($exponent, $p) < 0) { if ($adapter->equals($exponent, $this->zero)) { return $this->one; } $G = $base; $k = $exponent; if ($adapter->equals($adapter->mod($k, $this->two), $this->one)) { $s = $G; } else { $s = array($this->one); } while ($adapter->cmp($k, $this->one) > 0) { $k = $adapter->div($k, $this->two); $G = $this->polynomialMultiplyMod($G, $G, $polymod, $p); if ($adapter->equals($adapter->mod($k, $this->two), $this->one)) { $s = $this->polynomialMultiplyMod($G, $s, $polymod, $p); } } return $s; } throw new NumberTheoryException('Unable to calculate polynomialPowMod'); } /** * @param \GMP $a * @param \GMP $p * @return \GMP */ public function squareRootModP(\GMP $a, \GMP $p): \GMP { $math = $this->adapter; $four = gmp_init(4, 10); $eight = gmp_init(8, 10); $modMath = $math->getModularArithmetic($p); if ($math->cmp($this->one, $p) < 0) { if ($math->equals($a, $this->zero)) { return $this->zero; } if ($math->equals($p, $this->two)) { return $a; } $jac = $math->jacobi($a, $p); if ($jac === -1) { throw new SquareRootException("{$math->toString($a)} has no square root modulo {$math->toString($p)}"); } if ($math->equals($math->mod($p, $four), gmp_init(3, 10))) { return $modMath->pow($a, $math->div($math->add($p, $this->one), $four)); } if ($math->equals($math->mod($p, $eight), gmp_init(5, 10))) { $d = $modMath->pow($a, $math->div($math->sub($p, $this->one), $four)); if ($math->equals($d, $this->one)) { return $modMath->pow($a, $math->div($math->add($p, gmp_init(3, 10)), $eight)); } if ($math->equals($d, $math->sub($p, $this->one))) { return $modMath->mul( $math->mul( $this->two, $a ), $modMath->pow( $math->mul( $four, $a ), $math->div( $math->sub( $p, gmp_init(5, 10) ), $eight ) ) ); } //shouldn't get here } for ($b = $this->two; $math->cmp($b, $p) < 0; $b = gmp_add($b, $this->one)) { if ($math->jacobi( $math->sub( $math->mul($b, $b), $math->mul($four, $a) ), $p ) == -1 ) { $f = array($a, $math->sub($this->zero, $b), $this->one); $ff = $this->polynomialPowMod( array($this->zero, $this->one), $math->div( $math->add( $p, $this->one ), $this->two ), $f, $p ); if ($math->equals($ff[1], $this->zero)) { return $ff[0]; } // if we got here no b was found } } } throw new SquareRootException('Unable to calculate square root mod p!'); } } vendor/mdanter/ecc/src/Primitives/CurveFp.php000064400000015647150736751610015262 0ustar00parameters = $parameters; $this->adapter = $adapter; $this->modAdapter = new ModularArithmetic($this->adapter, $this->parameters->getPrime()); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\CurveFpInterface::getModAdapter() */ public function getModAdapter(): ModularArithmetic { return $this->modAdapter; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\CurveFpInterface::getPoint() */ public function getPoint(\GMP $x, \GMP $y, \GMP $order = null): PointInterface { return new Point($this->adapter, $this, $x, $y, $order); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\CurveFpInterface::getInfinity() */ public function getInfinity(): PointInterface { return new Point($this->adapter, $this, gmp_init(0, 10), gmp_init(0, 10), null, true); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\CurveFpInterface::getGenerator() */ public function getGenerator(\GMP $x, \GMP $y, \GMP $order, RandomNumberGeneratorInterface $randomGenerator = null): GeneratorPoint { return new GeneratorPoint($this->adapter, $this, $x, $y, $order, $randomGenerator); } /** * @param bool $wasOdd * @param \GMP $xCoord * @return \GMP */ public function recoverYfromX(bool $wasOdd, \GMP $xCoord): \GMP { $math = $this->adapter; $prime = $this->getPrime(); try { $root = $this->adapter->getNumberTheory()->squareRootModP( $math->add( $math->add( $this->modAdapter->pow($xCoord, gmp_init(3, 10)), $math->mul($this->getA(), $xCoord) ), $this->getB() ), $prime ); } catch (SquareRootException $e) { throw new PointRecoveryException("Failed to recover y coordinate for point", 0, $e); } if ($math->equals($math->mod($root, gmp_init(2, 10)), gmp_init(1)) === $wasOdd) { return $root; } else { return $math->sub($prime, $root); } } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\CurveFpInterface::contains() */ public function contains(\GMP $x, \GMP $y): bool { $math = $this->adapter; $eq_zero = $math->equals( $this->modAdapter->sub( $math->pow($y, 2), $math->add( $math->add( $math->pow($x, 3), $math->mul($this->getA(), $x) ), $this->getB() ) ), gmp_init(0, 10) ); return $eq_zero; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\CurveFpInterface::getA() */ public function getA(): \GMP { return $this->parameters->getA(); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\CurveFpInterface::getB() */ public function getB(): \GMP { return $this->parameters->getB(); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\CurveFpInterface::getPrime() */ public function getPrime(): \GMP { return $this->parameters->getPrime(); } /** * @return int */ public function getSize(): int { return $this->parameters->getSize(); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\CurveFpInterface::cmp() */ public function cmp(CurveFpInterface $other): int { $math = $this->adapter; $equal = $math->equals($this->getA(), $other->getA()); $equal &= $math->equals($this->getB(), $other->getB()); $equal &= $math->equals($this->getPrime(), $other->getPrime()); return ($equal) ? 0 : 1; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\CurveFpInterface::equals() */ public function equals(CurveFpInterface $other): bool { return $this->cmp($other) == 0; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\CurveFpInterface::__toString() */ public function __toString(): string { return 'curve(' . $this->adapter->toString($this->getA()) . ', ' . $this->adapter->toString($this->getB()) . ', ' . $this->adapter->toString($this->getPrime()) . ')'; } /** * @return array */ public function __debugInfo() { return [ 'a' => $this->adapter->toString($this->getA()), 'b' => $this->adapter->toString($this->getB()), 'prime' => $this->adapter->toString($this->getPrime()) ]; } } vendor/mdanter/ecc/src/Primitives/CurveFpInterface.php000064400000007435150736751610017077 0ustar00 0 if $this > $other */ public function cmp(CurveFpInterface $other): int; /** * Checks whether the curve is equal to another. * * @param CurveFpInterface $other * @return bool */ public function equals(CurveFpInterface $other): bool; /** * Return string representation of curve for debugging * * @return string */ public function __toString(): string; } vendor/mdanter/ecc/src/Primitives/CurveParameters.php000064400000002272150736751610017006 0ustar00size = $size; $this->prime = $prime; $this->a = $a; $this->b = $b; } /** * @return \GMP */ public function getA(): \GMP { return $this->a; } /** * @return \GMP */ public function getB(): \GMP { return $this->b; } /** * @return \GMP */ public function getPrime(): \GMP { return $this->prime; } /** * @return int */ public function getSize(): int { return $this->size; } } vendor/mdanter/ecc/src/Primitives/GeneratorPoint.php000064400000005647150736751610016647 0ustar00generator = $generator ?: RandomGeneratorFactory::getRandomGenerator(); parent::__construct($adapter, $curve, $x, $y, $order); } /** * Verifies validity of given coordinates against the current point and its point. * * @todo Check if really necessary here (only used for testing in lib) * @param \GMP $x * @param \GMP $y * @return bool */ public function isValid(\GMP $x, \GMP $y): bool { $math = $this->getAdapter(); $n = $this->getOrder(); $zero = gmp_init(0, 10); $curve = $this->getCurve(); if ($math->cmp($x, $zero) < 0 || $math->cmp($n, $x) <= 0 || $math->cmp($y, $zero) < 0 || $math->cmp($n, $y) <= 0) { return false; } if (! $curve->contains($x, $y)) { return false; } $point = $curve->getPoint($x, $y)->mul($n); if (! $point->isInfinity()) { return false; } return true; } /** * @return PrivateKeyInterface */ public function createPrivateKey(): PrivateKeyInterface { $secret = $this->generator->generate($this->getOrder()); return new PrivateKey($this->getAdapter(), $this, $secret); } /** * @param \GMP $x * @param \GMP $y * @return PublicKeyInterface */ public function getPublicKeyFrom(\GMP $x, \GMP $y): PublicKeyInterface { $pubPoint = $this->getCurve()->getPoint($x, $y, $this->getOrder()); return new PublicKey($this->getAdapter(), $this, $pubPoint); } /** * @param \GMP $secretMultiplier * @return PrivateKeyInterface */ public function getPrivateKeyFrom(\GMP $secretMultiplier): PrivateKeyInterface { return new PrivateKey($this->getAdapter(), $this, $secretMultiplier); } } vendor/mdanter/ecc/src/Primitives/Point.php000064400000026377150736751610015003 0ustar00adapter = $adapter; $this->modAdapter = $curve->getModAdapter(); $this->curve = $curve; $this->x = $x; $this->y = $y; $this->order = $order !== null ? $order : gmp_init(0, 10); $this->infinity = (bool) $infinity; if (! $infinity && ! $curve->contains($x, $y)) { throw new PointNotOnCurveException($x, $y, $curve); } if (!is_null($order)) { $mul = $this->mul($order); if (!$mul->isInfinity()) { throw new PointException("SELF * ORDER MUST EQUAL INFINITY. (" . (string)$mul . " found instead)"); } } } /** * @return GmpMathInterface */ public function getAdapter(): GmpMathInterface { return $this->adapter; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\PointInterface::isInfinity() */ public function isInfinity(): bool { return (bool) $this->infinity; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\PointInterface::getCurve() */ public function getCurve(): CurveFpInterface { return $this->curve; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\PointInterface::getOrder() */ public function getOrder(): \GMP { return $this->order; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\PointInterface::getX() */ public function getX(): \GMP { return $this->x; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\PointInterface::getY() */ public function getY(): \GMP { return $this->y; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\PointInterface::add() * @return self */ public function add(PointInterface $addend): PointInterface { if (! $this->curve->equals($addend->getCurve())) { throw new \RuntimeException("The Elliptic Curves do not match."); } if ($addend->isInfinity()) { return clone $this; } if ($this->isInfinity()) { return clone $addend; } $math = $this->adapter; $modMath = $this->modAdapter; if ($math->equals($addend->getX(), $this->x)) { if ($math->equals($addend->getY(), $this->y)) { return $this->getDouble(); } else { return $this->curve->getInfinity(); } } $slope = $modMath->div( $math->sub($addend->getY(), $this->y), $math->sub($addend->getX(), $this->x) ); $xR = $modMath->sub( $math->sub($math->pow($slope, 2), $this->x), $addend->getX() ); $yR = $modMath->sub( $math->mul($slope, $math->sub($this->x, $xR)), $this->y ); return $this->curve->getPoint($xR, $yR, $this->order); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\PointInterface::cmp() */ public function cmp(PointInterface $other): int { if ($other->isInfinity() && $this->isInfinity()) { return 0; } if ($other->isInfinity() || $this->isInfinity()) { return 1; } $math = $this->adapter; $equal = ($math->equals($this->x, $other->getX())); $equal &= ($math->equals($this->y, $other->getY())); $equal &= $this->isInfinity() == $other->isInfinity(); $equal &= $this->curve->equals($other->getCurve()); if ($equal) { return 0; } return 1; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\PointInterface::equals() */ public function equals(PointInterface $other): bool { return $this->cmp($other) == 0; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\PointInterface::mul() */ public function mul(\GMP $n): PointInterface { if ($this->isInfinity()) { return $this->curve->getInfinity(); } $zero = gmp_init(0, 10); if ($this->adapter->cmp($this->order, $zero) > 0) { $n = $this->adapter->mod($n, $this->order); } if ($this->adapter->equals($n, $zero)) { return $this->curve->getInfinity(); } /** @var Point[] $r */ $r = [ $this->curve->getInfinity(), clone $this ]; $k = $this->curve->getSize(); $n = str_pad($this->adapter->baseConvert($this->adapter->toString($n), 10, 2), $k, '0', STR_PAD_LEFT); for ($i = 0; $i < $k; $i++) { $j = $n[$i]; $this->cswap($r[0], $r[1], $j ^ 1, $k); $r[0] = $r[0]->add($r[1]); $r[1] = $r[1]->getDouble(); $this->cswap($r[0], $r[1], $j ^ 1, $k); } $r[0]->validate(); return $r[0]; } /** * @param Point $a * @param Point $b * @param int $cond * @param int $curveSize */ private function cswap(self $a, self $b, int $cond, int $curveSize) { $this->cswapValue($a->x, $b->x, $cond, $curveSize); $this->cswapValue($a->y, $b->y, $cond, $curveSize); $this->cswapValue($a->order, $b->order, $cond, $curveSize); $this->cswapValue($a->infinity, $b->infinity, $cond, 8); } /** * @param bool|\GMP $a * @param bool|\GMP $b * @param int $cond * @param int $maskBitSize */ public function cswapValue(& $a, & $b, int $cond, int $maskBitSize) { $isGMP = is_object($a) && $a instanceof \GMP; $sa = $isGMP ? $a : gmp_init(intval($a), 10); $sb = $isGMP ? $b : gmp_init(intval($b), 10); $mask = str_pad('', $maskBitSize, (string) (1 - intval($cond)), STR_PAD_LEFT); $mask = gmp_init($mask, 2); $taA = $this->adapter->bitwiseAnd($sa, $mask); $taB = $this->adapter->bitwiseAnd($sb, $mask); $sa = $this->adapter->bitwiseXor($this->adapter->bitwiseXor($sa, $sb), $taB); $sb = $this->adapter->bitwiseXor($this->adapter->bitwiseXor($sa, $sb), $taA); $sa = $this->adapter->bitwiseXor($this->adapter->bitwiseXor($sa, $sb), $taB); $a = $isGMP ? $sa : (bool) gmp_strval($sa, 10); $b = $isGMP ? $sb : (bool) gmp_strval($sb, 10); } /** * */ private function validate() { if (! $this->infinity && ! $this->curve->contains($this->x, $this->y)) { throw new \RuntimeException('Invalid point'); } } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\PointInterface::getDouble() * @return self */ public function getDouble(): PointInterface { if ($this->isInfinity()) { return $this->curve->getInfinity(); } $math = $this->adapter; $modMath = $this->modAdapter; $a = $this->curve->getA(); $threeX2 = $math->mul(gmp_init(3, 10), $math->pow($this->x, 2)); $tangent = $modMath->div( $math->add($threeX2, $a), $math->mul(gmp_init(2, 10), $this->y) ); $x3 = $modMath->sub( $math->pow($tangent, 2), $math->mul(gmp_init(2, 10), $this->x) ); $y3 = $modMath->sub( $math->mul($tangent, $math->sub($this->x, $x3)), $this->y ); return $this->curve->getPoint($x3, $y3, $this->order); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Primitives\PointInterface::__toString() */ public function __toString(): string { if ($this->infinity) { return '[ (infinity) on ' . (string) $this->curve . ' ]'; } return "[ (" . $this->adapter->toString($this->x) . "," . $this->adapter->toString($this->y) . ') on ' . (string) $this->curve . ' ]'; } /** * @return array */ public function __debugInfo(): array { $info = [ 'x' => $this->adapter->toString($this->x), 'y' => $this->adapter->toString($this->y), 'z' => $this->adapter->toString($this->order), 'curve' => $this->curve ]; if ($this->infinity) { $info['x'] = 'inf (' . $info['x'] . ')'; $info['y'] = 'inf (' . $info['y'] . ')'; $info['z'] = 'inf (' . $info['z'] . ')'; } return $info; } } vendor/mdanter/ecc/src/Primitives/PointInterface.php000064400000007542150736751610016615 0ustar00generator = $generator; $this->generatorName = $name; } /** * @param \GMP $max * @return \GMP */ public function generate(\GMP $max): \GMP { echo $this->generatorName.'::rand() = '; $result = $this->generator->generate($max); echo gmp_strval($result, 10).PHP_EOL; return $result; } } vendor/mdanter/ecc/src/Random/HmacRandomNumberGenerator.php000064400000010414150736751610020011 0ustar00 160, 'sha224' => 224, 'sha256' => 256, 'sha384' => 384, 'sha512' => 512 ); /** * Hmac constructor. * @param GmpMathInterface $math * @param PrivateKeyInterface $privateKey * @param \GMP $messageHash - decimal hash of the message (*may* be truncated) * @param string $algorithm - hashing algorithm */ public function __construct(GmpMathInterface $math, PrivateKeyInterface $privateKey, \GMP $messageHash, string $algorithm) { if (!isset($this->algSize[$algorithm])) { throw new \InvalidArgumentException('Unsupported hashing algorithm'); } $this->math = $math; $this->algorithm = $algorithm; $this->privateKey = $privateKey; $this->messageHash = $messageHash; } /** * @param string $bits - binary string of bits * @param \GMP $qlen - length of q in bits * @return \GMP */ public function bits2int(string $bits, \GMP $qlen): \GMP { $vlen = gmp_init(BinaryString::length($bits) * 8, 10); $hex = bin2hex($bits); $v = gmp_init($hex, 16); if ($this->math->cmp($vlen, $qlen) > 0) { $v = $this->math->rightShift($v, (int) $this->math->toString($this->math->sub($vlen, $qlen))); } return $v; } /** * @param \GMP $int * @param \GMP $rlen - rounded octet length * @return string */ public function int2octets(\GMP $int, \GMP $rlen): string { $out = pack("H*", $this->math->decHex(gmp_strval($int, 10))); $length = gmp_init(BinaryString::length($out), 10); if ($this->math->cmp($length, $rlen) < 0) { return str_pad('', (int) $this->math->toString($this->math->sub($rlen, $length)), "\x00") . $out; } if ($this->math->cmp($length, $rlen) > 0) { return BinaryString::substring($out, 0, (int) $this->math->toString($rlen)); } return $out; } /** * @param string $algorithm * @return int */ private function getHashLength(string $algorithm): int { return $this->algSize[$algorithm]; } /** * @param \GMP $q * @return \GMP */ public function generate(\GMP $q): \GMP { $qlen = gmp_init(NumberSize::bnNumBits($this->math, $q), 10); $rlen = $this->math->rightShift($this->math->add($qlen, gmp_init(7, 10)), 3); $hlen = $this->getHashLength($this->algorithm); $bx = $this->int2octets($this->privateKey->getSecret(), $rlen) . $this->int2octets($this->messageHash, $rlen); $v = str_pad('', $hlen >> 3, "\x01", STR_PAD_LEFT); $k = str_pad('', $hlen >> 3, "\x00", STR_PAD_LEFT); $k = hash_hmac($this->algorithm, $v . "\x00" . $bx, $k, true); $v = hash_hmac($this->algorithm, $v, $k, true); $k = hash_hmac($this->algorithm, $v . "\x01" . $bx, $k, true); $v = hash_hmac($this->algorithm, $v, $k, true); $t = ''; for (;;) { $toff = gmp_init(0, 10); while ($this->math->cmp($toff, $rlen) < 0) { $v = hash_hmac($this->algorithm, $v, $k, true); $cc = min(BinaryString::length($v), (int) gmp_strval(gmp_sub($rlen, $toff), 10)); $t .= BinaryString::substring($v, 0, $cc); $toff = gmp_add($toff, $cc); } $k = $this->bits2int($t, $qlen); if ($this->math->cmp($k, gmp_init(0, 10)) > 0 && $this->math->cmp($k, $q) < 0) { return $k; } $k = hash_hmac($this->algorithm, $v . "\x00", $k, true); $v = hash_hmac($this->algorithm, $v, $k, true); } } } vendor/mdanter/ecc/src/Random/RandomGeneratorFactory.php000064400000003501150736751610017376 0ustar00adapter = $adapter; } /** * @param \GMP $max * @return \GMP */ public function generate(\GMP $max): \GMP { $numBits = NumberSize::bnNumBits($this->adapter, $max); $numBytes = (int) ceil($numBits / 8); // Generate an integer of size >= $numBits $bytes = random_bytes($numBytes); $value = $this->adapter->stringToInt($bytes); $mask = gmp_sub(gmp_pow(2, $numBits), 1); $integer = gmp_and($value, $mask); return $integer; } } vendor/mdanter/ecc/src/Random/RandomNumberGeneratorInterface.php000064400000000477150736751610021051 0ustar00adapter = $adapter; $this->theory = $adapter->getNumberTheory(); } /** * @param PointInterface $point * @return string */ public function getPrefix(PointInterface $point): string { if ($this->adapter->equals($this->adapter->mod($point->getY(), gmp_init(2, 10)), gmp_init(0))) { return '02'; } else { return '03'; } } /** * @param PointInterface $point * @return string */ public function serialize(PointInterface $point): string { $length = CurveOidMapper::getByteSize($point->getCurve()) * 2; $hexString = $this->getPrefix($point); $hexString .= str_pad(gmp_strval($point->getX(), 16), $length, '0', STR_PAD_LEFT); return $hexString; } /** * @param CurveFpInterface $curve * @param string $data - hex serialized compressed point * @return PointInterface */ public function unserialize(CurveFpInterface $curve, string $data): PointInterface { $prefix = substr($data, 0, 2); if ($prefix !== '03' && $prefix !== '02') { throw new \InvalidArgumentException('Invalid data: only compressed keys are supported.'); } $x = gmp_init(substr($data, 2), 16); $y = $curve->recoverYfromX($prefix === '03', $x); return $curve->getPoint($x, $y); } } vendor/mdanter/ecc/src/Serializer/Point/PointSerializerInterface.php000064400000001133150736751610021704 0ustar00getCurve()) * 2; $hexString = '04'; $hexString .= str_pad(gmp_strval($point->getX(), 16), $length, '0', STR_PAD_LEFT); $hexString .= str_pad(gmp_strval($point->getY(), 16), $length, '0', STR_PAD_LEFT); return $hexString; } /** * @param CurveFpInterface $curve * @param string $data * @return PointInterface */ public function unserialize(CurveFpInterface $curve, string $data): PointInterface { if (BinaryString::substring($data, 0, 2) != '04') { throw new \InvalidArgumentException('Invalid data: only uncompressed keys are supported.'); } $data = BinaryString::substring($data, 2); $dataLength = BinaryString::length($data); $x = gmp_init(BinaryString::substring($data, 0, $dataLength / 2), 16); $y = gmp_init(BinaryString::substring($data, $dataLength / 2), 16); return $curve->getPoint($x, $y); } } vendor/mdanter/ecc/src/Serializer/PrivateKey/DerPrivateKeySerializer.php000064400000006461150736751610022513 0ustar00adapter = $adapter ?: MathAdapterFactory::getAdapter(); $this->pubKeySerializer = $pubKeySerializer ?: new DerPublicKeySerializer($this->adapter); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Serializer\PrivateKey\PrivateKeySerializerInterface::serialize() */ public function serialize(PrivateKeyInterface $key): string { // CurveOidMapper::getCurveOid($key->getPoint()->getCurve()); // die(); $privateKeyInfo = new Sequence( new Integer(self::VERSION), new OctetString($this->formatKey($key)), new ExplicitlyTaggedObject(0, CurveOidMapper::getCurveOid($key->getPoint()->getCurve())), new ExplicitlyTaggedObject(1, $this->encodePubKey($key)) ); return $privateKeyInfo->getBinary(); } /** * @param PrivateKeyInterface $key * @return BitString */ private function encodePubKey(PrivateKeyInterface $key): BitString { return new BitString( $this->pubKeySerializer->getUncompressedKey($key->getPublicKey()) ); } /** * @param PrivateKeyInterface $key * @return string */ private function formatKey(PrivateKeyInterface $key): string { return gmp_strval($key->getSecret(), 16); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Serializer\PrivateKey\PrivateKeySerializerInterface::parse() * @throws \FG\ASN1\Exception\ParserException */ public function parse(string $data): PrivateKeyInterface { $asnObject = ASNObject::fromBinary($data); if (! ($asnObject instanceof Sequence) || $asnObject->getNumberofChildren() !== 4) { throw new \RuntimeException('Invalid data.'); } $children = $asnObject->getChildren(); $version = $children[0]; if ($version->getContent() != 1) { throw new \RuntimeException('Invalid data: only version 1 (RFC5915) keys are supported.'); } $key = gmp_init($children[1]->getContent(), 16); $oid = $children[2]->getContent()[0]; $generator = CurveOidMapper::getGeneratorFromOid($oid); return $generator->getPrivateKeyFrom($key); } } vendor/mdanter/ecc/src/Serializer/PrivateKey/PemPrivateKeySerializer.php000064400000003020150736751610022506 0ustar00derSerializer = $derSerializer; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Serializer\PrivateKey\PrivateKeySerializerInterface::serialize() */ public function serialize(PrivateKeyInterface $key): string { $privateKeyInfo = $this->derSerializer->serialize($key); $content = '-----BEGIN EC PRIVATE KEY-----'.PHP_EOL; $content .= trim(chunk_split(base64_encode($privateKeyInfo), 64, PHP_EOL)).PHP_EOL; $content .= '-----END EC PRIVATE KEY-----'; return $content; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Serializer\PrivateKey\PrivateKeySerializerInterface::parse() */ public function parse(string $formattedKey): PrivateKeyInterface { $formattedKey = str_replace('-----BEGIN EC PRIVATE KEY-----', '', $formattedKey); $formattedKey = str_replace('-----END EC PRIVATE KEY-----', '', $formattedKey); $data = base64_decode($formattedKey); return $this->derSerializer->parse($data); } } vendor/mdanter/ecc/src/Serializer/PrivateKey/PrivateKeySerializerInterface.php000064400000000746150736751610023701 0ustar00pointSerializer = $pointSerializer ?: new UncompressedPointSerializer(); } /** * @param PublicKeyInterface $key * @return string */ public function format(PublicKeyInterface $key): string { if (! ($key->getCurve() instanceof NamedCurveFp)) { throw new \RuntimeException('Not implemented for unnamed curves'); } $sequence = new Sequence( new Sequence( new ObjectIdentifier(DerPublicKeySerializer::X509_ECDSA_OID), CurveOidMapper::getCurveOid($key->getCurve()) ), new BitString($this->encodePoint($key->getPoint())) ); return $sequence->getBinary(); } /** * @param PointInterface $point * @return string */ public function encodePoint(PointInterface $point): string { return $this->pointSerializer->serialize($point); } } vendor/mdanter/ecc/src/Serializer/PublicKey/Der/Parser.php000064400000006605150736751610017515 0ustar00adapter = $adapter; $this->pointSerializer = $pointSerializer ?: new UncompressedPointSerializer(); } /** * @param string $binaryData * @return PublicKeyInterface * @throws \FG\ASN1\Exception\ParserException */ public function parse(string $binaryData): PublicKeyInterface { $asnObject = ASNObject::fromBinary($binaryData); if ($asnObject->getType() !== Identifier::SEQUENCE) { throw new \RuntimeException('Invalid data.'); } /** @var Sequence $asnObject */ if ($asnObject->getNumberofChildren() != 2) { throw new \RuntimeException('Invalid data.'); } $children = $asnObject->getChildren(); if (count($children) != 2) { throw new \RuntimeException('Invalid data.'); } if (count($children) != 2) { throw new \RuntimeException('Invalid data.'); } if ($children[0]->getType() !== Identifier::SEQUENCE) { throw new \RuntimeException('Invalid data.'); } if (count($children[0]->getChildren()) != 2) { throw new \RuntimeException('Invalid data.'); } if ($children[0]->getChildren()[0]->getType() !== Identifier::OBJECT_IDENTIFIER) { throw new \RuntimeException('Invalid data.'); } if ($children[0]->getChildren()[1]->getType() !== Identifier::OBJECT_IDENTIFIER) { throw new \RuntimeException('Invalid data.'); } if ($children[1]->getType() !== Identifier::BITSTRING) { throw new \RuntimeException('Invalid data.'); } $oid = $children[0]->getChildren()[0]; $curveOid = $children[0]->getChildren()[1]; $encodedKey = $children[1]; if ($oid->getContent() !== DerPublicKeySerializer::X509_ECDSA_OID) { throw new \RuntimeException('Invalid data: non X509 data.'); } $generator = CurveOidMapper::getGeneratorFromOid($curveOid); return $this->parseKey($generator, $encodedKey->getContent()); } /** * @param GeneratorPoint $generator * @param string $data * @return PublicKeyInterface */ public function parseKey(GeneratorPoint $generator, string $data): PublicKeyInterface { $point = $this->pointSerializer->unserialize($generator->getCurve(), $data); return new PublicKey($this->adapter, $generator, $point); } } vendor/mdanter/ecc/src/Serializer/PublicKey/DerPublicKeySerializer.php000064400000003766150736751610022130 0ustar00adapter = $adapter ?: MathAdapterFactory::getAdapter(); $this->formatter = new Formatter(); $this->parser = new Parser($this->adapter, $pointSerializer ?: new UncompressedPointSerializer()); } /** * * @param PublicKeyInterface $key * @return string */ public function serialize(PublicKeyInterface $key): string { return $this->formatter->format($key); } /** * @param PublicKeyInterface $key * @return string */ public function getUncompressedKey(PublicKeyInterface $key): string { return $this->formatter->encodePoint($key->getPoint()); } /** * {@inheritDoc} * @see \Mdanter\Ecc\Serializer\PublicKey\PublicKeySerializerInterface::parse() */ public function parse(string $string): PublicKeyInterface { return $this->parser->parse($string); } } vendor/mdanter/ecc/src/Serializer/PublicKey/PemPublicKeySerializer.php000064400000002733150736751610022130 0ustar00derSerializer = $serializer; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Serializer\PublicKey\PublicKeySerializerInterface::serialize() */ public function serialize(PublicKeyInterface $key): string { $publicKeyInfo = $this->derSerializer->serialize($key); $content = '-----BEGIN PUBLIC KEY-----'.PHP_EOL; $content .= trim(chunk_split(base64_encode($publicKeyInfo), 64, PHP_EOL)).PHP_EOL; $content .= '-----END PUBLIC KEY-----'; return $content; } /** * {@inheritDoc} * @see \Mdanter\Ecc\Serializer\PublicKey\PublicKeySerializerInterface::parse() */ public function parse(string $formattedKey): PublicKeyInterface { $formattedKey = str_replace('-----BEGIN PUBLIC KEY-----', '', $formattedKey); $formattedKey = str_replace('-----END PUBLIC KEY-----', '', $formattedKey); $data = base64_decode($formattedKey); return $this->derSerializer->parse($data); } } vendor/mdanter/ecc/src/Serializer/PublicKey/PublicKeySerializerInterface.php000064400000000721150736751610023302 0ustar00getR(), 10)), new Integer(gmp_strval($signature->getS(), 10)) ); } /** * @param SignatureInterface $signature * @return string */ public function serialize(SignatureInterface $signature): string { return $this->toAsn($signature)->getBinary(); } } vendor/mdanter/ecc/src/Serializer/Signature/Der/Parser.php000064400000002563150736751610017566 0ustar00getType() !== Identifier::SEQUENCE) { throw new SignatureDecodeException('Invalid tag for sequence.'); } if ($asnObject->getNumberofChildren() !== 2) { throw new SignatureDecodeException('Invalid data.'); } if (!($asnObject[0] instanceof Integer && $asnObject[1] instanceof Integer)) { throw new SignatureDecodeException('Invalid data.'); } return new Signature( gmp_init($asnObject[0]->getContent(), 10), gmp_init($asnObject[1]->getContent(), 10) ); } } vendor/mdanter/ecc/src/Serializer/Signature/DerSignatureSerializer.php000064400000001655150736751610022247 0ustar00parser = new Der\Parser(); $this->formatter = new Der\Formatter(); } /** * @param SignatureInterface $signature * @return string */ public function serialize(SignatureInterface $signature): string { return $this->formatter->serialize($signature); } /** * @param string $binary * @return SignatureInterface * @throws \FG\ASN1\Exception\ParserException */ public function parse(string $binary): SignatureInterface { return $this->parser->parse($binary); } } vendor/mdanter/ecc/src/Serializer/Signature/DerSignatureSerializerInterface.php000064400000001013150736751610024054 0ustar00 self::NIST_P192_OID, NistCurve::NAME_P224 => self::NIST_P224_OID, NistCurve::NAME_P256 => self::NIST_P256_OID, NistCurve::NAME_P384 => self::NIST_P384_OID, NistCurve::NAME_P521 => self::NIST_P521_OID, SecgCurve::NAME_SECP_112R1 => self::SECP_112R1_OID, SecgCurve::NAME_SECP_192K1 => self::SECP_192K1_OID, SecgCurve::NAME_SECP_256K1 => self::SECP_256K1_OID, SecgCurve::NAME_SECP_256R1 => self::SECP_256R1_OID, SecgCurve::NAME_SECP_384R1 => self::SECP_384R1_OID, ); /** * @var array */ private static $sizeMap = array( NistCurve::NAME_P192 => 24, NistCurve::NAME_P224 => 28, NistCurve::NAME_P256 => 32, NistCurve::NAME_P384 => 48, NistCurve::NAME_P521 => 66, SecgCurve::NAME_SECP_112R1 => 14, SecgCurve::NAME_SECP_192K1 => 24, SecgCurve::NAME_SECP_256K1 => 32, SecgCurve::NAME_SECP_256R1 => 32, SecgCurve::NAME_SECP_384R1 => 48, ); /** * @return array */ public static function getNames(): array { return array_keys(self::$oidMap); } /** * @param CurveFpInterface $curve * @return int */ public static function getByteSize(CurveFpInterface $curve): int { if ($curve instanceof NamedCurveFp && array_key_exists($curve->getName(), self::$sizeMap)) { return self::$sizeMap[$curve->getName()]; } throw new UnsupportedCurveException('Unsupported curve type'); } /** * @param NamedCurveFp $curve * @return ObjectIdentifier */ public static function getCurveOid(NamedCurveFp $curve): ObjectIdentifier { if (array_key_exists($curve->getName(), self::$oidMap)) { $oidString = self::$oidMap[$curve->getName()]; return new ObjectIdentifier($oidString); } throw new UnsupportedCurveException('Unsupported curve type'); } /** * @param ObjectIdentifier $oid * @return NamedCurveFp */ public static function getCurveFromOid(ObjectIdentifier $oid): NamedCurveFp { $oidString = $oid->getContent(); $invertedMap = array_flip(self::$oidMap); if (array_key_exists($oidString, $invertedMap)) { return CurveFactory::getCurveByName($invertedMap[$oidString]); } $error = new UnsupportedCurveException('Invalid data: unsupported curve.'); $error->setOid($oidString); throw $error; } /** * @param ObjectIdentifier $oid * @return GeneratorPoint */ public static function getGeneratorFromOid(ObjectIdentifier $oid): GeneratorPoint { $oidString = $oid->getContent(); $invertedMap = array_flip(self::$oidMap); if (array_key_exists($oidString, $invertedMap)) { return CurveFactory::getGeneratorByName($invertedMap[$oidString]); } $error = new UnsupportedCurveException('Invalid data: unsupported generator.'); $error->setOid($oidString); throw $error; } } vendor/mdanter/ecc/src/Util/BinaryString.php000064400000003304150736751610015070 0ustar00equals($x, $zero)) { return 0; } $log2 = 0; while (false === $adapter->equals($x, $zero)) { $x = $adapter->rightShift($x, 1); $log2++; } return $log2 ; } } vendor/mdanter/ecc/validate_examples.sh000064400000000224150736751610014261 0ustar00#!/bin/bash for i in examples/*.php; do php $i if [ $? != 0 ]; then echo "Error running example code"; exit -1 fi; done