-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathtx_msg.php
More file actions
148 lines (108 loc) · 4.53 KB
/
tx_msg.php
File metadata and controls
148 lines (108 loc) · 4.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
<?php
// Include the phpseclib library for elliptic curve operations
require_once 'vendor/autoload.php'; // Assuming phpseclib is installed using Composer
use Elliptic\EC;
function DecryptMessage(string $privateKeyHex, string $encryptedHex): string {
// strip 0x if present
if (strpos($privateKeyHex, '0x') === 0) $privateKeyHex = substr($privateKeyHex, 2);
if (strpos($encryptedHex, '0x') === 0) $encryptedHex = substr($encryptedHex, 2);
$encrypted = hex2bin($encryptedHex);
if ($encrypted === false) {
throw new \InvalidArgumentException('Invalid encrypted hex');
}
// parse components (match the python offsets)
// iv = encrypted[:16]
// ephemPubKeyEncoded = encrypted[17:81] (so byte 16 is the 0x04 prefix)
// mac = encrypted[81:113]
// ciphertext = encrypted[113:]
if (strlen($encrypted) < 113) {
throw new \InvalidArgumentException('Encrypted buffer too short '.strlen($encryptedHex).' '.strlen($encrypted) );
}
$iv = substr($encrypted, 0, 16);
$prefixByte = ord(substr($encrypted, 16, 1)); // should be 0x04
$ephemPubKeyEncoded = substr($encrypted, 17, 64); // 64 bytes: X||Y
$mac = substr($encrypted, 81, 32); // 32 bytes
$ciphertext = substr($encrypted, 113);
if ($prefixByte !== 0x04) {
// the Python code expected an uncompressed pubkey marker (0x04)
// If it's not present you may need to adapt for compressed keys.
throw new \RuntimeException('Unexpected ephemeral public key prefix (expected 0x04)');
}
// build full uncompressed public key (0x04 + X + Y) in hex
$ephemPubKeyFull = "\x04" . $ephemPubKeyEncoded;
$ephemPubKeyHex = bin2hex($ephemPubKeyFull);
// create curve object
$ec = new EC('secp256k1');
// load private key and ephemeral public key
$privKey = $ec->keyFromPrivate($privateKeyHex, 'hex');
$ephemPub = $ec->keyFromPublic($ephemPubKeyHex, 'hex');
// ECDH: derive shared secret (returns a BN-ish object in this lib)
// -> $z will be a big integer-like object; convert to hex then to binary
$z = $privKey->derive($ephemPub->getPublic()); // BN
$sharedHex = $z->toString(16);
// ensure even length hex
if (strlen($sharedHex) % 2 !== 0) $sharedHex = '0' . $sharedHex;
$px = hex2bin($sharedHex);
// Derive keys: SHA512(px) => encryptionKey (first 32), macKey (last 32)
$hashPx = hash('sha512', $px, true);
$encryptionKey = substr($hashPx, 0, 32);
$macKey = substr($hashPx, 32, 32);
// Reconstruct dataToMac: iv + bytearray([4]) + ephemPubKeyEncoded + ciphertext
$dataToMac = $iv . chr(4) . $ephemPubKeyEncoded . $ciphertext;
// compute HMAC-SHA256 and compare
$computedMac = hash_hmac('sha256', $dataToMac, $macKey, true);
if (!hash_equals($computedMac, $mac)) {
throw new \RuntimeException('MAC mismatch');
}
// decrypt AES-256-CBC (raw data)
$plaintext = openssl_decrypt($ciphertext, 'AES-256-CBC', $encryptionKey, OPENSSL_RAW_DATA, $iv);
if ($plaintext === false) {
throw new \RuntimeException('AES decryption failed');
}
return $plaintext;
}
header('Access-Control-Allow-Origin: *');
if (strlen($_GET['addr']) == 42) {
$addr = strtolower(preg_replace("/[^a-zA-Z0-9]+/", "", $_GET['addr']));
} else {
echo "Format of the Address not valid!";
exit;
}
$limit = 5;
if (is_numeric($_GET['max_count'])){
$limit = $_GET['max_count'];
}
$msg_key = getallheaders()['X-Comchain-Message-Key'];
if (empty($msg_key)) {
echo "missing message key";
exit;
}
$cluster = Cassandra::cluster('127.0.0.1') ->withCredentials("transactions_ro", "Public_transactions")
->build();
$keyspace = 'comchain';
$session = $cluster->connect($keyspace);
$counter = $limit;
$query = "select * from testtransactions WHERE add1 = ? AND status = 0 ORDER BY time DESC limit $counter;";
$options = array('arguments' => array($addr));
$full_set_row = $session->execute(new Cassandra\SimpleStatement($query), $options);
$line_ct = 0;
$jstring = [];
foreach ($full_set_row as $row) {
if ($row['direction']==2){
$row['time'] = $row['time']->value();
$clear = Null;
if (strlen($row["message_to"])>113){
$clear=DecryptMessage( $msg_key, $row["message_to"]);
}
$result = array(
"hash"=> $row['hash'],
"time"=> intval($row['time']),
"amount"=> floatval($row['recieved'])/100.0,
"msg"=> $clear
);
$jstring[$line_ct] = $result;
$line_ct++;
}
}
echo json_encode($jstring);
?>