aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Zotlabs/Lib/JcsEddsa2022.php91
-rw-r--r--Zotlabs/Lib/Multibase.php34
2 files changed, 125 insertions, 0 deletions
diff --git a/Zotlabs/Lib/JcsEddsa2022.php b/Zotlabs/Lib/JcsEddsa2022.php
new file mode 100644
index 000000000..cb5462952
--- /dev/null
+++ b/Zotlabs/Lib/JcsEddsa2022.php
@@ -0,0 +1,91 @@
+<?php
+
+namespace Zotlabs\Lib;
+
+use Mmccook\JsonCanonicalizator\JsonCanonicalizatorFactory;
+use StephenHill\Base58;
+
+class JcsEddsa2022 {
+
+ public function __construct() {
+ return $this;
+ }
+
+ public function sign($data, $channel): array {
+ $base58 = new Base58();
+ $pubkey = (new Multibase())->publicKey($channel['channel_epubkey']);
+ $options = [
+ 'type' => 'DataIntegrityProof',
+ 'cryptosuite' => 'eddsa-jcs-2022',
+ 'created' => datetime_convert(format: ATOM_TIME),
+ 'verificationMethod' => channel_url($channel) . '#' . $pubkey,
+ 'proofPurpose' => 'assertionMethod',
+ ];
+
+ $optionsHash = $this->hash($this->signableOptions($options), true);
+ $dataHash = $this->hash($this->signableData($data), true);
+
+ $options['proofValue'] = 'z' . $base58->encode(sodium_crypto_sign_detached($optionsHash . $dataHash,
+ sodium_base642bin($channel['channel_eprvkey'], SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING)));
+
+ return $options;
+ }
+
+ public function verify($data, $publicKey) {
+ $base58 = new Base58();
+ $encodedSignature = $data['proof']['proofValue'] ?? '';
+ if (!str_starts_with($encodedSignature,'z')) {
+ return false;
+ }
+ $encodedSignature = substr($encodedSignature, 1);
+ $optionsHash = $this->hash($this->signableOptions($data['proof']), true);
+ $dataHash = $this->hash($this->signableData($data),true);
+
+ try {
+ $result = sodium_crypto_sign_verify_detached($base58->decode($encodedSignature), $optionsHash . $dataHash,
+ (new Multibase())->decode($publicKey, true));
+ }
+ catch (\Exception $e) {
+ logger('verify exception:' . $e->getMessage());
+ }
+
+ logger('SignatureVerify (eddsa-jcs-2022) ' . (($result) ? 'true' : 'false'));
+
+ return $result;
+ }
+
+ public function signableData($data) {
+ $signableData = [];
+ if ($data) {
+ foreach ($data as $k => $v) {
+ if ($k != 'proof') {
+ $signableData[$k] = $v;
+ }
+ }
+ }
+ return $signableData;
+ }
+
+ public function signableOptions($options) {
+ $signableOptions = [];
+
+ if ($options) {
+ foreach ($options as $k => $v) {
+ if ($k !== 'proofValue') {
+ $signableOptions[$k] = $v;
+ }
+ }
+ }
+ return $signableOptions;
+ }
+
+ public function hash($obj, $binary = false) {
+ return hash('sha256', $this->canonicalize($obj), $binary);
+ }
+
+ public function canonicalize($data) {
+ $canonicalization = JsonCanonicalizatorFactory::getInstance();
+ return $canonicalization->canonicalize($data);
+ }
+
+}
diff --git a/Zotlabs/Lib/Multibase.php b/Zotlabs/Lib/Multibase.php
new file mode 100644
index 000000000..099723630
--- /dev/null
+++ b/Zotlabs/Lib/Multibase.php
@@ -0,0 +1,34 @@
+<?php
+namespace Zotlabs\Lib;
+
+use StephenHill\Base58;
+
+class Multibase {
+
+ protected $key = null;
+
+ public function __construct() {
+ return $this;
+ }
+
+ public function publicKey($key) {
+ $base58 = new Base58();
+ $raw = hex2bin('ed01') . sodium_base642bin($key, SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING);
+ return 'z' . $base58->encode($raw);
+ }
+
+ public function secretKey($key) {
+ $base58 = new Base58();
+ $raw = hex2bin('8026') . sodium_base642bin($key, SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING);
+ return 'z' . $base58->encode($raw);
+ }
+
+ public function decode($key, $binary = false) {
+ $base58 = new Base58();
+ $key = substr($key,1);
+ $raw = $base58->decode($key);
+ $binaryKey = substr($raw, 2);
+ return $binary ? $binaryKey : sodium_bin2base64($binaryKey, SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING);
+ }
+
+}