diff --git a/3rdparty/crc32c_adler/CMakeLists.txt b/3rdparty/crc32c_adler/CMakeLists.txt new file mode 100755 index 0000000000000000000000000000000000000000..b660945e8049ca7c527b3dc86ce57ec25fad0ba4 --- /dev/null +++ b/3rdparty/crc32c_adler/CMakeLists.txt @@ -0,0 +1,16 @@ +# +# DESCRIPTION: A miminal cmake script to be used to produce CRC32 Addler static library +# +# AUTHOR: Ruslan R. Laishev +# +# CREATION DATE: 14-NOV-2022 +# +# MODIFICATION HISTORY: +# +cmake_minimum_required(VERSION 3.10) +project(crc32c_adler) + +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall" ) +set( SRCS crc32c_adler.c crc32c_adler.h) +add_library(crc32c_adler STATIC ${SRCS}) +target_link_libraries(crc32c_adler pthread) diff --git a/3rdparty/crc32c_adler/README b/3rdparty/crc32c_adler/README new file mode 100755 index 0000000000000000000000000000000000000000..23b609d0e8e43e890a06a4068bc20da327abd40f --- /dev/null +++ b/3rdparty/crc32c_adler/README @@ -0,0 +1,14 @@ + +Extended version of CRC32C implementation by Mark Adler, providing both hardware (SSE 4.2) and software algorithms with auto-detection. + +Source: +https://stackoverflow.com/a/17646775 + +According to Ferry Toth, Adler's implementation is 'highly optimized': +https://stackoverflow.com/a/39862799 +https://github.com/htot/crc32c + +Revised software algorithm by Robert Važan: +https://stackoverflow.com/a/21915223 +https://crc32c.machinezoo.com/ +https://bitbucket.org/robertvazan/crc32c-hw/src diff --git a/3rdparty/crc32c_adler/crc32c_adler.c b/3rdparty/crc32c_adler/crc32c_adler.c new file mode 100755 index 0000000000000000000000000000000000000000..e21f8c8ec52e84d170265a285d60caa0c8d9bcb4 --- /dev/null +++ b/3rdparty/crc32c_adler/crc32c_adler.c @@ -0,0 +1,501 @@ +/* + CRC32C_ADLER -- Computes CRC32C Checksums + Version 1.2, Date 05/21/18 + Copyright (C) 2013 Mark Adler <madler@alumni.caltech.edu> + Copyright (C) 2018 Fonic <https://github.com/fonic> + + Provides both a hardware-accelerated algorithm (*) and a software algorithm. + Note that this computes CRC32C checksums, not CRC32 (without 'C') checksums + used by Ethernet, gzip, etc. + + (*) CRC instruction on Intel SSE 4.2 processors. SSE 4.2 was first supported + by Nehalem processors introduced in November, 2008. + + Version history: + 1.0 10 Feb 2013 First version + 1.1 1 Aug 2013 Correct comments on why three crc instructions in parallel + 1.2 21 May 2018 Add header file, revise hardware support check, eliminate + pthreads, restructure code, revise comments and description + + Version 1.1 by Mark Adler was originally published here: + https://stackoverflow.com/a/17646775 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> + +#include "crc32c_adler.h" + +/* CRC32C (iSCSI) polynomial in reversed bit order. */ +#define POLY 0x82f63b78 + + +/****************************************************************************** + * * + * Software Algorithm (1) - Table-driven, 8 Bytes / Iteration * + * * + ******************************************************************************/ + +/* Table for software algorithm. */ +static uint32_t crc32c_table[8][256]; + +/* Flag to indicate if crc32c_init_sw() has been called. */ +static int crc32c_sw_initialized = 0; + +/* Initialize table for software algorithm. */ +static void crc32c_init_sw(void) +{ + uint32_t n, crc, k; + + for (n = 0; n < 256; n++) { + crc = n; + crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; + crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; + crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; + crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; + crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; + crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; + crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; + crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; + crc32c_table[0][n] = crc; + } + for (n = 0; n < 256; n++) { + crc = crc32c_table[0][n]; + for (k = 1; k < 8; k++) { + crc = crc32c_table[0][crc & 0xff] ^ (crc >> 8); + crc32c_table[k][n] = crc; + } + } + crc32c_sw_initialized = 1; +} + +/* Compute CRC32C checksum. */ +uint32_t crc32c_sw(uint32_t crci, const void *buf, size_t len) +{ + const unsigned char *next = buf; + uint64_t crc; + + if (!crc32c_sw_initialized) + crc32c_init_sw(); + + crc = crci ^ 0xffffffff; + while (len && ((uintptr_t)next & 7) != 0) { + crc = crc32c_table[0][(crc ^ *next++) & 0xff] ^ (crc >> 8); + len--; + } + while (len >= 8) { + crc ^= *(uint64_t *)next; + crc = crc32c_table[7][crc & 0xff] ^ + crc32c_table[6][(crc >> 8) & 0xff] ^ + crc32c_table[5][(crc >> 16) & 0xff] ^ + crc32c_table[4][(crc >> 24) & 0xff] ^ + crc32c_table[3][(crc >> 32) & 0xff] ^ + crc32c_table[2][(crc >> 40) & 0xff] ^ + crc32c_table[1][(crc >> 48) & 0xff] ^ + crc32c_table[0][crc >> 56]; + next += 8; + len -= 8; + } + while (len) { + crc = crc32c_table[0][(crc ^ *next++) & 0xff] ^ (crc >> 8); + len--; + } + return (uint32_t)crc ^ 0xffffffff; +} + + +/****************************************************************************** + * * + * Software Algorithm (2) - Table-driven, 16 Bytes / Iteration * + * * + ******************************************************************************/ + +/* Table for software algorithm. */ +static uint32_t crc32c_table2[16][256]; + +/* Flag to indicate if crc32c_init_sw2() has been called. */ +static int crc32c_table2_initialized = 0; + +/* Initialize table for software algorithm. */ +static void crc32c_init_sw2(void) +{ + for(int i = 0; i < 256; i++) + { + uint32_t res = (uint32_t)i; + for(int t = 0; t < 16; t++) { + for (int k = 0; k < 8; k++) res = (res & 1) == 1 ? POLY ^ (res >> 1) : (res >> 1); + crc32c_table2[t][i] = res; + } + } + crc32c_table2_initialized = 1; +} + +/* Compute CRC32C checksum. */ +uint32_t crc32c_sw2(uint32_t crci, const void *buf, size_t len) +{ + const unsigned char *next = buf; +#ifdef __x86_64__ + uint64_t crc; +#else + uint32_t crc; +#endif + + if(!crc32c_table2_initialized) + crc32c_init_sw2(); + + crc = crci ^ 0xffffffff; +#ifdef __x86_64__ + while (len && ((uintptr_t)next & 7) != 0) + { + crc = crc32c_table2[0][(crc ^ *next++) & 0xff] ^ (crc >> 8); + --len; + } + while (len >= 16) + { + crc ^= *(uint64_t *)next; + uint64_t high = *(uint64_t *)(next + 8); + crc = crc32c_table2[15][crc & 0xff] + ^ crc32c_table2[14][(crc >> 8) & 0xff] + ^ crc32c_table2[13][(crc >> 16) & 0xff] + ^ crc32c_table2[12][(crc >> 24) & 0xff] + ^ crc32c_table2[11][(crc >> 32) & 0xff] + ^ crc32c_table2[10][(crc >> 40) & 0xff] + ^ crc32c_table2[9][(crc >> 48) & 0xff] + ^ crc32c_table2[8][crc >> 56] + ^ crc32c_table2[7][high & 0xff] + ^ crc32c_table2[6][(high >> 8) & 0xff] + ^ crc32c_table2[5][(high >> 16) & 0xff] + ^ crc32c_table2[4][(high >> 24) & 0xff] + ^ crc32c_table2[3][(high >> 32) & 0xff] + ^ crc32c_table2[2][(high >> 40) & 0xff] + ^ crc32c_table2[1][(high >> 48) & 0xff] + ^ crc32c_table2[0][high >> 56]; + next += 16; + len -= 16; + } +#else + while (len && ((uintptr_t)next & 3) != 0) + { + crc = crc32c_table2[0][(crc ^ *next++) & 0xff] ^ (crc >> 8); + --len; + } + while (len >= 12) + { + crc ^= *(uint32_t *)next; + uint32_t high = *(uint32_t *)(next + 4); + uint32_t high2 = *(uint32_t *)(next + 8); + crc = crc32c_table2[11][crc & 0xff] + ^ crc32c_table2[10][(crc >> 8) & 0xff] + ^ crc32c_table2[9][(crc >> 16) & 0xff] + ^ crc32c_table2[8][crc >> 24] + ^ crc32c_table2[7][high & 0xff] + ^ crc32c_table2[6][(high >> 8) & 0xff] + ^ crc32c_table2[5][(high >> 16) & 0xff] + ^ crc32c_table2[4][high >> 24] + ^ crc32c_table2[3][high2 & 0xff] + ^ crc32c_table2[2][(high2 >> 8) & 0xff] + ^ crc32c_table2[1][(high2 >> 16) & 0xff] + ^ crc32c_table2[0][high2 >> 24]; + next += 12; + len -= 12; + } +#endif + while (len) + { + crc = crc32c_table2[0][(crc ^ *next++) & 0xff] ^ (crc >> 8); + --len; + } + return (uint32_t)crc ^ 0xffffffff; +} + + +/****************************************************************************** + * * + * Hardware Algorithm - SSE 4.2 * + * * + ******************************************************************************/ + +/* Multiply a matrix times a vector over the Galois field of two elements, + GF(2). Each element is a bit in an unsigned integer. mat must have at + least as many entries as the power of two for most significant one bit in + vec. */ +static inline uint32_t gf2_matrix_times(uint32_t *mat, uint32_t vec) +{ + uint32_t sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* Multiply a matrix by itself over GF(2). Both mat and square must have 32 + rows. */ +static inline void gf2_matrix_square(uint32_t *square, uint32_t *mat) +{ + int n; + + for (n = 0; n < 32; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* Construct an operator to apply len zeros to a crc. len must be a power of + two. If len is not a power of two, then the result is the same as for the + largest power of two less than len. The result for len == 0 is the same as + for len == 1. A variant of this routine could be easily written for any + len, but that is not needed for this application. */ +static void crc32c_zeros_op(uint32_t *even, size_t len) +{ + int n; + uint32_t row; + uint32_t odd[32]; /* odd-power-of-two zeros operator */ + + /* Put operator for one zero bit in odd. */ + odd[0] = POLY; /* CRC32C polynomial */ + row = 1; + for (n = 1; n < 32; n++) { + odd[n] = row; + row <<= 1; + } + + /* Put operator for two zero bits in even. */ + gf2_matrix_square(even, odd); + + /* Put operator for four zero bits in odd. */ + gf2_matrix_square(odd, even); + + /* First square will put the operator for one zero byte (eight zero bits), + in even -- next square puts operator for two zero bytes in odd, and so + on, until len has been rotated down to zero. */ + do { + gf2_matrix_square(even, odd); + len >>= 1; + if (len == 0) + return; + gf2_matrix_square(odd, even); + len >>= 1; + } while (len); + + /* Answer ended up in odd -- copy to even. */ + for (n = 0; n < 32; n++) + even[n] = odd[n]; +} + +/* Take a length and build four lookup tables for applying the zeros operator + for that length, byte-by-byte on the operand. */ +static void crc32c_zeros(uint32_t zeros[][256], size_t len) +{ + uint32_t n; + uint32_t op[32]; + + crc32c_zeros_op(op, len); + for (n = 0; n < 256; n++) { + zeros[0][n] = gf2_matrix_times(op, n); + zeros[1][n] = gf2_matrix_times(op, n << 8); + zeros[2][n] = gf2_matrix_times(op, n << 16); + zeros[3][n] = gf2_matrix_times(op, n << 24); + } +} + +/* Apply the zeros operator table to crc. */ +static inline uint32_t crc32c_shift(uint32_t zeros[][256], uint32_t crc) +{ + return zeros[0][crc & 0xff] ^ zeros[1][(crc >> 8) & 0xff] ^ + zeros[2][(crc >> 16) & 0xff] ^ zeros[3][crc >> 24]; +} + +/* Block sizes for three-way parallel crc computation. LONG and SHORT must + both be powers of two. The associated string constants must be set + accordingly, for use in constructing the assembler instructions. */ +#define LONG 8192 +#define LONGx1 "8192" +#define LONGx2 "16384" +#define SHORT 256 +#define SHORTx1 "256" +#define SHORTx2 "512" + +/* Tables for hardware algorithm that shift a crc by LONG and SHORT zeros. */ +static uint32_t crc32c_long[4][256]; +static uint32_t crc32c_short[4][256]; + +/* Flag to indicate if crc32c_init_hw() has been called. */ +static int crc32c_hw_initialized = 0; + + + + +#if defined(__x86_64__) /* @RRL: to compile for ARM */ + + + +static void crc32c_init_hw(void) +{ + crc32c_zeros(crc32c_long, LONG); + crc32c_zeros(crc32c_short, SHORT); + crc32c_hw_initialized = 1; +} + +/* Compute CRC32C checksum. */ +uint32_t crc32c_hw(uint32_t crc, const void *buf, size_t len) +{ + const unsigned char *next = buf; + const unsigned char *end; + uint64_t crc0, crc1, crc2; /* need to be 64 bits for crc32q */ + + /* Populate shift tables the first time through. */ + if (!crc32c_hw_initialized) + crc32c_init_hw(); + + /* Pre-process the crc. */ + crc0 = crc ^ 0xffffffff; + + /* Compute the crc for up to seven leading bytes to bring the data pointer + to an eight-byte boundary. */ + while (len && ((uintptr_t)next & 7) != 0) { + __asm__("crc32b\t" "(%1), %0" + : "=r"(crc0) + : "r"(next), "0"(crc0)); + next++; + len--; + } + + /* Compute the crc on sets of LONG*3 bytes, executing three independent crc + instructions, each on LONG bytes -- this is optimized for the Nehalem, + Westmere, Sandy Bridge, and Ivy Bridge architectures, which have a + throughput of one crc per cycle, but a latency of three cycles. */ + while (len >= LONG*3) { + crc1 = 0; + crc2 = 0; + end = next + LONG; + do { + __asm__("crc32q\t" "(%3), %0\n\t" + "crc32q\t" LONGx1 "(%3), %1\n\t" + "crc32q\t" LONGx2 "(%3), %2" + : "=r"(crc0), "=r"(crc1), "=r"(crc2) + : "r"(next), "0"(crc0), "1"(crc1), "2"(crc2)); + next += 8; + } while (next < end); + crc0 = crc32c_shift(crc32c_long, crc0) ^ crc1; + crc0 = crc32c_shift(crc32c_long, crc0) ^ crc2; + next += LONG*2; + len -= LONG*3; + } + + /* Do the same thing, but now on SHORT*3 blocks for the remaining data less + than a LONG*3 block. */ + while (len >= SHORT*3) { + crc1 = 0; + crc2 = 0; + end = next + SHORT; + do { + __asm__("crc32q\t" "(%3), %0\n\t" + "crc32q\t" SHORTx1 "(%3), %1\n\t" + "crc32q\t" SHORTx2 "(%3), %2" + : "=r"(crc0), "=r"(crc1), "=r"(crc2) + : "r"(next), "0"(crc0), "1"(crc1), "2"(crc2)); + next += 8; + } while (next < end); + crc0 = crc32c_shift(crc32c_short, crc0) ^ crc1; + crc0 = crc32c_shift(crc32c_short, crc0) ^ crc2; + next += SHORT*2; + len -= SHORT*3; + } + + /* Compute the crc on the remaining eight-byte units less than a SHORT*3 + block. */ + end = next + (len - (len & 7)); + while (next < end) { + __asm__("crc32q\t" "(%1), %0" + : "=r"(crc0) + : "r"(next), "0"(crc0)); + next += 8; + } + len &= 7; + + /* Compute the crc for up to seven trailing bytes. */ + while (len) { + __asm__("crc32b\t" "(%1), %0" + : "=r"(crc0) + : "r"(next), "0"(crc0)); + next++; + len--; + } + + /* Return a post-processed crc. */ + return (uint32_t)crc0 ^ 0xffffffff; +} + + + +#endif /* @RRL: to compile for ARM */ + +/****************************************************************************** + * * + * Other Functions * + * * + ******************************************************************************/ + +/* Variables to store information on hardware support. */ +static int crc32c_hardware_support = 0; +static int crc32c_hardware_checked = 0; + +/* Check for hardware support (SSE 4.2). Note that this does not check for + the existence of the cpuid instruction itself, which was introduced on the + 486SL in 1992, so this will fail on earlier x86 processors. cpuid works + on all Pentium and later processors. */ +int crc32c_hw_support() +{ +#if defined(__x86_64__) /* @RRL: to compile for ARM */ + if (!crc32c_hardware_checked) { + do { + uint32_t eax, ecx; + eax = 1; + __asm__("cpuid" + : "=c"(ecx) + : "a"(eax) + : "%ebx", "%edx"); + (crc32c_hardware_support) = (ecx >> 20) & 1; + } while (0); + crc32c_hardware_checked = 1; + } + return crc32c_hardware_support; +#else + return 0; +#endif + +} + +/* Disable hardware algorithm even if supported by hardware. */ +void crc32c_hw_disable() +{ + crc32c_hardware_support = 0; + crc32c_hardware_checked = 1; +} + +/* Compute CRC32C checksum. Use hardware algorithm if supported, + fall back on software algorithm otherwise. */ +uint32_t crc32c(uint32_t crc, const void *buf, size_t len) +{ + return crc32c_hw_support() ? crc32c_hw(crc, buf, len) : crc32c_sw(crc, buf, len); +} diff --git a/3rdparty/crc32c_adler/crc32c_adler.h b/3rdparty/crc32c_adler/crc32c_adler.h new file mode 100755 index 0000000000000000000000000000000000000000..32f3f81e6b5421cac48d9da560919392bb0530ce --- /dev/null +++ b/3rdparty/crc32c_adler/crc32c_adler.h @@ -0,0 +1,61 @@ +/* + CRC32C_ADLER -- Computes CRC32C Checksums + Version 1.2, Date 05/21/18 + Copyright (C) 2013 Mark Adler <madler@alumni.caltech.edu> + Copyright (C) 2018 Fonic <https://github.com/fonic> + + Provides both a hardware-accelerated algorithm (*) and a software algorithm. + Note that this computes CRC32C checksums, not CRC32 (without 'C') checksums + used by Ethernet, gzip, etc. + + (*) CRC instruction on Intel SSE 4.2 processors. SSE 4.2 was first supported + by Nehalem processors introduced in November, 2008. + + Version history: + 1.0 10 Feb 2013 First version + 1.1 1 Aug 2013 Correct comments on why three crc instructions in parallel + 1.2 21 May 2018 Add header file, revise hardware support check, eliminate + pthreads, restructure code, revise comments and description + + Version 1.1 by Mark Adler was originally published here: + https://stackoverflow.com/a/17646775 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#ifndef CRC32C_ADLER_H +#define CRC32C_ADLER_H + +/* Compute CRC32C checksum using software algorithm (1). */ +uint32_t crc32c_sw(uint32_t crci, const void *buf, size_t len); + +/* Compute CRC32C checksum using software algorithm (2). */ +uint32_t crc32c_sw2(uint32_t crci, const void *buf, size_t len); + +/* Compute CRC32C checksum using hardware algorithm. */ +uint32_t crc32c_hw(uint32_t crc, const void *buf, size_t len); + +/* Check if hardware-support (i.e. SSE 4.2) is available. */ +int crc32c_hw_support(); + +/* Disable hardware algorithm even if supported by hardware. */ +void crc32c_hw_disable(); + +/* Compute CRC32C checksum. Use hardware algorithm if supported, + fall back on software algorithm otherwise. */ +uint32_t crc32c(uint32_t crc, const void *buf, size_t len); + +#endif // CRC32C_ADLER_H diff --git a/3rdparty/crc32c_adler/example-dht.c b/3rdparty/crc32c_adler/example-dht.c new file mode 100755 index 0000000000000000000000000000000000000000..5bd05b1e6b835eaf6c60d9edd599b0aefa996a27 --- /dev/null +++ b/3rdparty/crc32c_adler/example-dht.c @@ -0,0 +1,163 @@ +/* + TODO describe example +*/ +#define _GNU_SOURCE /* random, srandom*/ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <fcntl.h> /* open, close etc. */ +#include <string.h> /* memcpy */ +#include <netinet/in.h> /* AF_INET, INET_ADDRSTRLEN etc. */ +#include <arpa/inet.h> /* inet_ntop */ + +#include "crc32c_adler.h" + +/* Convert id to hex string of formate used in BEP 42. */ +char id_hex_str[20*2+2+1]; /* 20 bytes x 2 characters + 2 x ' ' + '\0' */ +const char* +id_to_hex(const unsigned char *id) +{ + //const char* hex_chr = "0123456789ABCDEF"; + const char* hex_chr = "0123456789abcdef"; + for(int i=0,j=0; i < 20 && j < sizeof(id_hex_str)-2; i++) { + id_hex_str[j++] = hex_chr[ (id[i]>>4) & 0x0F ]; + id_hex_str[j++] = hex_chr[ id[i] & 0x0F ]; + if (i == 2 || i == 18) { + id_hex_str[j++] = ' '; + } + } + id_hex_str[sizeof(id_hex_str)-1] = '\0'; + return id_hex_str; +} + +/* Generate node ID from IP address + predefined rand using example algorithm + provided in BEP 42. + + Parameters: + ip IPv4 or IPv6 address (network byte order) + iplen number of octets to consider in ip (4 or 8) + id resulting node ID + rand predefined random value */ +void crc32c_id(const uint8_t* ip, int iplen, uint8_t id[20], uint32_t rand) +{ + uint8_t v4_mask[] = { 0x03, 0x0f, 0x3f, 0xff }; + uint8_t v6_mask[] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; + uint8_t* mask = iplen == 4 ? v4_mask : v6_mask; + + uint8_t ip_copy[8]; + memcpy(ip_copy, ip, iplen); + + for (int i = 0; i < iplen; ++i) + ip_copy[i] &= mask[i]; + + //uint32_t rand = random() & 0xff; + uint8_t r = rand & 0x7; + ip_copy[0] |= r << 5; + + uint32_t crc = 0; + crc = crc32c(crc, ip_copy, iplen); + + /* only take the top 21 bits from crc */ + id[0] = (crc >> 24) & 0xff; + id[1] = (crc >> 16) & 0xff; + id[2] = ((crc >> 8) & 0xf8) | (random() & 0x7); + for (int i = 3; i < 19; ++i) id[i] = random(); + id[19] = rand; +} + +/* Find how many bits two ids have in common. */ +int common_bits(const unsigned char *id1, const unsigned char *id2) +{ + int i, j; + unsigned char xor; + for(i = 0; i < 20; i++) { + if(id1[i] != id2[i]) + break; + } + + if(i == 20) + return 160; + + xor = id1[i] ^ id2[i]; + + j = 0; + while((xor & 0x80) == 0) { + xor <<= 1; + j++; + } + + return 8 * i + j; +} + +/* Check if a node ID is correct in the sense of BEP 42. */ +int check_id(const uint8_t id1[20], const uint8_t* ip, int iplen, uint32_t rand) +{ + /* Generate ID from IP + rand -> id2. */ + uint8_t id2[20]; + crc32c_id(ip, iplen, id2, rand); + + /* Compare id1 with id2: + - the first 21 bits must match + - the last byte must match rand */ + int cbits = common_bits(id1, id2); + if (cbits < 21) { + printf("Only the first %i bits match (expected: 21)\n", cbits); + return 0; + } + if (id1[19] != id2[19]) { + printf("Last byte does not match (expected: %u, got: %u)\n", id2[19], id1[19]); + return 0; + } + return 1; +} + +/* Main. */ +int main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + /* Print which CRC32C algorithm is used. */ + printf("\nUsing %s algorithm.\n\n", crc32c_hw_support() ? "hardware-accelerated (SSE 4.2)" : "software"); + + /* Seed random. */ + int fd = open("/dev/urandom", O_RDONLY); + if(fd < 0) { + perror("open(random)"); + exit(1); + } + unsigned seed; + read(fd, &seed, sizeof(seed)); + srandom(seed); + close(fd); + + /* Example IP/rand combinations as used in BEP 42. */ + uint8_t ip[5][4] = { + { 124, 31, 75, 21 }, + { 21, 75, 31, 124 }, + { 65, 23, 51, 170 }, + { 84, 124, 73, 14 }, + { 43, 213, 53, 83 } + }; + uint32_t rand[] = { + 1, + 86, + 22, + 65, + 90 + }; + int iplen = 4; + uint8_t id[20]; + + printf("IP rand Node ID Ok?\n"); + printf("=============== ===== ========================================== ====\n"); + for (int i = 0; i < 5; ++i) { + crc32c_id(ip[i], iplen, id, rand[i]); + char ipstr[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, ip[i], ipstr, sizeof(ipstr)); + printf("%-15s %2u %s %s\n", ipstr, rand[i], id_to_hex(id), (check_id(id, ip[i], 4, rand[i]) ? "yes" : "no")); + } + + return 0; +} diff --git a/3rdparty/crc32c_adler/example-stdin.c b/3rdparty/crc32c_adler/example-stdin.c new file mode 100755 index 0000000000000000000000000000000000000000..d64fdb6a8a4408451a2a447de7d7f4abf8a1f33c --- /dev/null +++ b/3rdparty/crc32c_adler/example-stdin.c @@ -0,0 +1,46 @@ +/* + TODO describe example +*/ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> + +#include "crc32c_adler.h" + +#define SIZE (262144*3) +#define CHUNK SIZE + +int main(int argc, char **argv) +{ + char *buf; + ssize_t got; + size_t off, n; + uint32_t crc; + + (void)argv; + crc = 0; + buf = malloc(SIZE); + if (buf == NULL) { + fputs("out of memory", stderr); + return 1; + } + while ((got = read(0, buf, SIZE)) > 0) { + off = 0; + do { + n = (size_t)got - off; + if (n > CHUNK) + n = CHUNK; + crc = argc > 1 ? crc32c_sw(crc, buf + off, n) : + crc32c(crc, buf + off, n); + off += n; + } while (off < (size_t)got); + } + free(buf); + if (got == -1) { + fputs("read error\n", stderr); + return 1; + } + printf("%08x\n", crc); + return 0; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 98e954bf412ee5c076ead5d33f6fbea22013f020..3d922c8554160c15fbfa5f3bce24a387badf9b8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,11 +66,19 @@ if (CELLFRAME_MODULES MATCHES "test-framework") set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_test) endif() + + add_subdirectory(3rdparty/crc32c_adler) # https://github.com/fonic/crc32c_adler + include_directories(3rdparty/crc32c_adler) + set(CELLFRAME_LIBS ${CELLFRAME_LIBS} crc32c_adler) + + + if(BUILD_TESTS) include(cmake/OS_Detection.cmake) add_subdirectory(dap-sdk) endif() + if (BUILD_WITH_ZIP) add_subdirectory(3rdparty/libzip) include_directories(3rdparty/libzip/lib) @@ -83,6 +91,7 @@ endif() add_subdirectory(modules/) + add_library(${PROJECT_NAME} STATIC cellframe-sdk.c) # init libs @@ -207,6 +216,7 @@ if (CELLFRAME_MODULES MATCHES "srv-stake-pos-delegate") #add TARGET_FILE for proper symbols resolving #pos_delegate depends on symbols from this libs set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_stake_pos_delegate $<TARGET_FILE:dap_chain_cs_dag_poa> $<TARGET_FILE:dap_chain_cs_block_poa> $<TARGET_FILE:dap_chain_cs_dag> $<TARGET_FILE:dap_chain_cs_blocks>) + set(CELLFRAME_LIBS ${CELLFRAME_LIBS} crc32c_adler) endif() # Enable service for dynamic modules @@ -217,7 +227,7 @@ endif() if (WIN32) set(CELLFRAME_LIBS ${CELLFRAME_LIBS} kernel32 user32 shell32 winmm gdi32 advapi32 - ole32 version imm32 oleaut32 ws2_32 ntdll psapi + ole32 version imm32 oleaut32 ws2_32 ntdll psapi shlwapi bcrypt crypt32 secur32 userenv) #mqrt) endif() @@ -225,7 +235,11 @@ if (DARWIN) set(CELLFRAME_LIBS ${CELLFRAME_LIBS} bz2) endif() -target_link_libraries(${PROJECT_NAME} ${CELLFRAME_LIBS}) +set(CELLFRAME_LIBS ${CELLFRAME_LIBS} crc32c_adler) + + + +target_link_libraries(${PROJECT_NAME} ${CELLFRAME_LIBS} crc32c_adler) #if(BUILD_DAP_TESTS) # file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test/main_test.py # DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c index 04404537e8b3dd62802b9b0dd0b06d7b98d4cc9a..11acd29739b4d6227de7b2f3013c05168cd52c02 100644 --- a/modules/net/dap_chain_node_cli.c +++ b/modules/net/dap_chain_node_cli.c @@ -118,8 +118,12 @@ int dap_chain_node_cli_init(dap_config_t * g_config) "? [<command>]\n" "\tObtain help for <command> or get the total list of the commands\n" ); - dap_cli_server_cmd_add("wallet", com_tx_wallet, "Wallet operations", - "wallet {new -w <wallet_name> [-sign <sign_type>] [-restore <hex_value>] [-net <net_name>] [-force] | list | info {-addr <addr> | -w <wallet_name>} -net <net_name>}\n"); + dap_cli_server_cmd_add ("wallet", com_tx_wallet, "Wallet operations", + "wallet list\n" + "wallet new -w <wallet_name> [-sign <sign_type>] [-restore <hex_value>] [-net <net_name>] [-force] [-password <password>] [-restore <hash>]\n" + "wallet info {-addr <addr> | -w <wallet_name>} -net <net_name>\n" + "wallet activate -w <wallet_name> -password <password> [-ttl <password_ttl_in_minutes>]\n" + "wallet deactivate -w <wallet_name> -password <password>\n"); // Token commands dap_cli_server_cmd_add ("token_update", com_token_update, "Token update", diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c index 462e95f2c1415d656230724f1e8f9e06952ae584..a8ce008a4056a1edc585a46803473aaf9252ede3 100644 --- a/modules/net/dap_chain_node_cli_cmd.c +++ b/modules/net/dap_chain_node_cli_cmd.c @@ -1696,26 +1696,29 @@ int com_help(int argc, char ** argv, char **str_reply) * @param str_reply * @return int */ +#if 0 int com_tx_wallet(int argc, char ** argv, char **str_reply) { - const char *c_wallets_path = dap_chain_wallet_get_path(g_config); - // Get address of wallet - enum { - CMD_NONE, CMD_WALLET_NEW, CMD_WALLET_LIST, CMD_WALLET_INFO - }; - int arg_index = 1; - int cmd_num = CMD_NONE; +const char *c_wallets_path = dap_chain_wallet_get_path(g_config); +enum { CMD_NONE, CMD_WALLET_NEW, CMD_WALLET_LIST, CMD_WALLET_INFO, CMD_WALLET_ACTIVATE, CMD_WALLET_DEACTIVATE }; +int l_arg_index = 1, l_rc, cmd_num = CMD_NONE; +char l_buf[1024]; + + // find add parameter ('alias' or 'handshake') - if(dap_cli_server_cmd_find_option_val(argv, arg_index, min(argc, arg_index + 1), "new", NULL)) { + if(dap_cli_server_cmd_find_option_val(argv, l_arg_index, min(argc, l_arg_index + 1), "new", NULL)) cmd_num = CMD_WALLET_NEW; - } - else if(dap_cli_server_cmd_find_option_val(argv, arg_index, min(argc, arg_index + 1), "list", NULL)) { + else if(dap_cli_server_cmd_find_option_val(argv, l_arg_index, min(argc, l_arg_index + 1), "list", NULL)) cmd_num = CMD_WALLET_LIST; - } - else if(dap_cli_server_cmd_find_option_val(argv, arg_index, min(argc, arg_index + 1), "info", NULL)) { + else if(dap_cli_server_cmd_find_option_val(argv, l_arg_index, min(argc, l_arg_index + 1), "info", NULL)) cmd_num = CMD_WALLET_INFO; - } - arg_index++; + else if(dap_cli_server_cmd_find_option_val(argv, l_arg_index, min(argc, l_arg_index + 1), "activate", NULL)) + cmd_num = CMD_WALLET_ACTIVATE; + else if(dap_cli_server_cmd_find_option_val(argv, l_arg_index, min(argc, l_arg_index + 1), "deactivate", NULL)) + cmd_num = CMD_WALLET_DEACTIVATE; + + l_arg_index++; + if(cmd_num == CMD_NONE) { dap_cli_server_cmd_set_reply_text(str_reply, "Format of command: wallet [new -w <wallet_name> | list | info [<-addr <addr>]|[-w <wallet_name> -net <net_name>]"); @@ -1930,6 +1933,319 @@ int com_tx_wallet(int argc, char ** argv, char **str_reply) *str_reply = dap_string_free(l_string_ret, false); return 0; } +#endif + +int com_tx_wallet(int argc, char ** argv, char **str_reply) +{ +const char *c_wallets_path = dap_chain_wallet_get_path(g_config); +enum { CMD_NONE, CMD_WALLET_NEW, CMD_WALLET_LIST, CMD_WALLET_INFO, CMD_WALLET_ACTIVATE, CMD_WALLET_DEACTIVATE }; +int l_arg_index = 1, l_rc, cmd_num = CMD_NONE; +char l_buf[1024]; + + + // find add parameter ('alias' or 'handshake') + if(dap_cli_server_cmd_find_option_val(argv, l_arg_index, min(argc, l_arg_index + 1), "new", NULL)) + cmd_num = CMD_WALLET_NEW; + else if(dap_cli_server_cmd_find_option_val(argv, l_arg_index, min(argc, l_arg_index + 1), "list", NULL)) + cmd_num = CMD_WALLET_LIST; + else if(dap_cli_server_cmd_find_option_val(argv, l_arg_index, min(argc, l_arg_index + 1), "info", NULL)) + cmd_num = CMD_WALLET_INFO; + else if(dap_cli_server_cmd_find_option_val(argv, l_arg_index, min(argc, l_arg_index + 1), "activate", NULL)) + cmd_num = CMD_WALLET_ACTIVATE; + else if(dap_cli_server_cmd_find_option_val(argv, l_arg_index, min(argc, l_arg_index + 1), "deactivate", NULL)) + cmd_num = CMD_WALLET_DEACTIVATE; + + l_arg_index++; + + if(cmd_num == CMD_NONE) { + dap_cli_server_cmd_set_reply_text (str_reply, + "Format of command: wallet {new -w <wallet_name> | list | info [-addr <addr>]|[-w <wallet_name> -net <net_name>]}"); + return -1; + } + + const char *l_addr_str = NULL, *l_wallet_name = NULL, *l_net_name = NULL, *l_sign_type_str = NULL, *l_restore_str = NULL, + *l_pass_str = NULL, *l_ttl_str = NULL; + + // find wallet addr + dap_cli_server_cmd_find_option_val(argv, l_arg_index, argc, "-addr", &l_addr_str); + dap_cli_server_cmd_find_option_val(argv, l_arg_index, argc, "-w", &l_wallet_name); + dap_cli_server_cmd_find_option_val(argv, l_arg_index, argc, "-net", &l_net_name); + + + + dap_chain_net_t * l_net = l_net_name ? dap_chain_net_by_name( l_net_name) : NULL; + + dap_string_t *l_string_ret = dap_string_new(NULL); + + + switch (cmd_num) + { + case CMD_WALLET_ACTIVATE: + case CMD_WALLET_DEACTIVATE: + dap_cli_server_cmd_find_option_val(argv, l_arg_index, argc, "-password", &l_pass_str); + dap_cli_server_cmd_find_option_val(argv, l_arg_index, argc, "-ttl", &l_ttl_str); + + + if( !l_wallet_name ) + return dap_cli_server_cmd_set_reply_text(str_reply, "Wallet name option <-w> not defined"), -EINVAL; + + if( !l_pass_str ) + return dap_cli_server_cmd_set_reply_text(str_reply, "Wallet password option <-password> not defined"), -EINVAL; + + if ( l_ttl_str ) + l_rc = strtoul(l_ttl_str, NULL, 10); + else l_rc = 60; + l_rc = l_rc ? l_rc : 60; + + if ( cmd_num == CMD_WALLET_ACTIVATE ) + l_rc = dap_chain_wallet_activate (l_wallet_name, strlen(l_wallet_name), l_pass_str, strlen(l_pass_str), l_rc ); + else l_rc = dap_chain_wallet_deactivate (l_wallet_name, strlen(l_wallet_name), l_pass_str, strlen(l_pass_str) ); + + if ( !l_rc ) + dap_string_append_printf(l_string_ret, "Wallet: %s is %sactivated\n", + l_wallet_name, cmd_num == CMD_WALLET_ACTIVATE ? "" : "de"); + else + { + switch ( l_rc ) + { + case -EBUSY: + strcpy(l_buf, "already activated"); + break; + + case -EINVAL: + strcpy(l_buf, "wrong password"); + break; + + + default: + strerror_r(l_rc, l_buf, sizeof(l_buf) - 1 ); + break; + } + + dap_string_append_printf(l_string_ret, "Wallet: %s %sactivation error, errno=%d (%s)\n", + l_wallet_name, cmd_num == CMD_WALLET_ACTIVATE ? "" : "de", l_rc, l_buf ); + } + + break; + + + // new wallet + case CMD_WALLET_NEW: { + dap_cli_server_cmd_find_option_val(argv, l_arg_index, argc, "-password", &l_pass_str); + dap_cli_server_cmd_find_option_val(argv, l_arg_index, argc, "-sign", &l_sign_type_str); + dap_cli_server_cmd_find_option_val(argv, l_arg_index, argc, "-restore", &l_restore_str); + // rewrite existing wallet + int l_is_force = dap_cli_server_cmd_find_option_val(argv, l_arg_index, argc, "-force", NULL); + + if(!l_wallet_name) { + dap_cli_server_cmd_set_reply_text(str_reply, "Wallet name option <-w> not defined"); + return -1; + } + // Check if wallet name has only digits and English letter + if (!dap_isstralnum(l_wallet_name)){ + dap_cli_server_cmd_set_reply_text(str_reply, "Wallet name must contains digits and aplhabetical symbols"); + return -1; + } + + // check wallet existence + if (!l_is_force) { + char *l_file_name = dap_strdup_printf("%s/%s.dwallet", c_wallets_path, l_wallet_name); + FILE *l_exists = fopen(l_file_name, "rb"); + DAP_DELETE(l_file_name); + if (l_exists) { + dap_cli_server_cmd_set_reply_text(str_reply, "Wallet %s already exists", l_wallet_name); + fclose(l_exists); + return -1; + } + } + + dap_sign_type_t l_sign_type; + if (!l_sign_type_str) { + l_sign_type.type = SIG_TYPE_DILITHIUM; + l_sign_type_str = dap_sign_type_to_str(l_sign_type); + } else { + l_sign_type = dap_sign_type_from_str(l_sign_type_str); + if (l_sign_type.type == SIG_TYPE_NULL){ + dap_cli_server_cmd_set_reply_text(str_reply, "Unknown signature type"); + return -1; + } + } + + // + // Check unsupported tesla algorithm + // + + if (l_sign_type.type == SIG_TYPE_TESLA) + return dap_cli_server_cmd_set_reply_text(str_reply, "Tesla algorithm is no longer supported, please, use another variant"), -1; + + uint8_t *l_seed = NULL; + size_t l_seed_size = 0, l_restore_str_size = dap_strlen(l_restore_str); + + if(l_restore_str && l_restore_str_size > 2 && !dap_strncmp(l_restore_str, "0x", 2)) { + l_seed_size = (l_restore_str_size - 2) / 2; + l_seed = DAP_NEW_SIZE(uint8_t, l_seed_size); + if(!dap_hex2bin(l_seed, l_restore_str + 2, l_restore_str_size - 2)){ + DAP_DELETE(l_seed); + l_seed = NULL; + l_seed_size = 0; + dap_cli_server_cmd_set_reply_text(str_reply, "Restored hash is invalid, wallet is not created"); + return -1; + } + } + // Creates new wallet + dap_chain_wallet_t *l_wallet = dap_chain_wallet_create_with_seed(l_wallet_name, c_wallets_path, l_sign_type, + l_seed, l_seed_size, l_pass_str); + + if (!l_wallet) + return dap_cli_server_cmd_set_reply_text(str_reply, "Wallet is not created because of internal error"), -1; + + dap_chain_addr_t *l_addr = l_net? dap_chain_wallet_get_addr(l_wallet,l_net->pub.id ) : NULL; + + char *l_addr_str = l_addr? dap_chain_addr_to_str(l_addr) : NULL; + dap_string_append_printf(l_string_ret, "Wallet: %s (type=%s) successfully created\n", l_wallet->name, l_sign_type_str); + if ( l_addr_str ) { + dap_string_append_printf(l_string_ret, "new address %s", l_addr_str); + DAP_DELETE(l_addr_str); + } + dap_chain_wallet_close(l_wallet); + } + break; + + + // wallet list + case CMD_WALLET_LIST: + { + DIR * l_dir = opendir(c_wallets_path); + if(l_dir) { + struct dirent * l_dir_entry; + + while( (l_dir_entry = readdir(l_dir)) ) + { + const char *l_file_name = l_dir_entry->d_name; + size_t l_file_name_len = (l_file_name) ? strlen(l_file_name) : 0; + + if ( (l_file_name_len > 8) && (!strcmp(l_file_name + l_file_name_len - 8, ".dwallet")) ) + { + + char l_file_path_tmp[MAX_PATH] = {0}; + dap_snprintf(l_file_path_tmp, sizeof(l_file_path_tmp) - 1, "%s/%s", c_wallets_path, l_file_name); + + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_file_name, c_wallets_path); + + if (l_wallet) + { + dap_chain_addr_t *l_addr = l_net? dap_chain_wallet_get_addr(l_wallet, l_net->pub.id) : NULL; + char *l_addr_str = dap_chain_addr_to_str(l_addr); + + dap_string_append_printf(l_string_ret, "Wallet: %s%s\n", l_wallet->name, + (l_wallet->flags & DAP_WALLET$M_FL_ACTIVE) ? " (Active)" : ""); + + if (l_addr_str) + { + dap_string_append_printf(l_string_ret, "addr: %s\n", (l_addr_str) ? l_addr_str : "-"); + DAP_DELETE(l_addr_str); + } + + dap_chain_wallet_close(l_wallet); + + } else dap_string_append_printf(l_string_ret, "Wallet: %.*s (non-Active)\n", (int) l_file_name_len - 8, l_file_name); + } + } + closedir(l_dir); + } + } + break; + + // wallet info + case CMD_WALLET_INFO: { + dap_chain_wallet_t *l_wallet = NULL; + dap_chain_addr_t *l_addr = NULL; + + if(l_wallet_name) { + l_wallet = dap_chain_wallet_open(l_wallet_name, c_wallets_path); + if ( l_net ) + l_addr = (dap_chain_addr_t *) dap_chain_wallet_get_addr(l_wallet, l_net->pub.id ); + } + if(!l_addr && l_addr_str) + l_addr = dap_chain_addr_from_str(l_addr_str); + + dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name((const char *) l_net_name); + if(!l_net_name && !l_addr ) { + dap_cli_server_cmd_set_reply_text(str_reply, "Subcommand info requires parameter '-net'"); + return -1; + } + else if (! l_addr){ + if((l_ledger = dap_chain_ledger_by_net_name(l_net_name)) == NULL) { + dap_cli_server_cmd_set_reply_text(str_reply, "Not found net by name '%s'", l_net_name); + return -1; + } + }else{ + l_net = dap_chain_net_by_id(l_addr->net_id); + if (l_net){ + l_ledger = l_net->pub.ledger; + l_net_name = l_net->pub.name; + }else{ + dap_cli_server_cmd_set_reply_text(str_reply, "Can't find network id 0x%08X from address %s", l_addr->net_id.uint64, + l_addr_str); + return -1; + + } + } + + if(l_addr) { + char *l_addr_str = dap_chain_addr_to_str((dap_chain_addr_t*) l_addr); + if(l_wallet) + dap_string_append_printf(l_string_ret, "wallet: %s\n", l_wallet->name); + dap_string_append_printf(l_string_ret, "addr: %s\n", (l_addr_str) ? l_addr_str : "-"); + dap_string_append_printf(l_string_ret, "network: %s\n", (l_net_name ) ? l_net_name : "-"); + + size_t l_l_addr_tokens_size = 0; + char **l_l_addr_tokens = NULL; + dap_chain_ledger_addr_get_token_ticker_all(l_ledger, l_addr, &l_l_addr_tokens, &l_l_addr_tokens_size); + if(l_l_addr_tokens_size > 0) + dap_string_append_printf(l_string_ret, "balance:\n"); + else + dap_string_append_printf(l_string_ret, "balance: 0"); + + for(size_t i = 0; i < l_l_addr_tokens_size; i++) { + if(l_l_addr_tokens[i]) { + uint256_t l_balance = dap_chain_ledger_calc_balance(l_ledger, l_addr, l_l_addr_tokens[i]); + char *l_balance_coins = dap_chain_balance_to_coins(l_balance); + char *l_balance_datoshi = dap_chain_balance_print(l_balance); + dap_string_append_printf(l_string_ret, "\t%s (%s) %s\n", l_balance_coins, + l_balance_datoshi, l_l_addr_tokens[i]); + if(i < l_l_addr_tokens_size - 1) + dap_string_append_printf(l_string_ret, "\n"); + DAP_DELETE(l_balance_coins); + DAP_DELETE(l_balance_datoshi); + + } + DAP_DELETE(l_l_addr_tokens[i]); + } + DAP_DELETE(l_l_addr_tokens); + DAP_DELETE(l_addr_str); + if(l_wallet) + dap_chain_wallet_close(l_wallet); + } + else { + if(l_wallet) + dap_chain_wallet_close(l_wallet); + + dap_string_free(l_string_ret, true); + dap_cli_server_cmd_set_reply_text(str_reply, "Wallet not found"); + return -1; + } + } + break; + } + + *str_reply = dap_string_free(l_string_ret, false); + return 0; +} + + + + /** * @brief s_values_parse_net_chain @@ -2031,7 +2347,7 @@ static dap_chain_datum_token_t * s_sign_cert_in_cycle(dap_cert_t ** l_certs, dap } size_t l_tsd_size = 0; - if ((l_datum_token->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL) + if ((l_datum_token->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL) || (l_datum_token->type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL)) l_tsd_size = l_datum_token->header_native_decl.tsd_total_size; diff --git a/modules/wallet/CMakeLists.txt b/modules/wallet/CMakeLists.txt index 4feeb32d5872d7fa6d33d657452044dd6cb4376a..b6219a6e2485b05cdb583844bf63d864e40bfc70 100644 --- a/modules/wallet/CMakeLists.txt +++ b/modules/wallet/CMakeLists.txt @@ -1,12 +1,12 @@ cmake_minimum_required(VERSION 3.10) project (dap_chain_wallet) - + file(GLOB DAP_CHAIN_WALLET_SRCS *.c) file(GLOB DAP_CHAIN_WALLET_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_WALLET_SRCS} ${DAP_CHAIN_WALLET_HEADERS}) -target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_chain_net) +target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_chain_net crc32c_adler) target_include_directories(${PROJECT_NAME} INTERFACE .) target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/wallet/dap_chain_wallet.c b/modules/wallet/dap_chain_wallet.c index d51811c615965d35230fe12fb3579a1422212d2b..fd7e2aceff5130323258b323293a7cba3223ec00 100644 --- a/modules/wallet/dap_chain_wallet.c +++ b/modules/wallet/dap_chain_wallet.c @@ -20,6 +20,11 @@ You should have received a copy of the GNU General Public License along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. + + MODIFICATION HISTORY: + + 27-APR-2021 RRL Added password protected wallet support + */ #include <stdlib.h> @@ -35,6 +40,7 @@ #ifdef DAP_OS_UNIX #include <sys/types.h> #include <sys/stat.h> +#include <sys/uio.h> #endif #ifdef WIN32 @@ -46,6 +52,8 @@ #endif #include <pthread.h> +#include "crc32c_adler.h" + #include "dap_common.h" #include "dap_strfuncs.h" @@ -53,42 +61,294 @@ #include "dap_cert_file.h" #include "dap_chain_wallet.h" #include "dap_chain_wallet_internal.h" +#include "dap_enc_key.h" #define LOG_TAG "dap_chain_wallet" + /* An argument for open()/create() */ +static const mode_t s_fileprot = ( S_IREAD | S_IWRITE) | (S_IREAD >> 3) | (S_IREAD >> 6) ; +static char s_wallet_ext [] = ".dwallet"; + + +static pthread_rwlock_t s_wallet_n_pass_lock = PTHREAD_RWLOCK_INITIALIZER; /* Coordinate access to the hash-table */ +static dap_chain_wallet_n_pass_t *s_wallet_n_pass; /* A hash table to keep passwords for wallets */ + + + +/* CRC32-C */ +#define CRC32C_INIT 0xEDB88320 + + +/* + * DESCRIPTION: Add/update a record for wallet into the internaly used table of name/password pair. + * Thhose records are supposed to be used for operations with the password-protected wallets. + * + * INPUTS: + * a_name: A name of the wallet + * a_name_len: A length of the wallet's name + * a_pass: A password string + * a_pass_len: A length of the password string + * a_ttl: A time to live of the wallet's context, minutes + * + * IMPLICITE OUTPUTS: + * s_wallet_n_pass + * + * RETURNS: + * 0 - Success + * <0 - <errno> + */ + +int dap_chain_wallet_activate ( + const char *a_name, + ssize_t a_name_len, + const char *a_pass, + ssize_t a_pass_len, + unsigned a_ttl + ) +{ +int l_rc, l_rc2; +dap_chain_wallet_n_pass_t l_rec = {0}, *l_prec; +dap_chain_wallet_t *l_wallet; +char *c_wallets_path; + + /* Sanity checks ... */ + if ( a_name_len > DAP_WALLET$SZ_NAME ) + return log_it(L_ERROR, "Wallet's name is too long (%d > %d)", a_name_len, DAP_WALLET$SZ_NAME), -EINVAL; + + if ( a_pass_len > DAP_WALLET$SZ_PASS ) + return log_it(L_ERROR, "Wallet's password is too long (%d > %d)", a_pass_len, DAP_WALLET$SZ_PASS), -EINVAL; + + + memcpy(l_rec.name, a_name, l_rec.name_len = a_name_len); /* Prefill local record fields */ + memcpy(l_rec.pass, a_pass, l_rec.pass_len = a_pass_len); + + if ( (l_rc2 = pthread_rwlock_wrlock(&s_wallet_n_pass_lock)) ) /* Lock for WR access */ + return log_it(L_ERROR, "Error locking Wallet table, errno=%d", l_rc2), -l_rc2; + + HASH_FIND_STR(s_wallet_n_pass, a_name, l_prec); /* Check for existen record */ + + + l_rc = 0; + + if ( !l_prec ) + { + l_prec = DAP_NEW_Z(dap_chain_wallet_n_pass_t); /* Get memory for new record */ + *l_prec = l_rec; /* Fill it by data */ + HASH_ADD_STR(s_wallet_n_pass, name, l_prec); /* Add into the hash-table */ + } + else { + if ( !l_prec->pass_len ) /* Password field is empty ? */ + memcpy(l_prec->pass, a_pass, l_prec->pass_len = a_pass_len);/* Update password with new one */ + + else l_rc = -EBUSY, log_it(L_ERROR, "Wallet has been activated, do deactivation first"); + } + + + clock_gettime(CLOCK_REALTIME, &l_prec->exptm); + l_prec->exptm.tv_sec += (a_ttl * 60); /* Compute context expiration time */ + + + if ( (l_rc2 = pthread_rwlock_unlock(&s_wallet_n_pass_lock)) ) /* Release lock */ + log_it(L_ERROR, "Error unlocking Wallet table, errno=%d", l_rc2); + + + /* + * Check password by open/close BMF Wallet file + */ + if ( !(c_wallets_path = (char *) dap_chain_wallet_get_path(g_config)) ) /* No path to wallets - nothing to do */ + { + memset(l_prec->pass, 0, l_prec->pass_len), l_prec->pass_len = 0; + return log_it(L_ERROR, "Wallet's path has been not configured"), -EINVAL; + } + + if ( !(l_wallet = dap_chain_wallet_open (a_name, c_wallets_path)) ) + { + memset(l_prec->pass, 0, l_prec->pass_len), l_prec->pass_len = 0; + return log_it(L_ERROR, "Wallet's password is invalid"), -EINVAL; + } + + dap_chain_wallet_close( l_wallet); + + return l_rc; +} + +/* + * DESCRIPTIOB: Lookup and retrieve password for a given wallet. A buffer for a_pass should be enough + * to accept password string up to DAP_WALLET$SZ_PASS octets + * + * INPUTS: + * a_name: A name of the wallet + * a_name_len: A length of the wallet's name + a_pass_len: A size of the buffer to accept password + * + * IMPLICITE INPUTS: + * s_wallet_n_pass + * + * OUTPUTS: + * a_pass: A password string + * a_pass_len: A length of the password string + * + * RETURNS: + * 0 - Success, <a_pass> and a_pass_len contains actual data + * <0 - <errno> + */ + +int s_dap_chain_wallet_pass ( + const char *a_name, + ssize_t a_name_len, + char *a_pass, + ssize_t *a_pass_len + ) +{ +int l_rc; +dap_chain_wallet_n_pass_t *l_prec; +struct timespec l_now; + + /* Sanity checks ... */ + if ( a_name_len > DAP_WALLET$SZ_NAME ) + return log_it(L_ERROR, "Wallet's name is too long (%d > %d)", a_name_len, DAP_WALLET$SZ_NAME), -EINVAL; + + if ( *a_pass_len < DAP_WALLET$SZ_PASS ) + return log_it(L_ERROR, "Wallet's buffer for password is too small (%d < %d)", *a_pass_len, DAP_WALLET$SZ_PASS), -EINVAL; + + + clock_gettime(CLOCK_REALTIME, &l_now); + + + if ( (l_rc = pthread_rwlock_rdlock(&s_wallet_n_pass_lock)) ) /* Lock for RD access */ + return log_it(L_ERROR, "Error locking Wallet table, errno=%d", l_rc), -l_rc; + + HASH_FIND_STR(s_wallet_n_pass, a_name, l_prec); /* Check for existen record */ + + + if (l_prec && (l_now.tv_sec > l_prec->exptm.tv_sec) ) /* Record is expired ? */ + { + /* Reset password field */ + memset(l_prec->pass, l_prec->pass_len = 0, sizeof(l_prec->pass)); + l_prec = NULL; //log_it(L_ERROR, "Wallet's credential has been expired, need re-Activation "); + } + else if ( l_prec && !l_prec->pass_len ) /* Is record has been deactivated ? */ + l_prec = NULL; // log_it(L_ERROR, "Wallet's credential has been zeroed, need re-Activation "); + else if ( l_prec ) /* Store password to given buffer */ + memcpy(a_pass, l_prec->pass, *a_pass_len = l_prec->pass_len); + + if ( (l_rc = pthread_rwlock_unlock(&s_wallet_n_pass_lock)) ) /* Release lock */ + log_it(L_ERROR, "Error locking Wallet table, errno=%d", l_rc); + + return l_prec ? 0 : -ENOENT; +} + + + +/* + * DESCRIPTION: Deactivate a data for the wallet's name & password pair. For existen record just clearing password field. + * Use given password to additional verification. We don't remove record from the hash table - only reset to zero the password field ! + * + * INPUTS: + * a_name: A name of the wallet + * a_name_len: A length of the wallet's name + * a_pass: A password string + * a_pass_len: A length of the password string + * + * IMPLICITE OUTPUTS: + * s_wallet_n_pass + * + * RETURNS: + * 0 - Success + * <0 - <errno> + */ +int dap_chain_wallet_deactivate ( + const char *a_name, + ssize_t a_name_len, + const char *a_pass, + ssize_t a_pass_len + ) +{ +int l_rc, l_rc2; +dap_chain_wallet_n_pass_t *l_prec; + + if ( a_name_len > DAP_WALLET$SZ_NAME ) + return log_it(L_ERROR, "Wallet's name is too long (%d > %d)", a_name_len, DAP_WALLET$SZ_NAME), -EINVAL; + + if ( (l_rc = pthread_rwlock_wrlock(&s_wallet_n_pass_lock)) ) /* Lock for WR access */ + return log_it(L_ERROR, "Error locking Wallet table, errno=%d", l_rc), -l_rc; + + l_rc = -ENOENT; + + HASH_FIND_STR(s_wallet_n_pass, a_name, l_prec); /* Check for existen record */ + + if ( l_prec ) + { + if ( !l_prec->pass_len ) /* Password is zero - has been reset probably */ + log_it(L_WARNING, "The Wallet %.*s is not active", a_name_len, a_name); + + else if ( (l_prec->pass_len != a_pass_len) /* Check that passwords is equivalent */ + || memcmp(l_prec->pass, a_pass, l_prec->pass_len) ) + l_rc = -EINVAL, log_it(L_ERROR, "Wallet's password does not match"); + + else l_rc = 0, memset(l_prec->pass, l_prec->pass_len = 0, sizeof(l_prec->pass)); + } + + if ( (l_rc2 = pthread_rwlock_unlock(&s_wallet_n_pass_lock)) ) /* Release lock */ + log_it(L_ERROR, "Error unlocking Wallet table, errno=%d", l_rc2); + + return l_rc; +} + + + + + + + + + + /** * @brief dap_chain_wallet_init * @return */ int dap_chain_wallet_init(void) { - // load certificates from existing wallets - const char *c_wallets_path = dap_chain_wallet_get_path(g_config); - if(c_wallets_path) { - DIR * l_dir = opendir(c_wallets_path); - if (l_dir) { - struct dirent * l_dir_entry; - while((l_dir_entry = readdir(l_dir)) != NULL) { - const char *l_file_name = l_dir_entry->d_name; - size_t l_file_name_len = (l_file_name) ? strlen(l_file_name) : 0; - if((l_file_name_len > 8) && (strcmp(l_file_name + l_file_name_len - 8, ".dwallet") == 0)) { - char l_file_path_tmp[MAX_PATH] = {'\0'}; - dap_sprintf(l_file_path_tmp, "%s/%s", c_wallets_path, l_file_name); - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open_file(l_file_path_tmp); - if(l_wallet) { - dap_chain_wallet_close(l_wallet); - } - } - } - closedir(l_dir); - } else { +char *c_wallets_path, l_fspec[MAX_PATH] = {0}; +DIR * l_dir; +struct dirent * l_dir_entry; +dap_chain_wallet_t *l_wallet; +size_t l_len; + + if ( !(c_wallets_path = (char *) dap_chain_wallet_get_path(g_config)) ) /* No path to wallets - nothing to do */ + return 0; + + if ( !(l_dir = opendir(c_wallets_path)) ) /* Path is not exist ? Create the dir and exit */ + { #ifdef _WIN32 - mkdir(c_wallets_path); + mkdir(c_wallets_path); #else - mkdir(c_wallets_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + mkdir(c_wallets_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); #endif + return 0; + } + + /* + * Load certificates from existing no-password-protected (!!!) wallets + */ + while( (l_dir_entry = readdir(l_dir))) + { + if ( l_dir_entry->d_type != DT_REG ) /* Skip unrelated entries */ + continue; + + l_len = strlen(l_dir_entry->d_name); /* Check for *.dwallet */ + + if ( (l_len > 8) && (strcmp(l_dir_entry->d_name + l_len - (sizeof(s_wallet_ext) - 1), s_wallet_ext) == 0) ) + { + dap_snprintf(l_fspec, sizeof(l_fspec) - 1, "%s/%s", c_wallets_path, l_dir_entry->d_name); + + if ( (l_wallet = dap_chain_wallet_open_file(l_fspec, NULL)) ) + dap_chain_wallet_close(l_wallet); } } + + closedir(l_dir); return 0; } @@ -105,14 +365,21 @@ void dap_chain_wallet_deinit(void) * @param[in] a_config Configuration * @return wallets path or NULL if error */ +static char s_wallets_path[MAX_PATH]; + const char* dap_chain_wallet_get_path(dap_config_t * a_config) { - static char l_wallets_path[MAX_PATH]; - if (strlen(l_wallets_path) > 3) - goto RET; - dap_sprintf(l_wallets_path, "%s", dap_config_get_item_str(g_config, "resources", "wallets_path")); -RET: - return l_wallets_path; +char *l_cp; + + if ( s_wallets_path[0] ) /* Is the path to the wallet's store has been defined ? */ + return s_wallets_path; /* Fine, just return existen value */ + + /* Retrieve Wallet's store path from config */ + if ( !(l_cp = (char *) dap_config_get_item_str(g_config, "resources", "wallets_path")) ) + return log_it(L_WARNING, "No path to wallet's store has been defined"), s_wallets_path; + + + return strncpy(s_wallets_path, l_cp, sizeof(s_wallets_path) - 1 ); /* Make local copy , return it to caller */ } /** @@ -124,31 +391,54 @@ RET: * @details Creates new wallet * @return Wallet, new wallet or NULL if errors */ -dap_chain_wallet_t * dap_chain_wallet_create_with_seed(const char * a_wallet_name, const char * a_wallets_path, - dap_sign_type_t a_sig_type, const void* a_seed, size_t a_seed_size) +dap_chain_wallet_t * dap_chain_wallet_create_with_seed ( + const char * a_wallet_name, + const char * a_wallets_path, + dap_sign_type_t a_sig_type, + const void* a_seed, + size_t a_seed_size, + const char *a_pass + ) { - dap_chain_wallet_t * l_wallet = DAP_NEW_Z(dap_chain_wallet_t); - DAP_CHAIN_WALLET_INTERNAL_LOCAL_NEW(l_wallet); - l_wallet->name = strdup(a_wallet_name); - l_wallet_internal->certs_count = 1; - l_wallet_internal->certs = DAP_NEW_Z_SIZE(dap_cert_t *,l_wallet_internal->certs_count * sizeof(dap_cert_t *)); +dap_chain_wallet_t *l_wallet; +dap_chain_wallet_internal_t *l_wallet_internal; +int l_rc, l_wallet_name_len, l_pass_len; + + /* Sanity checks ... */ + if ( DAP_WALLET$SZ_NAME < (l_wallet_name_len = strnlen(a_wallet_name, DAP_WALLET$SZ_NAME + 1)) ) + return log_it(L_ERROR, "Wallet's name is too long ( > %d)", DAP_WALLET$SZ_NAME), NULL; + + if ( DAP_WALLET$SZ_PASS < (l_pass_len = strnlen(a_wallet_name, DAP_WALLET$SZ_PASS + 1)) ) + return log_it(L_ERROR, "Wallet's password is too long ( > %d)", DAP_WALLET$SZ_PASS), NULL; + + if ( !(l_wallet = DAP_NEW_Z(dap_chain_wallet_t)) ) + return log_it(L_ERROR, "Memory allocation error, errno=&d", errno), NULL; - size_t l_file_name_size = strlen(a_wallet_name)+strlen(a_wallets_path)+13; - l_wallet_internal->file_name = DAP_NEW_Z_SIZE (char, l_file_name_size); + if ( !(l_wallet->_internal = l_wallet_internal = DAP_NEW_Z(dap_chain_wallet_internal_t)) ) + return DAP_DELETE(l_wallet), log_it(L_ERROR, "Memory allocation error, errno=&d", errno), NULL; - dap_snprintf(l_wallet_internal->file_name,l_file_name_size,"%s/%s.dwallet",a_wallets_path,a_wallet_name); - l_wallet_internal->certs[0] = dap_cert_generate_mem_with_seed(a_wallet_name, - dap_sign_type_to_key_type(a_sig_type), a_seed, a_seed_size); + strncpy(l_wallet->name, a_wallet_name, DAP_WALLET$SZ_NAME); + l_wallet_internal->certs_count = 1; + l_wallet_internal->certs = DAP_NEW_Z_SIZE(dap_cert_t *,l_wallet_internal->certs_count * sizeof(dap_cert_t *)); + assert(l_wallet_internal->certs); + + dap_snprintf(l_wallet_internal->file_name, sizeof(l_wallet_internal->file_name) - 1, "%s/%s%s", a_wallets_path, a_wallet_name, s_wallet_ext); + + l_wallet_internal->certs[0] = dap_cert_generate_mem_with_seed(a_wallet_name, dap_sign_type_to_key_type(a_sig_type), a_seed, a_seed_size); - if ( dap_chain_wallet_save(l_wallet) == 0 ) + if ( !(l_rc = dap_chain_wallet_save(l_wallet, a_pass)) ) + { + log_it(L_INFO, "Wallet %s has been created (%s)", a_wallet_name, l_wallet_internal->file_name); return l_wallet; - else { - log_it(L_ERROR,"Can't save the new wallet in disk: \"%s\"",strerror(errno)); - dap_chain_wallet_close(l_wallet); - return NULL; } + + log_it(L_ERROR,"Can't save the new wallet (%s) to disk, errno=%d", l_wallet_internal->file_name, errno); + dap_chain_wallet_close(l_wallet); + + return NULL; + } /** @@ -160,9 +450,14 @@ dap_chain_wallet_t * dap_chain_wallet_create_with_seed(const char * a_wallet_nam * @details Creates new wallet * @return Wallet, new wallet or NULL if errors */ -dap_chain_wallet_t * dap_chain_wallet_create(const char * a_wallet_name, const char * a_wallets_path, dap_sign_type_t a_sig_type) +dap_chain_wallet_t * dap_chain_wallet_create( + const char * a_wallet_name, + const char * a_wallets_path, + dap_sign_type_t a_sig_type, + const char *a_pass + ) { - return dap_chain_wallet_create_with_seed(a_wallet_name, a_wallets_path, a_sig_type, NULL, 0); + return dap_chain_wallet_create_with_seed(a_wallet_name, a_wallets_path, a_sig_type, NULL, 0, a_pass); } /** @@ -171,24 +466,22 @@ dap_chain_wallet_t * dap_chain_wallet_create(const char * a_wallet_name, const c */ void dap_chain_wallet_close( dap_chain_wallet_t * a_wallet) { +dap_chain_wallet_internal_t * l_wallet_internal; + if(!a_wallet) return; - DAP_CHAIN_WALLET_INTERNAL_LOCAL(a_wallet); - if(a_wallet->name) - DAP_DELETE (a_wallet->name); + // TODO Make clean struct dap_chain_wallet_internal_t (certs, addr) - if(l_wallet_internal){ - if(l_wallet_internal->addr) - DAP_DELETE(l_wallet_internal->addr); - if(l_wallet_internal->file_name) - DAP_DELETE(l_wallet_internal->file_name); + if ( (l_wallet_internal = a_wallet->_internal) ) + { if ( l_wallet_internal->certs ) - for(size_t i = 0; i<l_wallet_internal->certs_count;i++) + for(size_t i = 0; i < l_wallet_internal->certs_count; i++) dap_cert_delete( l_wallet_internal->certs[i]); - DAP_DELETE(l_wallet_internal->certs); + DAP_DELETE(l_wallet_internal->certs); DAP_DELETE(l_wallet_internal); } + DAP_DELETE(a_wallet); } @@ -202,8 +495,10 @@ dap_chain_addr_t* dap_chain_wallet_get_addr(dap_chain_wallet_t * a_wallet, dap_c { if(!a_wallet) return NULL; + DAP_CHAIN_WALLET_INTERNAL_LOCAL(a_wallet); - return a_net_id.uint64? dap_cert_to_addr (l_wallet_internal->certs[0], a_net_id) : NULL; + + return a_net_id.uint64 ? dap_cert_to_addr (l_wallet_internal->certs[0], a_net_id) : NULL; } /** @@ -228,12 +523,14 @@ dap_chain_addr_t * dap_cert_to_addr(dap_cert_t * a_cert, dap_chain_net_id_t a_ne dap_pkey_t* dap_chain_wallet_get_pkey( dap_chain_wallet_t * a_wallet,uint32_t a_pkey_idx ) { DAP_CHAIN_WALLET_INTERNAL_LOCAL(a_wallet); - if( l_wallet_internal->certs_count > a_pkey_idx ){ + + if( l_wallet_internal->certs_count > a_pkey_idx ) return dap_cert_to_pkey(l_wallet_internal->certs[a_pkey_idx]); - }else{ - log_it( L_WARNING, "No pkey with index %u in the wallet (total size %zu)",a_pkey_idx,l_wallet_internal->certs_count); - return 0; - } + + + log_it( L_WARNING, "No pkey with index %u in the wallet (total size %zu)", a_pkey_idx, l_wallet_internal->certs_count); + return 0; + } /** @@ -259,161 +556,339 @@ dap_enc_key_t* dap_chain_wallet_get_key( dap_chain_wallet_t * a_wallet,uint32_t { if(!a_wallet) return NULL; + DAP_CHAIN_WALLET_INTERNAL_LOCAL(a_wallet); - if( l_wallet_internal->certs_count > a_pkey_idx ){ - return l_wallet_internal->certs[a_pkey_idx] ? - l_wallet_internal->certs[a_pkey_idx]->enc_key - : NULL; - }else{ - log_it( L_WARNING, "No key with index %u in the wallet (total size %zu)",a_pkey_idx,l_wallet_internal->certs_count); - return 0; - } + + if( l_wallet_internal->certs_count > a_pkey_idx ) + return l_wallet_internal->certs[a_pkey_idx] ? l_wallet_internal->certs[a_pkey_idx]->enc_key : NULL; + + log_it( L_WARNING, "No key with index %u in the wallet (total size %zu)",a_pkey_idx,l_wallet_internal->certs_count); + return 0; } -/** - * @brief dap_chain_wallet_save - * @param a_wallet - * @return +/* + * DESCRIPTION: Save memory wallet's context into the protected by given password. + * + * INPUTS: + * a_wallet: Wallet's context structure + * a_pass: A password string to be used to protect wallet's content + * + * OUTPUTS: + * NONE + * + * RETURNS: + * 0 - SUCCESS + * <errno> */ -int dap_chain_wallet_save(dap_chain_wallet_t * a_wallet) + +int dap_chain_wallet_save(dap_chain_wallet_t * a_wallet, const char *a_pass) { - if ( a_wallet ){ - DAP_CHAIN_WALLET_INTERNAL_LOCAL (a_wallet); - FILE * l_file = fopen( l_wallet_internal->file_name ,"wb"); - if ( l_file ){ - dap_chain_wallet_file_hdr_t l_file_hdr = {0}; - l_file_hdr.signature = DAP_CHAIN_WALLETS_FILE_SIGNATURE; - l_file_hdr.type = 0; - l_file_hdr.version = 1; - size_t i; - // write header - fwrite(&l_file_hdr,1,sizeof(l_file_hdr),l_file); - // write name - uint16_t name_len = (a_wallet->name) ? (uint16_t)strlen(a_wallet->name) : 0; - fwrite(&name_len,1,sizeof(uint16_t),l_file); - fwrite(a_wallet->name,1,name_len,l_file); - // write certs - for ( i = 0; i < l_wallet_internal->certs_count ; i ++) { - dap_chain_wallet_cert_hdr_t l_wallet_cert_hdr = {0}; - l_wallet_cert_hdr.version = 1; - uint32_t l_cert_raw_size=0; - uint8_t * l_buf = dap_cert_mem_save(l_wallet_internal->certs[i], &l_cert_raw_size); - l_wallet_cert_hdr.cert_raw_size= l_cert_raw_size; - fwrite( &l_wallet_cert_hdr,1, sizeof (l_wallet_cert_hdr), l_file); - if ( l_buf ){ - fwrite( l_buf, 1, l_wallet_cert_hdr.cert_raw_size, l_file); - }else{ - log_it(L_WARNING,"Cant write cert to file %s: error \"%s\"",l_wallet_internal->file_name, - strerror(errno)); - } - DAP_DELETE (l_buf); - } - fclose (l_file); - return 0; - }else{ - log_it(L_ERROR,"Cant open file %s for writting",l_wallet_internal->file_name); - return -2; +DAP_CHAIN_WALLET_INTERNAL_LOCAL (a_wallet); /* Declare l_wallet_internal */ +int l_fd = -1, l_rc = 0, l_len = 0; +dap_chain_wallet_file_hdr_t l_file_hdr = {0}; +dap_chain_wallet_cert_hdr_t l_wallet_cert_hdr = {0}; +char *l_cp, *l_cert_raw, l_buf[32*1024]; +dap_enc_key_t *l_enc_key = NULL; +uint32_t csum = CRC32C_INIT; +enum { WALLET$K_IOV_HEADER = 0, WALLET$K_IOV_BODY, WALLET$SZ_IOV_NR}; +struct iovec l_iov [ WALLET$SZ_IOV_NR ]; + + if ( !a_wallet ) + return log_it(L_ERROR, "Wallet is null, can't save it to file!"), -EINVAL; + + if ( a_pass ) + if ( !(l_enc_key = dap_enc_key_new_generate(DAP_ENC_KEY_TYPE_GOST_OFB, NULL, 0, a_pass, strlen(a_pass), 0)) ) + return log_it(L_ERROR, "Error create key context"), -EINVAL; + + if ( 0 > (l_fd = open(l_wallet_internal->file_name , O_CREAT | O_WRONLY, s_fileprot)) ) + return log_it(L_ERROR,"Cant open file %s for writting, errno=%d", l_wallet_internal->file_name, errno), -errno; + + l_file_hdr.signature = DAP_CHAIN_WALLETS_FILE_SIGNATURE; /* Fill and write Wallet's file header */ + l_file_hdr.type = a_pass ? DAP_WALLET$K_TYPE_GOST89 : DAP_WALLET$K_TYPE_PLAIN; + l_file_hdr.version = a_pass ? DAP_WALLET$K_VER_2 : DAP_WALLET$K_VER_1; + + l_cp = a_wallet->name ? a_wallet->name : "Bad-MotherFuqqer-Wallet"; /* What ?! */ + l_file_hdr.wallet_len = strnlen(l_cp, DAP_WALLET$SZ_NAME); + l_file_hdr.wallet_len += 1; /* Special ASCIZ for advanced programmers */ + + l_iov[WALLET$K_IOV_HEADER].iov_base = &l_file_hdr; + l_len = l_iov[WALLET$K_IOV_HEADER].iov_len = sizeof(l_file_hdr); + + l_iov[WALLET$K_IOV_BODY].iov_base = l_cp; + l_len += l_iov[WALLET$K_IOV_BODY].iov_len = l_file_hdr.wallet_len; + + l_rc = writev (l_fd, l_iov, WALLET$SZ_IOV_NR ); /* Performs writting vectorized buffer */ + if ( l_len != l_rc ) + { + close(l_fd); + return log_it(L_ERROR, "Error write Wallet header to file '%s', errno=%d", l_wallet_internal->file_name, errno), -EIO; + } + + /* CRC for file header part */ + csum = crc32c (csum, l_iov[WALLET$K_IOV_HEADER].iov_base, l_iov[WALLET$K_IOV_HEADER].iov_len); + /* CRC for file body part */ + csum = crc32c (csum, l_iov[WALLET$K_IOV_BODY].iov_base, l_iov[WALLET$K_IOV_BODY].iov_len); + + /* Write certs */ + for ( size_t i = 0; i < l_wallet_internal->certs_count ; i++) + { + /* Get ceritificate body */ + if ( !(l_cert_raw = (char *) dap_cert_mem_save(l_wallet_internal->certs[i], (uint32_t *) &l_len)) ) + { + log_it(L_WARNING, "Certificate #%zu cannot be obtained, go next ...", i); + continue; + } + + csum = crc32c (csum, l_cert_raw, l_len); /* CRC for every certificate */ + + if ( l_enc_key ) + { + /* Encrypt buffer with cert to local storage, + * be advised that we don't performs a source buffer aligment preparation according to + * block nature of the GOST family and other block-cyphers. We expect that this work is performed + * by the "enc_na" internaly. So , relax mothefackerzzz! + */ + l_len = l_enc_key->enc_na(l_enc_key, l_cert_raw, l_len, l_buf, sizeof(l_buf) ); } - }else{ - log_it(L_ERROR,"Wallet is null, can't save it to file!"); - return -1; + + l_wallet_cert_hdr.type = DAP_WALLET$K_CERT; /* Prepare on-disk cert record header */ + l_wallet_cert_hdr.cert_raw_size = l_len; + + /* + * Gather chunks for I/O + */ + l_len = 0; /* Total octets to be writtent to disk */ + + l_iov[WALLET$K_IOV_HEADER].iov_base = &l_wallet_cert_hdr; /* Cert's record header */ + l_len += l_iov[WALLET$K_IOV_HEADER].iov_len = sizeof(l_wallet_cert_hdr); + + l_iov[WALLET$K_IOV_BODY].iov_base = l_enc_key ? l_buf : l_cert_raw;/* Cert itself or buffer with has been encrypted cert */ + l_len += l_iov[WALLET$K_IOV_BODY].iov_len = l_wallet_cert_hdr.cert_raw_size; + + l_rc = writev (l_fd, l_iov, WALLET$SZ_IOV_NR ); /* Perform writting vectorized buffer */ + DAP_DEL_Z (l_cert_raw); /* Free cert's memory */ + if ( l_rc != l_len ) /* Check a result of the I/O operation */ + { + close (l_fd); + return log_it(L_ERROR, "Error write %d octets of cert to file '%s', errno=%d", l_len, l_wallet_internal->file_name, errno), errno; + } + } + + if ( l_file_hdr.version == DAP_WALLET$K_VER_2 ) + { + l_wallet_cert_hdr.type = DAP_WALLET$K_MAGIC; + l_wallet_cert_hdr.cert_raw_size = sizeof(csum); + + l_len = 0; /* Total octets to be writtent to disk */ + + l_iov[WALLET$K_IOV_HEADER].iov_base = &l_wallet_cert_hdr; + l_len += l_iov[WALLET$K_IOV_HEADER].iov_len = sizeof(l_wallet_cert_hdr); + + l_iov[WALLET$K_IOV_BODY].iov_base = &csum; + l_len += l_iov[WALLET$K_IOV_BODY].iov_len = sizeof(csum); + + l_rc = writev (l_fd, l_iov, WALLET$SZ_IOV_NR ); /* Perform writting vectorized buffer */ + if ( l_rc != l_len ) /* Check a result of the I/O operation */ + log_it(L_ERROR, "Error write %d octets of cert to file '%s', errno=%d", l_len, l_wallet_internal->file_name, errno); } + + /* Cleanup and exit ... */ + close (l_fd); + + if ( l_enc_key ) + dap_enc_key_delete(l_enc_key); + + + +#ifdef DAP_SYS_DEBUG /* @RRL: For debug purpose only!!! */ + { + dap_chain_wallet_t *l_wallet; + + if ( (l_wallet = dap_chain_wallet_open_file (l_wallet_internal->file_name, a_pass)) ) + dap_chain_wallet_close(l_wallet); + + } +#endif /* DAP_SYS_DEBUG */ + + return log_it(L_NOTICE, "Wallet '%s' has been saved into the '%s'", a_wallet->name, l_wallet_internal->file_name), 0; } + + /** * @brief dap_chain_wallet_open_file * @param a_file_name * @return */ -dap_chain_wallet_t * dap_chain_wallet_open_file(const char * a_file_name) +dap_chain_wallet_t *dap_chain_wallet_open_file ( + const char *a_file_name, + const char *l_pass + ) { - FILE * l_file = fopen( a_file_name ,"rb"); - if(!l_file){ - log_it(L_WARNING,"Can't open wallet file %s",a_file_name); - return NULL; +dap_chain_wallet_t *l_wallet; +int l_fd = -1, l_rc, l_certs_count, l_len; +dap_chain_wallet_file_hdr_t l_file_hdr = {0}; +dap_chain_wallet_cert_hdr_t l_cert_hdr = {0}; +char l_buf[32*1024], l_buf2[32*1024], *l_bufp, l_wallet_name [DAP_WALLET$SZ_NAME] = {0}; +dap_enc_key_t *l_enc_key = NULL; +uint32_t l_csum = CRC32C_INIT, l_csum2 = CRC32C_INIT; + + if ( 0 > (l_fd = open(a_file_name , O_RDONLY)) ) /* Open file for ReadOnly !!! */ + return log_it(L_ERROR,"Cant open file %s for read, errno=%d", a_file_name, errno), NULL; + + if ( sizeof(l_file_hdr) != read(l_fd, &l_file_hdr, sizeof(l_file_hdr)) )/* Get the file header record */ + return log_it(L_ERROR, "Error read Wallet file (%s) header, errno=%d", a_file_name, errno), close(l_fd), NULL; + + if ( l_file_hdr.signature != DAP_CHAIN_WALLETS_FILE_SIGNATURE ) /* Check signature of the file */ + return log_it(L_ERROR, "Wallet (%s) signature mismatch (%#lx != %#lx", a_file_name, l_file_hdr.signature, DAP_CHAIN_WALLETS_FILE_SIGNATURE), + close(l_fd), NULL; + + if ( (l_file_hdr.version == DAP_WALLET$K_VER_2) && (!l_pass) ) + return log_it(L_DEBUG, "Wallet (%s) version 2 cannot be processed w/o password", a_file_name), close(l_fd), NULL; + + if ( l_file_hdr.wallet_len > DAP_WALLET$SZ_NAME ) + return log_it(L_ERROR, "Invalid Wallet name (%s) length ( >%d)", a_file_name, DAP_WALLET$SZ_NAME), + close(l_fd), NULL; + + if ( l_file_hdr.wallet_len != read(l_fd, l_wallet_name, l_file_hdr.wallet_len) ) /* Read wallet's name */ + return log_it(L_ERROR, "Error Wallet's name (%s), errno=%d", a_file_name, errno), close(l_fd), NULL; + + + l_csum = crc32c (l_csum, &l_file_hdr, sizeof(l_file_hdr) ); /* Compute check sum of the Wallet file header */ + l_csum = crc32c (l_csum, l_wallet_name, l_file_hdr.wallet_len); + + log_it(L_DEBUG, "Wallet file: %s, Wallet[Version: %d, type: %d, name: '%.*s']", + a_file_name, l_file_hdr.version, l_file_hdr.type, l_file_hdr.wallet_len, l_wallet_name); + + /* First run - count certs in file */ + for ( l_certs_count = 0; sizeof(l_cert_hdr) == (l_rc = read (l_fd, &l_cert_hdr, sizeof(l_cert_hdr))); l_certs_count++ ) { + if ( (l_file_hdr.version == DAP_WALLET$K_VER_2) && (l_cert_hdr.type == DAP_WALLET$K_MAGIC) ) + break; + + if ( (int) l_cert_hdr.cert_raw_size != (l_rc = read(l_fd, l_buf, l_cert_hdr.cert_raw_size)) ) { + log_it(L_ERROR, "Error read certificate's body (%d != %d), errno=%d", l_cert_hdr.cert_raw_size, l_rc, errno); + break; + } } - fseek(l_file, 0L, SEEK_END); - uint64_t l_file_size = ftell(l_file); - rewind(l_file); - - if ( l_file ){ - dap_chain_wallet_file_hdr_t l_file_hdr={0}; - // read header - if ( fread(&l_file_hdr,1,sizeof(l_file_hdr),l_file) == sizeof (l_file_hdr) ) { - if ( l_file_hdr.signature == DAP_CHAIN_WALLETS_FILE_SIGNATURE ) { - dap_chain_wallet_t * l_wallet = DAP_NEW_Z(dap_chain_wallet_t); - DAP_CHAIN_WALLET_INTERNAL_LOCAL_NEW(l_wallet); - // read name - uint16_t name_len = 0; - fread(&name_len, 1, sizeof(uint16_t), l_file); - l_wallet->name = DAP_NEW_Z_SIZE(char, name_len + 1); - fread(l_wallet->name, 1, name_len, l_file); - - l_wallet_internal->file_name = strdup(a_file_name); - size_t i = sizeof (l_file_hdr) + sizeof(uint16_t) + name_len; - // calculate certs count - while (i < l_file_size ){ - dap_chain_wallet_cert_hdr_t l_cert_hdr={0}; - fread(&l_cert_hdr,1,sizeof(l_cert_hdr),l_file); - i+=sizeof(l_cert_hdr); - if (l_cert_hdr.cert_raw_size > 0 ){ - if(l_cert_hdr.cert_raw_size <= (l_file_size - i)) { - i+=l_cert_hdr.cert_raw_size; - l_wallet_internal->certs_count++; - }else{ - log_it(L_WARNING,"Wrong raw cert size %u (too big)",l_cert_hdr.cert_raw_size); - break; - } - }else{ - log_it(L_WARNING,"Wrong raw cert size 0"); - break; - } - } - if(l_wallet_internal->certs_count){ - // read certs - fseek(l_file,sizeof (l_file_hdr) + sizeof(uint16_t) + name_len,SEEK_SET); - l_wallet_internal->certs = DAP_NEW_Z_SIZE(dap_cert_t *,l_wallet_internal->certs_count * sizeof(dap_cert_t *)); - for (i = 0; i < l_wallet_internal->certs_count; i++ ){ - dap_chain_wallet_cert_hdr_t l_cert_hdr={0}; - fread(&l_cert_hdr,1,sizeof(l_cert_hdr),l_file); - uint8_t * l_data = DAP_NEW_SIZE(uint8_t,l_cert_hdr.cert_raw_size); - fread(l_data,1,l_cert_hdr.cert_raw_size,l_file); - l_wallet_internal->certs[i] = dap_cert_mem_load(l_data,l_cert_hdr.cert_raw_size); - DAP_DELETE (l_data); - } - }else - log_it(L_WARNING,"Corrupted wallet file, no certs found in it"); - fclose(l_file); - return l_wallet; - } else { - log_it(L_ERROR,"Wrong wallet file signature: corrupted file or wrong format"); - return NULL; - } - }else{ - log_it(L_ERROR,"Can't read wallet's header %s: \"%s\"",a_file_name,strerror(errno)); - return NULL; + + if ( l_rc < 0 ) + return log_it(L_ERROR, "Wallet file (%s) I/O error, errno=%d", a_file_name, errno), close(l_fd), NULL; + + if ( !l_certs_count ) + return log_it(L_ERROR, "No certificate (-s) in the wallet file (%s)", a_file_name), close(l_fd), NULL; + + + if ( (l_file_hdr.version == DAP_WALLET$K_VER_2) && l_pass ) /* Generate encryptor context */ + if ( !(l_enc_key = dap_enc_key_new_generate(DAP_ENC_KEY_TYPE_GOST_OFB, NULL, 0, l_pass, strlen(l_pass), 0)) ) + return log_it(L_ERROR, "Error create key context"), close(l_fd), NULL; + + + /* Create local instance of wallet, + * allocate memory for array to keep loaded certs */ + l_wallet = DAP_NEW_Z(dap_chain_wallet_t); + assert(l_wallet); + DAP_CHAIN_WALLET_INTERNAL_LOCAL_NEW(l_wallet); + assert(l_wallet_internal); + + dap_snprintf(l_wallet->name, DAP_WALLET$SZ_NAME, "%.*s", l_file_hdr.wallet_len, l_wallet_name); + strncpy(l_wallet_internal->file_name, a_file_name, sizeof(l_wallet_internal->file_name) ); + + l_wallet_internal->certs_count = l_certs_count; + assert(l_wallet_internal->certs_count); + + l_wallet_internal->certs = DAP_NEW_Z_SIZE(dap_cert_t *, l_wallet_internal->certs_count * sizeof(dap_cert_t *)); + assert(l_wallet_internal->certs); + + + + lseek(l_fd, sizeof(l_file_hdr) + l_file_hdr.wallet_len, SEEK_SET); /* Set file pointer to first record after cert file header */ + + + + for ( size_t i = 0; sizeof(l_cert_hdr) == (l_rc = read (l_fd, &l_cert_hdr, sizeof(l_cert_hdr))); i++ ) /* Read Cert/Record header */ + { + if ( (int) l_cert_hdr.cert_raw_size != (l_rc = read(l_fd, l_buf, l_cert_hdr.cert_raw_size)) ) { + log_it(L_ERROR, "Error read certificate's body (%d != %d), errno=%d", l_cert_hdr.cert_raw_size, l_rc, errno); + break; } - }else{ - log_it(L_ERROR,"Can't open file %s: \"%s\"",a_file_name,strerror(errno)); - return NULL; + + if ( (l_file_hdr.version == DAP_WALLET$K_VER_2) && (l_cert_hdr.type == DAP_WALLET$K_MAGIC) ) { + l_csum2 = *((uint32_t *) &l_buf); /* CRC32 must be terminal element in the wallet file */ + break; + } + + + l_bufp = l_buf; + + if ( l_enc_key ) + { + l_len = l_enc_key->dec_na(l_enc_key, l_buf, l_rc, l_buf2, sizeof(l_buf2) ); + l_bufp = l_buf2; + l_csum = crc32c (l_csum, l_bufp, l_len); /* CRC for every certificate */ + } + + l_wallet_internal->certs[ i ] = dap_cert_mem_load(l_bufp, l_cert_hdr.cert_raw_size); + } + + + + /* Cleanup and exit ... */ + close (l_fd); + + if ( l_enc_key ) + { + l_wallet->flags |= (DAP_WALLET$M_FL_PROTECTED | DAP_WALLET$M_FL_ACTIVE); + if ( l_csum != l_csum2 ) + { + log_it(L_ERROR, "Wallet checksum mismatch, %#x <> %#x", l_csum, l_csum2); + dap_chain_wallet_close( l_wallet); + l_wallet = NULL; + } + + dap_enc_key_delete(l_enc_key); } + + return l_wallet; } + + + + /** * @brief dap_chain_wallet_open * @param a_wallet_name * @param a_wallets_path * @return */ -dap_chain_wallet_t * dap_chain_wallet_open(const char * a_wallet_name, const char * a_wallets_path) +dap_chain_wallet_t *dap_chain_wallet_open ( + const char *a_wallet_name, + const char *a_wallets_path + ) { +char l_file_name [MAX_PATH] = {0}, l_pass [ DAP_WALLET$SZ_PASS + 3] = {0}, + *l_cp, l_wallet_name[DAP_WALLET$SZ_PASS + 3] = {0}; +ssize_t l_rc, l_pass_len; + + /* Sanity checks */ if(!a_wallet_name || !a_wallets_path) return NULL; - char *l_file_name = dap_strdup_printf("%s/%s.dwallet", a_wallets_path, a_wallet_name); - dap_chain_wallet_t * l_wallet = dap_chain_wallet_open_file(l_file_name); - DAP_DELETE(l_file_name); - return l_wallet; + + if ( (l_cp = strstr(a_wallet_name, s_wallet_ext)) ) + strncpy(l_wallet_name, a_wallet_name, l_cp - a_wallet_name); + else strcpy(l_wallet_name, a_wallet_name); + + dap_snprintf(l_file_name, sizeof(l_file_name) - 1, "%s/%s%s", a_wallets_path, l_wallet_name, s_wallet_ext); + + + l_pass_len = DAP_WALLET$SZ_PASS; /* Size of the buffer for password */ + /* Lookup password in the internal hash-table */ + if ( (l_rc = s_dap_chain_wallet_pass (l_wallet_name, strlen(l_wallet_name), l_pass, &l_pass_len)) ) + l_pass_len = 0; + + + return dap_chain_wallet_open_file(l_file_name, l_pass_len ? l_pass : NULL); } /** @@ -422,15 +897,14 @@ dap_chain_wallet_t * dap_chain_wallet_open(const char * a_wallet_name, const cha * @param a_net_id * @return */ -uint256_t dap_chain_wallet_get_balance(dap_chain_wallet_t *a_wallet, dap_chain_net_id_t a_net_id, const char *a_token_ticker) +uint256_t dap_chain_wallet_get_balance ( + dap_chain_wallet_t *a_wallet, + dap_chain_net_id_t a_net_id, + const char *a_token_ticker + ) { dap_chain_net_t *l_net = dap_chain_net_by_id(a_net_id); - dap_chain_addr_t *l_addr =dap_chain_wallet_get_addr(a_wallet, a_net_id); - uint256_t l_balance = {}; - if (l_net) - { - dap_ledger_t *l_ledger = l_net->pub.ledger; - l_balance = dap_chain_ledger_calc_balance(l_ledger, l_addr, a_token_ticker); - } - return l_balance; + dap_chain_addr_t *l_addr = dap_chain_wallet_get_addr(a_wallet, a_net_id); + + return (l_net) ? dap_chain_ledger_calc_balance(l_net->pub.ledger, l_addr, a_token_ticker) : uint256_0; } diff --git a/modules/wallet/include/dap_chain_wallet.h b/modules/wallet/include/dap_chain_wallet.h index 51ffd4c91ba18f5af2488f0d9855736e30211c31..8c7448389afae88207910ec8b74e58c868ee9da0 100644 --- a/modules/wallet/include/dap_chain_wallet.h +++ b/modules/wallet/include/dap_chain_wallet.h @@ -30,10 +30,19 @@ #include "dap_sign.h" #include "dap_cert.h" + +/* @RRL: #6131 */ +#define DAP_WALLET$SZ_NAME 64 /* Maximum length of the wallet's name */ +#define DAP_WALLET$SZ_PASS 64 /* Maximum length of the wallet's password */ + +#define DAP_WALLET$M_FL_PROTECTED (1 << 0) /* Wallet is password protected */ +#define DAP_WALLET$M_FL_ACTIVE (1 << 1) /* Has been activated (has been open with password) */ + typedef struct dap_chain_wallet{ - char * name; - void * _internal; - void * _inheritor; + char name[ DAP_WALLET$SZ_NAME + 1 ]; /* Human readable name of BMF Wallet */ + uint64_t flags; /* See DAP_WALLET$M_FL_* constants */ + void *_internal; + void *_inheritor; } dap_chain_wallet_t; @@ -42,12 +51,19 @@ void dap_chain_wallet_deinit(void); const char* dap_chain_wallet_get_path(dap_config_t * a_config); +/* @RRL: #6131 - Password protected BMF Wallet */ dap_chain_wallet_t * dap_chain_wallet_create_with_seed(const char * a_wallet_name, const char * a_wallets_path, - dap_sign_type_t a_sig_type, const void* a_seed, size_t a_seed_size); -dap_chain_wallet_t * dap_chain_wallet_create(const char * a_wallet_name, const char * a_wallets_path, dap_sign_type_t a_sig_type); // Creates new one if not found -dap_chain_wallet_t * dap_chain_wallet_open_file(const char * a_file_name); -dap_chain_wallet_t * dap_chain_wallet_open(const char * a_wallet_name, const char * a_wallets_path); -int dap_chain_wallet_save(dap_chain_wallet_t * a_wallet); + dap_sign_type_t a_sig_type, const void* a_seed, size_t a_seed_size, const char *a_pass); + +dap_chain_wallet_t * dap_chain_wallet_create_with_pass(const char * a_wallet_name, const char * a_wallets_path, + const void* a_pass, size_t a_pass_sz); + + +dap_chain_wallet_t *dap_chain_wallet_create(const char * a_wallet_name, const char * a_wallets_path, dap_sign_type_t a_sig_type, const char *a_pass); // Creates new one if not found +dap_chain_wallet_t *dap_chain_wallet_open_file(const char * a_file_name, const char *a_pass); +dap_chain_wallet_t *dap_chain_wallet_open(const char * a_wallet_name, const char * a_wallets_path); +dap_chain_wallet_t *dap_chain_wallet_open_ext(const char * a_wallet_name, const char * a_wallets_path, const char *pass); +int dap_chain_wallet_save(dap_chain_wallet_t * a_wallet, const char *a_pass); void dap_chain_wallet_close( dap_chain_wallet_t * a_wallet); @@ -61,3 +77,6 @@ dap_enc_key_t * dap_chain_wallet_get_key( dap_chain_wallet_t * a_wallet,uint32_t uint256_t dap_chain_wallet_get_balance(dap_chain_wallet_t *a_wallet, dap_chain_net_id_t a_net_id, const char *a_token_ticker); int dap_chain_wallet_save_file( dap_chain_wallet_t * a_wallet); + +int dap_chain_wallet_activate (const char *a_name, ssize_t a_name_len, const char *a_pass, ssize_t a_pass_len, unsigned a_ttl); +int dap_chain_wallet_deactivate (const char *a_name, ssize_t a_name_len, const char *a_pass, ssize_t a_pass_len); diff --git a/modules/wallet/include/dap_chain_wallet_internal.h b/modules/wallet/include/dap_chain_wallet_internal.h index 0256080f4ce8e719a929b31a81302e3d6d4b47ff..ef746aede875d65eab533869ea450c6ee6273ee8 100644 --- a/modules/wallet/include/dap_chain_wallet_internal.h +++ b/modules/wallet/include/dap_chain_wallet_internal.h @@ -27,13 +27,42 @@ #include "dap_cert.h" #include "dap_cert_file.h" #include "dap_chain_common.h" - #include "dap_chain_wallet.h" #define DAP_CHAIN_WALLETS_FILE_SIGNATURE 0x1a167bef15feea18 + +enum { + DAP_WALLET$K_TYPE_PLAIN = 0, /* 0x00 - uncompressed and unencrypted */ + DAP_WALLET$K_TYPE_GOST89 = 1, /* Encrypted with the GOST 89 */ +}; + +enum { + DAP_WALLET$K_VER_1 = 1, /* Wallet's file structure version, entry level */ + DAP_WALLET$K_VER_2 = 2, /* BMF Level */ +}; + + +enum { + DAP_WALLET$K_CERT = 1, /* Cert record type */ + DAP_WALLET$K_MAGIC = 2, /* Record is magic sequence */ +}; + + +typedef struct dap_chain_wallet_n_pass { + uint16_t name_len; /* Length of the follows wallet's name string */ + char name[DAP_WALLET$SZ_NAME + 1]; + uint16_t pass_len; /* Length of the follows wallet's password string */ + char pass[DAP_WALLET$SZ_PASS + 1]; + + struct timespec exptm; /* A time of expiration of the record + need RE-Activation steps */ + + UT_hash_handle hh; /* Context for hash-table */ +} dap_chain_wallet_n_pass_t; + typedef struct dap_chain_wallet_cert_hdr{ - uint32_t version; + uint32_t type; /* See DAP_WALLET$K_CERT/MAGIC ...constants */ uint32_t cert_raw_size; /// Certificate size } DAP_ALIGN_PACKED dap_chain_wallet_cert_hdr_t; @@ -43,13 +72,15 @@ typedef struct dap_chain_wallet_cert{ } DAP_ALIGN_PACKED dap_chain_wallet_cert_t; typedef struct dap_chain_wallet_file_hdr{ - uint64_t signature; - uint32_t version; - uint8_t type; /// Wallets storage type 0x00 - uncompressed and unencrypted - uint64_t padding; + uint64_t signature; + uint32_t version; + uint8_t type; /* See DAP_WALLET$K_TYPE_* constants */ + uint64_t padding; + uint16_t wallet_len; /* Length of the follows wallet's name string */ + char wallet_name[]; } DAP_ALIGN_PACKED dap_chain_wallet_file_hdr_t; -typedef struct dap_chain_wallet_file +typedef struct dap_chain_wallet_file /* On-disk structure */ { dap_chain_wallet_file_hdr_t header; uint8_t data[]; @@ -57,14 +88,12 @@ typedef struct dap_chain_wallet_file typedef struct dap_chain_wallet_internal { - dap_chain_addr_t *addr; - char * file_name; - size_t certs_count; - dap_cert_t ** certs; + char file_name[MAX_PATH]; + size_t certs_count; + dap_cert_t **certs; } dap_chain_wallet_internal_t; #define DAP_CHAIN_WALLET_INTERNAL(a) (a ? (dap_chain_wallet_internal_t *) a->_internal : NULL) - #define DAP_CHAIN_WALLET_INTERNAL_LOCAL(a) dap_chain_wallet_internal_t * l_wallet_internal = DAP_CHAIN_WALLET_INTERNAL(a) - #define DAP_CHAIN_WALLET_INTERNAL_LOCAL_NEW(a) dap_chain_wallet_internal_t * l_wallet_internal = DAP_NEW_Z(dap_chain_wallet_internal_t); a->_internal = l_wallet_internal +