Squashed 'external/toxcore/c-toxcore/' content from commit 67badf69

git-subtree-dir: external/toxcore/c-toxcore
git-subtree-split: 67badf69416a74e74f6d7eb51dd96f37282b8455
This commit is contained in:
2023-07-25 11:53:09 +02:00
commit 227425b90e
467 changed files with 116591 additions and 0 deletions

101
other/fun/BUILD.bazel Normal file
View File

@ -0,0 +1,101 @@
load("@rules_cc//cc:defs.bzl", "cc_binary")
package(features = ["layering_check"])
#cc_binary(
# name = "cracker",
# testonly = 1,
# srcs = ["cracker.c"],
# copts = ["-fopenmp"],
# linkopts = ["-fopenmp"],
# deps = [
# "//c-toxcore/toxcore:ccompat",
# "@libsodium",
# ],
#)
cc_binary(
name = "cracker_simple",
testonly = 1,
srcs = ["cracker_simple.c"],
deps = [
"//c-toxcore/testing:misc_tools",
"//c-toxcore/toxcore:ccompat",
"@libsodium",
],
)
cc_binary(
name = "create_minimal_savedata",
testonly = 1,
srcs = [
"create_common.h",
"create_minimal_savedata.c",
],
deps = [
"//c-toxcore/toxcore:ccompat",
"@libsodium",
],
)
cc_binary(
name = "create_savedata",
testonly = 1,
srcs = [
"create_common.h",
"create_savedata.c",
],
deps = [
"//c-toxcore/toxcore:ccompat",
"//c-toxcore/toxcore:tox",
"@libsodium",
],
)
cc_binary(
name = "create_bootstrap_keys",
testonly = 1,
srcs = [
"create_bootstrap_keys.c",
"create_common.h",
],
deps = [
"//c-toxcore/toxcore:ccompat",
"@libsodium",
],
)
cc_binary(
name = "sign",
testonly = 1,
srcs = ["sign.c"],
copts = ["-w"],
deps = [
"//c-toxcore/testing:misc_tools",
"//c-toxcore/toxcore:ccompat",
"@libsodium",
],
)
cc_binary(
name = "strkey",
testonly = 1,
srcs = ["strkey.c"],
copts = ["-w"],
deps = [
"//c-toxcore/toxcore:ccompat",
"//c-toxcore/toxcore:tox",
"@libsodium",
],
)
cc_binary(
name = "save-generator",
testonly = 1,
srcs = ["save-generator.c"],
deps = [
"//c-toxcore/testing:misc_tools",
"//c-toxcore/toxcore:ccompat",
"//c-toxcore/toxcore:tox",
],
)

30
other/fun/CMakeLists.txt Normal file
View File

@ -0,0 +1,30 @@
add_executable(save-generator save-generator.c)
target_link_modules(save-generator toxcore misc_tools)
add_executable(strkey strkey.c)
target_link_modules(strkey toxcore ${LIBSODIUM_LIBRARIES})
add_executable(create_bootstrap_keys create_bootstrap_keys.c)
target_link_modules(create_bootstrap_keys ${LIBSODIUM_LIBRARIES})
add_executable(create_minimal_savedata create_minimal_savedata.c)
target_link_modules(create_minimal_savedata ${LIBSODIUM_LIBRARIES})
add_executable(create_savedata create_savedata.c)
target_link_modules(create_savedata toxcore ${LIBSODIUM_LIBRARIES})
add_executable(sign sign.c)
target_link_modules(sign ${LIBSODIUM_LIBRARIES} misc_tools)
add_executable(cracker_simple cracker_simple.c)
target_link_modules(cracker_simple ${LIBSODIUM_LIBRARIES} misc_tools)
# MSVC doesn't support OpenMP
if(NOT MSVC)
find_package(OpenMP)
if(OpenMP_C_FOUND)
add_executable(cracker cracker.c)
target_link_modules(cracker ${LIBSODIUM_LIBRARIES})
target_link_libraries(cracker OpenMP::OpenMP_C)
endif()
endif()

122
other/fun/bootstrap_node_info.py Executable file
View File

@ -0,0 +1,122 @@
#!/usr/bin/env python3
"""
Copyright (c) 2014 by nurupo <nurupo.contributions@gmail.com>
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.
"""
import socket
import sys
if sys.version_info[0] == 2:
print("This script requires Python 3+ in order to run.")
sys.exit(1)
def print_help(prog: str) -> None:
"""Print program usage to stdout."""
print(f"Usage: {prog} <ipv4|ipv6> <ip/hostname> <port>")
print(f" Example: {prog} ipv4 192.210.149.121 33445")
print(f" Example: {prog} ipv4 23.226.230.47 33445")
print(f" Example: {prog} ipv4 node.tox.biribiri.org 33445")
print(f" Example: {prog} ipv4 cerberus.zodiaclabs.org 33445")
print(f" Example: {prog} ipv6 2604:180:1::3ded:b280 33445")
print("")
print("Return values:")
print(" 0 - received info reply from a node")
print(" 1 - incorrect command line arguments")
print(" 2 - didn't receive any reply from a node")
print(" 3 - received a malformed/unexpected reply")
# https://github.com/irungentoo/toxcore/blob/4940c4c62b6014d1f0586aa6aca7bf6e4ecfcf29/toxcore/network.h#L128
INFO_PACKET_ID = b"\xF0"
# https://github.com/irungentoo/toxcore/blob/881b2d900d1998981fb6b9938ec66012d049635f/other/bootstrap_node_packets.c#L28
INFO_REQUEST_PACKET_LENGTH = 78
# first byte is INFO_REQUEST_ID, other bytes don't matter as long as reqest's
# length matches INFO_REQUEST_LENGTH
INFO_REQUEST_PACKET = INFO_PACKET_ID + (
b"0" * (INFO_REQUEST_PACKET_LENGTH - len(INFO_PACKET_ID)))
PACKET_ID_LENGTH = len(INFO_PACKET_ID)
# https://github.com/irungentoo/toxcore/blob/881b2d900d1998981fb6b9938ec66012d049635f/other/bootstrap_node_packets.c#L44
VERSION_LENGTH = 4
# https://github.com/irungentoo/toxcore/blob/881b2d900d1998981fb6b9938ec66012d049635f/other/bootstrap_node_packets.c#L26
MAX_MOTD_LENGTH = 256
MAX_INFO_RESPONSE_PACKET_LENGTH = PACKET_ID_LENGTH + VERSION_LENGTH + MAX_MOTD_LENGTH
SOCK_TIMEOUT_SECONDS = 1.0
def main(prog: str, protocol: str, host: str, port: int) -> None:
"""Call the bootstrap node info RPC and output the response."""
if protocol == "ipv4":
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
elif protocol == "ipv6":
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
else:
print("Invalid first argument")
print_help(prog)
sys.exit(1)
sock.sendto(INFO_REQUEST_PACKET, (host, port))
sock.settimeout(SOCK_TIMEOUT_SECONDS)
try:
data, _ = sock.recvfrom(MAX_INFO_RESPONSE_PACKET_LENGTH)
except socket.timeout:
print("The DHT bootstrap node didn't reply in " +
str(SOCK_TIMEOUT_SECONDS) + " sec.")
print("The likely reason for that is that the DHT bootstrap node "
"is either offline or has no info set.")
sys.exit(2)
packet_id = data[:PACKET_ID_LENGTH]
if packet_id != INFO_PACKET_ID:
print("Bad response, first byte should be {info_packet_id!r}"
" but got {packet_id!r}({data!r})".format(
info_packet_id=INFO_PACKET_ID,
packet_id=packet_id,
data=data,
))
print("Are you sure that you are pointing the script at a Tox "
"DHT bootstrap node and that the script is up to date?")
sys.exit(3)
version = int.from_bytes(data[PACKET_ID_LENGTH:PACKET_ID_LENGTH +
VERSION_LENGTH],
byteorder="big")
motd = data[PACKET_ID_LENGTH + VERSION_LENGTH:].decode("utf-8")
print("Version: " + str(version))
print("MOTD: " + motd)
sys.exit(0)
if __name__ == "__main__":
if len(sys.argv) != 4:
print_help(sys.argv[0])
sys.exit(1)
main(
prog=sys.argv[0],
protocol=sys.argv[1],
host=sys.argv[2],
port=int(sys.argv[3]),
)

255
other/fun/cracker.c Normal file
View File

@ -0,0 +1,255 @@
/* Public key cracker.
*
* Can be used to find public keys starting with specific hex (ABCD) for example.
*
* NOTE: There's probably a way to make this faster.
*
* Usage: ./cracker ABCDEF
*
* Will try to find a public key starting with: ABCDEF
*/
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
/* Sodium includes*/
#include <sodium/crypto_scalarmult_curve25519.h>
#include <sodium/randombytes.h>
/* NULL compatibility macro */
#include "../../toxcore/ccompat.h"
#define KEY_LEN 32
// Maximum number of bytes this program can crack in one run
#define MAX_CRACK_BYTES 8
// Maximum length of hex encoded prefix
#define MAX_HEX_PREFIX_LEN (MAX_CRACK_BYTES * 2)
#if defined(_OPENMP)
#include <omp.h>
#define NUM_THREADS() ((unsigned) omp_get_max_threads())
#else
#define NUM_THREADS() (1U)
#endif
static void print_key(const uint8_t *client_id)
{
for (uint32_t j = 0; j < 32; ++j) {
printf("%02X", client_id[j]);
}
}
/// bytes needs to be at least (hex_len+1)/2 long
static size_t hex_string_to_bin(const char *hex_string, size_t hex_len, uint8_t *bytes)
{
size_t i;
const char *pos = hex_string;
// make even
for (i = 0; i < hex_len / 2; ++i, pos += 2) {
uint8_t val;
if (sscanf(pos, "%02hhx", &val) != 1) {
return 0;
}
bytes[i] = val;
}
if (i * 2 < hex_len) {
uint8_t val;
if (sscanf(pos, "%hhx", &val) != 1) {
return 0;
}
bytes[i] = (uint8_t)(val << 4);
++i;
}
return i;
}
static size_t match_hex_prefix(const uint8_t *key, const uint8_t *prefix, size_t prefix_len)
{
size_t same = 0;
uint8_t diff = 0;
size_t i;
for (i = 0; i < prefix_len / 2; ++i) {
diff = key[i] ^ prefix[i];
// First check high nibble
if ((diff & 0xF0) == 0) {
++same;
}
// Then low nibble
if (diff == 0) {
++same;
} else {
break;
}
}
// check last high nibble
if ((prefix_len % 2) && diff == 0) {
diff = key[i] ^ prefix[i];
// First check high nibble
if ((diff & 0xF0) == 0) {
++same;
}
}
return same;
}
static void cracker_core(uint64_t range_start, uint64_t range_end, uint64_t range_offs, uint64_t priv_key_shadow[4],
uint32_t *longest_match, uint8_t hex_prefix[MAX_CRACK_BYTES], size_t prefix_chars_len)
{
#pragma omp parallel for firstprivate(priv_key_shadow) shared(longest_match, range_start, range_end, range_offs, hex_prefix, prefix_chars_len) schedule(static) default(none)
for (uint64_t batch = range_start; batch < range_end; ++batch) {
uint8_t *priv_key = (uint8_t *) priv_key_shadow;
/*
* We can't use the first and last bytes because they are masked in
* curve25519. Offset by 16 bytes to get better alignment.
*/
uint64_t *counter = priv_key_shadow + 2;
/*
* Add to `counter` instead of assign here, to preservere more randomness on short runs
* There can be an intentional overflow in `batch + range_offs`
*/
*counter += batch + range_offs;
uint8_t pub_key[KEY_LEN] = {0};
crypto_scalarmult_curve25519_base(pub_key, priv_key);
const unsigned matching = (unsigned) match_hex_prefix(pub_key, hex_prefix, prefix_chars_len);
// Global compare and update
uint32_t l_longest_match;
#pragma omp atomic read
l_longest_match = *longest_match;
if (matching > l_longest_match) {
#pragma omp atomic write
*longest_match = matching;
#pragma omp critical
{
printf("%u chars matching: \n", matching);
printf("Public key: ");
print_key(pub_key);
printf("\nSecret key: ");
print_key(priv_key);
printf("\n");
}
}
}
}
static void print_stats(double seconds_passed, double keys_tried)
{
printf("Runtime: %10lus, Keys tried %e/%e, Calculating %e keys/s\n",
(unsigned long) seconds_passed, keys_tried, (double) UINT64_MAX, keys_tried / seconds_passed);
}
int main(int argc, char *argv[])
{
if (argc < 2) {
printf("usage: ./cracker public_key(or beginning of one in hex format)\n");
return 0;
}
const size_t prefix_chars_len = strlen(argv[1]);
/*
* If you can afford the hardware to crack longer prefixes, you can probably
* afford to rewrite this program.
*/
if (prefix_chars_len > MAX_HEX_PREFIX_LEN) {
printf("Finding a key with more than 16 hex chars as prefix is not supported\n");
return 1;
}
uint8_t hex_prefix[MAX_CRACK_BYTES] = {0};
const size_t prefix_len = hex_string_to_bin(argv[1], prefix_chars_len, hex_prefix);
if (prefix_len == 0) {
printf("Invalid hex key specified\n");
return 1;
}
printf("Searching for key with prefix: %s\n", argv[1]);
time_t start_time = time(nullptr);
// Declare private key bytes as uint64_t[4] so we can lower the alignment without problems
uint64_t priv_key_shadow[KEY_LEN / 8];
uint8_t *priv_key = (uint8_t *) priv_key_shadow;
// Put randomness into the key
randombytes(priv_key, KEY_LEN);
uint32_t longest_match = 0;
// Finishes a batch every ~10s on my PC
const uint64_t batch_size = (UINT64_C(1) << 18) * NUM_THREADS();
// calculate remaining batch that doesn't fit the main loop
const uint64_t rem_batch_size = UINT64_MAX % batch_size;
const uint64_t rem_start = UINT64_MAX - rem_batch_size - 1;
cracker_core(rem_start, UINT64_MAX, 1, priv_key_shadow, &longest_match, hex_prefix, prefix_chars_len);
double seconds_passed = difftime(time(nullptr), start_time);
double old_seconds_passed = seconds_passed;
// Reduce time to first stats output
print_stats(seconds_passed, rem_batch_size + 1);
if (longest_match >= prefix_chars_len) {
printf("Found matching prefix, exiting...\n");
return 0;
}
for (uint64_t tries = 0; tries < rem_start; tries += batch_size) {
cracker_core(tries, tries + batch_size, 0, priv_key_shadow, &longest_match, hex_prefix, prefix_chars_len);
seconds_passed = difftime(time(nullptr), start_time);
// Use double type to avoid overflow in addition, we don't need precision here anyway
double keys_tried = ((double) tries) + rem_batch_size + 1;
if (longest_match >= prefix_chars_len) {
print_stats(seconds_passed, keys_tried);
printf("Found matching prefix, exiting...\n");
return 0;
}
// Rate limit output
if (seconds_passed - old_seconds_passed > 5.0) {
old_seconds_passed = seconds_passed;
print_stats(seconds_passed, keys_tried);
fflush(stdout);
}
}
printf("Congrats future person who successfully searched a key space of 2^64\n");
uint64_t *counter = priv_key_shadow + 2;
*counter = 0;
printf("Didn't find anything from:\n");
print_key(priv_key);
printf("\nto:\n");
*counter = UINT64_MAX;
print_key(priv_key);
printf("\n");
return 2;
}

View File

@ -0,0 +1,84 @@
/* Public key cracker.
*
* Can be used to find public keys starting with specific hex (ABCD) for example.
*
* NOTE: There's probably a way to make this faster.
*
* Usage: ./cracker ABCDEF
*
* Will try to find a public key starting with: ABCDEF
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* Sodium includes*/
#include <sodium/crypto_scalarmult_curve25519.h>
#include <sodium/randombytes.h>
#include "../../testing/misc_tools.h"
#include "../../toxcore/ccompat.h"
// Secret key and public key length
#define KEY_LEN 32
static void print_key(const uint8_t *client_id)
{
for (int j = 0; j < KEY_LEN; ++j) {
printf("%02X", client_id[j]);
}
}
int main(int argc, char *argv[])
{
if (argc < 2) {
printf("usage: ./cracker public_key(or beginning of one in hex format)\n");
return 0;
}
long long unsigned int num_tries = 0;
size_t len = strlen(argv[1]) / 2;
unsigned char *key = hex_string_to_bin(argv[1]);
uint8_t pub_key[KEY_LEN], priv_key[KEY_LEN], c_key[KEY_LEN];
if (len > KEY_LEN) {
printf("%zu characters given, truncating to: %d\n", len * 2, KEY_LEN * 2);
len = KEY_LEN;
}
memcpy(c_key, key, len);
free(key);
randombytes(priv_key, KEY_LEN);
while (1) {
crypto_scalarmult_curve25519_base(pub_key, priv_key);
if (memcmp(c_key, pub_key, len) == 0) {
break;
}
/*
* We can't use the first and last bytes because they are masked in
* curve25519. Using them would generate duplicate keys.
*/
for (int i = (KEY_LEN - 1); i > 1; --i) {
priv_key[i - 1] += 1;
if (priv_key[i - 1] != 0) {
break;
}
}
++num_tries;
}
printf("Public key:\n");
print_key(pub_key);
printf("\nPrivate key:\n");
print_key(priv_key);
printf("\n %llu keys tried\n", num_tries);
return 0;
}

View File

@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
*
* Creates bootstrap keys data for a given secret key, if provided, or a random key otherwise.
* The data is written to stderr, human-readable key info is written to stdout.
*
* Build: gcc -o create_bootstrap_keys create_bootstrap_key.c -lsodium -std=c99
*
* Usage: ./create_bootstrap_key [secret-key] 2>data
*/
#include <stdio.h>
#include "create_common.h"
int main(const int argc, const char *const argv[])
{
init_sodium();
unsigned char public_key[crypto_box_PUBLICKEYBYTES];
unsigned char secret_key[crypto_box_SECRETKEYBYTES];
handle_args(argc, argv, "Creates bootstrap keys data", public_key, secret_key);
print_keys(public_key, secret_key);
fwrite(public_key, sizeof(public_key), 1, stderr);
fwrite(secret_key, sizeof(secret_key), 1, stderr);
return 0;
}

89
other/fun/create_common.h Normal file
View File

@ -0,0 +1,89 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
*
* Shared functions of create_*.c programs.
*/
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sodium.h>
#include "../../toxcore/ccompat.h"
static void init_sodium(void)
{
if (sodium_init() < 0) {
printf("Error: Failed to initialize sodium.\n");
exit(1);
}
}
static int tox_strcasecmp(const char *s1, const char *s2)
{
while (true) {
const int c1 = tolower(*(s1++));
const int c2 = tolower(*(s2++));
if (c1 == '\0' || c2 == '\0' || c1 != c2) {
return c1 - c2;
}
}
}
static void print_usage(const char *const argv0, const char *const does_what)
{
printf("%s for a given secret key, if provided, or a random key otherwise.\n", does_what);
printf("The data is written to stderr, human-readable key info is written to stdout.\n");
printf("\nUsage: %s [secret-key] 2>data\n", argv0);
}
static void handle_args(const int argc, const char *const argv[], const char *const does_what,
unsigned char *const public_key, unsigned char *const secret_key)
{
if (argc == 2 && (!tox_strcasecmp(argv[1], "-h") || !tox_strcasecmp(argv[1], "--help"))) {
print_usage(argv[0], does_what);
exit(0);
}
if (argc == 1) {
crypto_box_keypair(public_key, secret_key);
} else if (argc == 2 && strlen(argv[1]) == crypto_box_SECRETKEYBYTES * 2) {
size_t bin_len = 0;
if (sodium_hex2bin(secret_key, crypto_box_SECRETKEYBYTES, argv[1], crypto_box_SECRETKEYBYTES * 2, nullptr, &bin_len,
nullptr) != 0 || bin_len != crypto_box_SECRETKEYBYTES) {
printf("Error: Secret key must be a hex string.\n");
exit(1);
}
crypto_scalarmult_base(public_key, secret_key);
} else if (argc == 2) {
printf("Error: Secret key must be a %u character hex string.\n", crypto_box_SECRETKEYBYTES * 2);
exit(1);
} else {
print_usage(argv[0], does_what);
exit(1);
}
}
static void bin2hex_toupper(char *const hex, const size_t hex_maxlen, const unsigned char *const bin,
const size_t bin_len)
{
sodium_bin2hex(hex, hex_maxlen, bin, bin_len);
for (size_t i = 0; i < hex_maxlen; i ++) {
hex[i] = (char)toupper(hex[i]);
}
}
static void print_keys(const unsigned char *const public_key, const unsigned char *const secret_key)
{
char public_key_str[crypto_box_PUBLICKEYBYTES * 2 + 1];
char secret_key_str[crypto_box_SECRETKEYBYTES * 2 + 1];
bin2hex_toupper(public_key_str, sizeof(public_key_str), public_key, crypto_box_PUBLICKEYBYTES);
bin2hex_toupper(secret_key_str, sizeof(secret_key_str), secret_key, crypto_box_SECRETKEYBYTES);
fprintf(stdout, "Public key: %s\n", public_key_str);
fprintf(stdout, "Secret key: %s\n", secret_key_str);
}

View File

@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
*
* Creates minimal Tox savedata for a given secret key, if provided, or a random key otherwise.
* The data is written to stderr, human-readable key info is written to stdout.
*
* Build: gcc -o create_minimal_savedata create_minimal_savedata.c -lsodium -std=c99
*
* Usage: ./create_minimal_savedata [secret-key] 2>data
*/
#include <stdio.h>
#include <sodium.h>
#include "create_common.h"
int main(const int argc, const char *const argv[])
{
init_sodium();
unsigned char public_key[crypto_box_PUBLICKEYBYTES];
unsigned char secret_key[crypto_box_SECRETKEYBYTES];
handle_args(argc, argv, "Creates minimal Tox savedata", public_key, secret_key);
print_keys(public_key, secret_key);
// toxcore stores integers in savedata explicitly in little-endian, so this is indeed portable across architectures
// 0x00000000 = (uint32_t) 0
// 0x15ed1b1f = (uint32_t) STATE_COOKIE_GLOBAL
// 0x00000044 = (uint32_t) (crypto_box_PUBLICKEYBYTES+crypto_box_SECRETKEYBYTES+sizeof(uint32_t))
// 0x0001 = (uint16_t) STATE_TYPE_NOSPAMKEYS
// 0x01ce = (uint16_t) STATE_COOKIE_TYPE
// 0x00000000 = (uint32_t) nospam
// _ = uint8_t[crypto_box_PUBLICKEYBYTES] public key
// _ = uint8_t[crypto_box_SECRETKEYBYTES] secret key
const char tox_file[] = "\x00\x00\x00\x00" \
"\x1f\x1b\xed\x15" \
"\x44\x00\x00\x00" \
"\x01\x00" \
"\xce\x01" \
"\x00\x00\x00\x00";
fwrite(tox_file, sizeof(tox_file) - 1, 1, stderr);
fwrite(public_key, sizeof(public_key), 1, stderr);
fwrite(secret_key, sizeof(secret_key), 1, stderr);
unsigned char checksum[2] = {0};
for (size_t i = 0; i < crypto_box_PUBLICKEYBYTES; i ++) {
checksum[i % sizeof(checksum)] ^= public_key[i];
}
char checksum_str[sizeof(checksum) * 2 + 1];
bin2hex_toupper(checksum_str, sizeof(checksum_str), checksum, sizeof(checksum));
char public_key_str[crypto_box_PUBLICKEYBYTES * 2 + 1];
bin2hex_toupper(public_key_str, sizeof(public_key_str), public_key, crypto_box_PUBLICKEYBYTES);
fprintf(stdout, "Tox Id: %s00000000%s\n", public_key_str, checksum_str);
return 0;
}

115
other/fun/create_savedata.c Normal file
View File

@ -0,0 +1,115 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
*
* Creates Tox savedata for a given secret key, if provided, or a random key otherwise.
* The data is written to stderr, human-readable key info is written to stdout.
*
* Build: gcc -o create_savedata create_savedata.c -lsodium -ltoxcore -std=c99
*
* Usage: ./create_savedata [secret-key] 2>data
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sodium.h>
#include "../../toxcore/ccompat.h"
#include "../../toxcore/tox.h"
#include "create_common.h"
static bool create_tox(const unsigned char *const secret_key, Tox **const tox)
{
Tox_Err_Options_New options_error;
struct Tox_Options *const options = tox_options_new(&options_error);
if (options_error != TOX_ERR_OPTIONS_NEW_OK) {
tox_options_free(options);
return false;
}
tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_SECRET_KEY);
tox_options_set_savedata_data(options, secret_key, crypto_box_SECRETKEYBYTES);
Tox_Err_New tox_error;
*tox = tox_new(options, &tox_error);
if (tox_error != TOX_ERR_NEW_OK) {
tox_options_free(options);
return false;
}
tox_options_free(options);
return true;
}
static bool print_savedata(Tox *const tox)
{
const size_t savedata_size = tox_get_savedata_size(tox);
uint8_t *const savedata = (uint8_t *)malloc(savedata_size);
if (savedata == nullptr) {
return false;
}
tox_get_savedata(tox, savedata);
fwrite(savedata, savedata_size, 1, stderr);
free(savedata);
return true;
}
static bool print_tox_id(const Tox *const tox)
{
uint8_t *const tox_id = (uint8_t *)malloc(tox_address_size());
if (tox_id == nullptr) {
return false;
}
tox_self_get_address(tox, tox_id);
const size_t tox_id_str_size = tox_address_size() * 2 + 1;
char *const tox_id_str = (char *)malloc(tox_id_str_size);
if (tox_id_str == nullptr) {
free(tox_id);
return false;
}
bin2hex_toupper(tox_id_str, tox_id_str_size, tox_id, tox_address_size());
fprintf(stdout, "Tox Id: %s\n", tox_id_str);
free(tox_id_str);
free(tox_id);
return true;
}
int main(const int argc, const char *const argv[])
{
init_sodium();
unsigned char public_key[crypto_box_PUBLICKEYBYTES];
unsigned char secret_key[crypto_box_SECRETKEYBYTES];
handle_args(argc, argv, "Creates Tox savedata", public_key, secret_key);
print_keys(public_key, secret_key);
Tox *tox;
if (!create_tox(secret_key, &tox)) {
printf("Error: Failed to create a Tox instance.\n");
return 1;
}
if (!print_savedata(tox)) {
printf("Error: Failed to print savedata.\n");
tox_kill(tox);
return 1;
}
if (!print_tox_id(tox)) {
printf("Error: Failed to print Tox ID.\n");
tox_kill(tox);
return 1;
}
tox_kill(tox);
return 0;
}

111
other/fun/make-funny-savefile.py Executable file
View File

@ -0,0 +1,111 @@
#!/usr/bin/python
"""
Generate a new (and empty) save file with predefined keys. Used to play
with externally generated keys.
(c) 2015 Alexandre Erwin Ittner
Distributed under the GNU GPL v3 or later, WITHOUT ANY WARRANTY. See the
file "LICENSE.md" for license information.
Usage:
./make-funny-savefile.py <public key> <private key> <user name> <out file>
The new user profile will be saved to <out file>.
The keys must be an hex-encoded valid key pair generated by any means
(eg. strkey.c); username may be anything. A random nospam value will be
generated.
Once the savefile is done, load it in your favorite client to get some
DHT nodes, set status and status messages, add friends, etc.
Example (of course, do not try using this key for anything real):
./make-funny-savefile.py 123411DC8B1A4760B648E0C7243B65F01069E4858F45C612CE1A6F673B603830 CC39440CFC063E4A95B7F2FB2580210558BE5C073AFC1C9604D431CCA3132238 "Test user" test.tox
"""
import os
import struct
import sys
PUBLIC_KEY_LENGTH = 32
PRIVATE_KEY_LENGTH = 32
# Constants taken from messenger.c
MESSENGER_STATE_COOKIE_GLOBAL = 0x15ED1B1F
MESSENGER_STATE_COOKIE_TYPE = 0x01CE
MESSENGER_STATE_TYPE_NOSPAMKEYS = 1
MESSENGER_STATE_TYPE_DHT = 2
MESSENGER_STATE_TYPE_FRIENDS = 3
MESSENGER_STATE_TYPE_NAME = 4
MESSENGER_STATE_TYPE_STATUSMESSAGE = 5
MESSENGER_STATE_TYPE_STATUS = 6
MESSENGER_STATE_TYPE_TCP_RELAY = 10
MESSENGER_STATE_TYPE_PATH_NODE = 11
STATUS_MESSAGE = "New user".encode("utf-8")
def abort(msg: str) -> None:
print(msg)
exit(1)
if len(sys.argv) != 5:
abort("Usage: %s <public key> <private key> <user name> <out file>" %
(sys.argv[0]))
try:
public_key = bytes.fromhex(sys.argv[1])
except:
abort("Bad public key")
try:
private_key = bytes.fromhex(sys.argv[2])
except:
abort("Bad private key")
if len(public_key) != PUBLIC_KEY_LENGTH:
abort("Public key with wrong length")
if len(private_key) != PRIVATE_KEY_LENGTH:
abort("Private key with wrong length")
user_name = sys.argv[3].encode("utf-8")
if len(user_name) > 32:
abort("User name too long (for this script, at least)")
out_file_name = sys.argv[4]
nospam = os.urandom(4)
def make_subheader(h_type: int, h_length: int) -> bytes:
return (struct.pack("<I", h_length) + struct.pack("<H", h_type) +
struct.pack("<H", MESSENGER_STATE_COOKIE_TYPE))
data = (
# Main header
struct.pack("<I", 0) + struct.pack("<I", MESSENGER_STATE_COOKIE_GLOBAL) +
# Keys
make_subheader(
MESSENGER_STATE_TYPE_NOSPAMKEYS,
len(nospam) + PUBLIC_KEY_LENGTH + PRIVATE_KEY_LENGTH,
) + nospam + public_key + private_key +
# Name (not really needed, but helps)
make_subheader(MESSENGER_STATE_TYPE_NAME, len(user_name)) + user_name +
# Status message (not really needed, but helps)
make_subheader(MESSENGER_STATE_TYPE_STATUSMESSAGE, len(STATUS_MESSAGE)) +
STATUS_MESSAGE)
try:
with open(out_file_name, "wb") as fp:
fp.write(data)
except Exception as e:
abort(str(e))

172
other/fun/save-generator.c Normal file
View File

@ -0,0 +1,172 @@
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../testing/misc_tools.h"
#include "../../toxcore/ccompat.h"
#include "../../toxcore/tox.h"
#define GENERATED_SAVE_FILE "save.tox"
#define GENERATED_STATUS_MESSAGE "Hello World"
#define GENERATED_REQUEST_MESSAGE "Add me."
#define BOOTSTRAP_IP "185.14.30.213"
#define BOOTSTRAP_ADDRESS "2555763C8C460495B14157D234DD56B86300A2395554BCAE4621AC345B8C1B1B"
#define BOOTSTRAP_UDP_PORT 443
static bool write_save(const uint8_t *data, size_t length)
{
FILE *fp = fopen(GENERATED_SAVE_FILE, "wb");
if (!fp) {
return false;
}
if (fwrite(data, length, 1, fp) != 1) {
fclose(fp);
return false;
}
fclose(fp);
return true;
}
static bool bootstrap_tox(Tox *tox)
{
uint8_t *key = hex_string_to_bin(BOOTSTRAP_ADDRESS);
if (!key) {
printf("Could not allocate memory for tox address\n");
return false;
}
Tox_Err_Bootstrap err;
tox_bootstrap(tox, BOOTSTRAP_IP, BOOTSTRAP_UDP_PORT, key, &err);
free(key);
if (err != TOX_ERR_BOOTSTRAP_OK) {
printf("Failed to bootstrap. Error number: %d", err);
return false;
}
return true;
}
static void tox_connection_callback(Tox *tox, Tox_Connection connection, void *userdata)
{
if (connection == TOX_CONNECTION_UDP) {
printf("Connected to the tox network.\n");
*(bool *)userdata = true;
}
}
static void print_information(Tox *tox)
{
uint8_t tox_id[TOX_ADDRESS_SIZE];
char tox_id_str[TOX_ADDRESS_SIZE * 2];
tox_self_get_address(tox, tox_id);
to_hex(tox_id_str, tox_id, TOX_ADDRESS_SIZE);
char nospam_str[(TOX_NOSPAM_SIZE * 2) + 1];
uint32_t nospam = tox_self_get_nospam(tox);
int length = snprintf(nospam_str, sizeof(nospam_str), "%08X", nospam);
nospam_str[length] = '\0';
uint8_t *name = (uint8_t *)malloc(tox_self_get_name_size(tox) + 1);
assert(name != nullptr);
tox_self_get_name(tox, name);
name[tox_self_get_name_size(tox)] = '\0';
printf("INFORMATION\n");
printf("----------------------------------\n");
printf("Tox ID: %.*s.\n", (int)TOX_ADDRESS_SIZE * 2, tox_id_str);
printf("Nospam: %s.\n", nospam_str);
printf("Name: %s.\n", name);
printf("Status message: %s.\n", GENERATED_STATUS_MESSAGE);
printf("Number of friends: %zu.\n", tox_self_get_friend_list_size(tox));
printf("----------------------------------\n");
}
int main(int argc, char *argv[])
{
if (argc < 3) {
printf("Usage: ./save-generator <name> <friend id> ...\n");
return -1;
}
Tox *tox = tox_new(nullptr, nullptr);
if (!tox) {
printf("Failed to create tox.\n");
return -1;
}
if (!bootstrap_tox(tox)) {
tox_kill(tox);
return -1;
}
tox_callback_self_connection_status(tox, tox_connection_callback);
bool connected = false;
while (!connected) {
tox_iterate(tox, &connected);
c_sleep(tox_iteration_interval(tox));
}
Tox_Err_Set_Info err;
const uint8_t *name = (uint8_t *)argv[1];
tox_self_set_name(tox, name, strlen((const char *)name), &err);
if (err != TOX_ERR_SET_INFO_OK) {
printf("Failed to set name. Error number %d\n", err);
}
tox_self_set_status_message(tox, (const uint8_t *)GENERATED_STATUS_MESSAGE, strlen(GENERATED_STATUS_MESSAGE), &err);
if (err != TOX_ERR_SET_INFO_OK) {
printf("Failed to set status. Error number: %d\n", err);
}
for (unsigned int i = 2; i < argc; i++) { //start at 2 because that is where the tox ids are
uint8_t *address = hex_string_to_bin(argv[i]);
Tox_Err_Friend_Add friend_err;
tox_friend_add(tox, address, (const uint8_t *)GENERATED_REQUEST_MESSAGE, strlen(GENERATED_REQUEST_MESSAGE),
&friend_err);
free(address);
if (friend_err != TOX_ERR_FRIEND_ADD_OK) {
printf("Failed to add friend number %u. Error number: %d\n", i - 1, friend_err);
}
}
const size_t length = tox_get_savedata_size(tox);
uint8_t *savedata = (uint8_t *)malloc(length);
if (!savedata) {
printf("Could not allocate memory for savedata.\n");
tox_kill(tox);
return -1;
}
tox_get_savedata(tox, savedata);
bool ret = write_save(savedata, length);
free(savedata);
if (!ret) {
printf("Failed to write save.\n");
tox_kill(tox);
return -1;
}
printf("Wrote tox save to %s\n", GENERATED_SAVE_FILE);
print_information(tox);
tox_kill(tox);
return 0;
}

147
other/fun/sign.c Normal file
View File

@ -0,0 +1,147 @@
/* Binary signer/checker using ed25519
*
* Compile with:
* gcc -o sign sign.c -lsodium
*
* Generate a keypair:
* ./sign g
*
* Sign a file:
* ./sign s PRIVATEKEY file.bin signedfile.bin
*
* Check a file:
*
* ./sign c PUBKEY signedfile.bin
*
* NOTE: The signature is appended to the end of the file.
*/
#include <sodium.h>
#include <string.h>
#include "../../testing/misc_tools.h" // hex_string_to_bin
#include "../../toxcore/ccompat.h"
static int load_file(char *filename, unsigned char **result)
{
int size = 0;
FILE *f = fopen(filename, "rb");
if (f == nullptr) {
*result = nullptr;
return -1; // -1 means file opening fail
}
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
*result = (unsigned char *)malloc(size + 1);
if (size != fread(*result, sizeof(char), size, f)) {
free(*result);
fclose(f);
return -2; // -2 means file reading fail
}
fclose(f);
(*result)[size] = 0;
return size;
}
int main(int argc, char *argv[])
{
unsigned char pk[crypto_sign_ed25519_PUBLICKEYBYTES];
unsigned char sk[crypto_sign_ed25519_SECRETKEYBYTES];
if (argc == 2 && argv[1][0] == 'g') {
crypto_sign_ed25519_keypair(pk, sk);
printf("Public key:\n");
for (int i = 0; i < crypto_sign_ed25519_PUBLICKEYBYTES; ++i) {
printf("%02X", pk[i]);
}
printf("\nSecret key:\n");
for (int i = 0; i < crypto_sign_ed25519_SECRETKEYBYTES; ++i) {
printf("%02X", sk[i]);
}
printf("\n");
}
if (argc == 5 && argv[1][0] == 's') {
unsigned char *secret_key = hex_string_to_bin(argv[2]);
unsigned char *data = nullptr;
int size = load_file(argv[3], &data);
if (size < 0) {
goto fail;
}
unsigned long long smlen;
unsigned char *sm = (unsigned char *)malloc(size + crypto_sign_ed25519_BYTES * 2);
crypto_sign_ed25519(sm, &smlen, data, size, secret_key);
free(data);
free(secret_key);
if (smlen - size != crypto_sign_ed25519_BYTES) {
free(sm);
goto fail;
}
FILE *f = fopen(argv[4], "wb");
if (f == nullptr) {
free(sm);
goto fail;
}
memcpy(sm + smlen, sm, crypto_sign_ed25519_BYTES); // Move signature from beginning to end of file.
if (fwrite(sm + (smlen - size), 1, smlen, f) != smlen) {
fclose(f);
free(sm);
goto fail;
}
fclose(f);
free(sm);
printf("Signed successfully.\n");
}
if (argc == 4 && argv[1][0] == 'c') {
unsigned char *public_key = hex_string_to_bin(argv[2]);
unsigned char *data;
int size = load_file(argv[3], &data);
if (size < 0) {
goto fail;
}
unsigned char *signe = (unsigned char *)malloc(size + crypto_sign_ed25519_BYTES);
memcpy(signe, data + size - crypto_sign_ed25519_BYTES,
crypto_sign_ed25519_BYTES); // Move signature from end to beginning of file.
memcpy(signe + crypto_sign_ed25519_BYTES, data, size - crypto_sign_ed25519_BYTES);
free(data);
unsigned char *m = (unsigned char *)malloc(size);
unsigned long long mlen;
if (crypto_sign_ed25519_open(m, &mlen, signe, size, public_key) == -1) {
printf("Failed checking sig.\n");
free(m);
free(signe);
goto fail;
}
free(m);
free(signe);
printf("Checked successfully.\n");
}
return 0;
fail:
printf("FAIL\n");
return 1;
}

151
other/fun/strkey.c Normal file
View File

@ -0,0 +1,151 @@
/* strkey -- String in Public Key
*
* Generates Tox's key pairs, checking if a certain string is in the public key.
*
* Requires sodium or nacl library.
*
* There seem to be some problems with the code working on Windows -- it works
* when built in debug mode with MinGW 4.8, but it doesn't work correctly when
* built in release.
*
* Usage: strkey <offset> <string>
*
* Offset - an integer specifying exact byte offset position of the string you
* are looking for within a public key. When offset is negative, the program
* just looks for the desired string being somewhere, doesn't matter where, in
* the public key.
*
* String - a hex string that you want to have in your public key. It must have
* an even number of letters, since every two hexes map to a single byte of
* the public key.
*
* Examples:
* strkey 0 0123
* Looks for a public key that begins with "0123".
*
* strkey 1 0123
* Looks for a public key that has "0123" starting at its second byte, i.e. "XX0123...".
*
* strkey 2 0123
* Looks for a public key that has "0123" starting at its third byte, i.e. "XXXX0123...".
* (each two hexes represent a single byte of a public key)
*
* strkey -1 AF57CC
* Looks for a public key that contains "AF57CC", regardless of its position.
*
* To compile with gcc and sodium: gcc strkey.c -o strkey -lsodium
*/
#include <stdio.h>
#include <string.h>
#include <sodium.h>
#include "../../toxcore/ccompat.h"
#define PRINT_TRIES_COUNT
static void print_key(unsigned char *key)
{
for (size_t i = 0; i < crypto_box_PUBLICKEYBYTES; ++i) {
if (key[i] < 16) {
fprintf(stdout, "0");
}
fprintf(stdout, "%hhX", key[i]);
}
}
int main(int argc, char *argv[])
{
unsigned char public_key[crypto_box_PUBLICKEYBYTES]; // null terminator
unsigned char secret_key[crypto_box_SECRETKEYBYTES];
long int offset = 0;
size_t len;
unsigned char desired_bin[crypto_box_PUBLICKEYBYTES]; // null terminator
if (argc == 3) {
offset = strtol(argv[1], nullptr, 10);
if (offset <= 0) {
fprintf(stderr, "strtol() failed to convert \"%s\" into an integer\n", argv[1]);
exit(1);
}
char *desired_hex = argv[2];
len = strlen(desired_hex);
if (len % 2 != 0) {
fprintf(stderr, "Desired key should have an even number of letters\n");
exit(1);
}
size_t block_length = (offset < 0 ? 0 : offset) + len / 2;
if (block_length > crypto_box_PUBLICKEYBYTES) {
fprintf(stderr, "The given key with the given offset exceed public key's length\n");
exit(1);
}
// convert hex to bin
char *pos = desired_hex;
size_t i;
for (i = 0; i < len; pos += 2) {
unsigned int value;
sscanf(pos, "%02x", &value);
desired_bin[i] = value;
++i;
}
} else {
fprintf(stdout, "Usage: executable <byte offset> <desired hex string with even number of letters>\n");
exit(1);
}
len /= 2;
#ifdef PRINT_TRIES_COUNT
long long unsigned int tries = 0;
#endif
if (offset < 0) {
int found = 0;
do {
#ifdef PRINT_TRIES_COUNT
++tries;
#endif
crypto_box_keypair(public_key, secret_key);
for (int i = 0; i <= crypto_box_PUBLICKEYBYTES - len; ++i) {
if (memcmp(public_key + i, desired_bin, len) == 0) {
found = 1;
break;
}
}
} while (!found);
} else {
unsigned char *p = public_key + offset;
do {
#ifdef PRINT_TRIES_COUNT
++tries;
#endif
crypto_box_keypair(public_key, secret_key);
} while (memcmp(p, desired_bin, len) != 0);
}
fprintf(stdout, "Public key: ");
print_key(public_key);
fprintf(stdout, "\n");
fprintf(stdout, "Private key: ");
print_key(secret_key);
fprintf(stdout, "\n");
#ifdef PRINT_TRIES_COUNT
fprintf(stdout, "Found the key pair on %llu try.\n", tries);
#endif
return 0;
}