├── LICENSE ├── Makefile ├── README.md ├── crypto-stream-state ├── LICENSE ├── README.md ├── src │ ├── crypto_stream_chacha20_xor.c │ ├── crypto_stream_chacha20_xor.h │ ├── crypto_stream_xchacha20_xor.c │ ├── crypto_stream_xchacha20_xor.h │ ├── crypto_stream_xor.c │ ├── crypto_stream_xor.h │ ├── crypto_stream_xsalsa20_xor.c │ └── crypto_stream_xsalsa20_xor.h └── test │ └── xsalsa20.c ├── dht.c ├── dht.h ├── dht_wrapper.c ├── dht_wrapper.h ├── log.c ├── log.h ├── main.c ├── metadata.proto ├── net.c ├── net.h ├── schema.proto ├── server.c ├── utils.c ├── utils.h ├── varint.c └── varint.h /LICENSE: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | 117 | 118 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | CC ?= gcc 3 | CFLAGS += -g -Wall -Werror -fno-strict-aliasing -Wwrite-strings -std=gnu99 -fsanitize=address -fsanitize=undefined 4 | 5 | all: metadata.pb-c.c schema.pb-c.c 6 | $(CC) $(CFLAGS) main.c utils.c metadata.pb-c.c -lsodium -lprotobuf-c -o main 7 | $(CC) $(CFLAGS) server.c net.c utils.c log.c dht.c dht_wrapper.c varint.c schema.pb-c.c crypto-stream-state/src/*.c -lsodium -lprotobuf-c -o server 8 | 9 | metadata.pb-c.c: 10 | protoc --c_out=. metadata.proto 11 | 12 | schema.pb-c.c: 13 | protoc --c_out=. schema.proto 14 | 15 | run: 16 | ./main 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dat-c 2 | 3 | A hobby implementation of the [dat protocol](https://github.com/datproject). 4 | State: More or less a collection of code snippets. 5 | 6 | Related Projects and Documentation: 7 | - [dat protocol whitepaper](https://github.com/datprotocol/whitepaper) 8 | - [Rust](https://www.rust-lang.org) implementation: [geniza](https://github.com/bnewbold/geniza) 9 | 10 | Dependencies: 11 | - libsodium 12 | - protobuf-c 13 | 14 | Working so far: 15 | - make an encrypted connection and send a few inital messages 16 | - read SLEEP files and verify node tree file content 17 | -------------------------------------------------------------------------------- /crypto-stream-state/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017, Emil Bay 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /crypto-stream-state/README.md: -------------------------------------------------------------------------------- 1 | # `crypto-stream-state` 2 | 3 | [![Build Status](https://travis-ci.org/emilbayes/crypto-stream-state.svg?branch=master)](https://travis-ci.org/emilbayes/crypto-stream-state) 4 | 5 | > Extension of libsodium crypto_stream_xor to do stateful streaming 6 | 7 | :warning: Work in progress :construction: 8 | 9 | ## Usage 10 | 11 | ```c 12 | #include 13 | #include "crypto_stream_xor.h" 14 | 15 | crypto_stream_xor_state state; 16 | 17 | #define PART1 (const unsigned char *) "Arbitrary data to encrypt" 18 | #define PART1_LEN 25 19 | 20 | #define PART2 (const unsigned char *) " split into " 21 | #define PART2_LEN 12 22 | 23 | #define PART3 (const unsigned char *) "three messages" 24 | #define PART3_LEN 14 25 | 26 | #define CIPHERTEXT_LEN PART1_LEN + PART2_LEN + PART3_LEN 27 | 28 | 29 | unsigned char key[crypto_stream_xor_NONCEBYTES]; 30 | unsigned char nonce[crypto_stream_xor_KEYBYTES]; 31 | unsigned char ciphertext[CIPHERTEXT_LEN]; 32 | unsigned char plaintext[CIPHERTEXT_LEN]; 33 | 34 | int main (int argc, char *argv[]) { 35 | crypto_stream_keygen(&key); 36 | randombytes_buf(&nonce, crypto_stream_KEYBYTES); 37 | 38 | unsigned char *c = ciphertext; 39 | unsigned char *p = plaintext; 40 | 41 | memset(c, 0, CIPHERTEXT_LEN); 42 | 43 | int ret; 44 | 45 | // Encrypt part 46 | ret = crypto_stream_xor_init(&state, &key, &nonce); 47 | if (ret) return ret; 48 | 49 | ret = crypto_stream_xor_update(&state, c, PART1, PART1_LEN); 50 | if (ret) return ret; 51 | c += PART1_LEN; 52 | 53 | ret = crypto_stream_xor_update(&state, c, PART2, PART2_LEN); 54 | if (ret) return ret; 55 | c += PART2_LEN; 56 | 57 | ret = crypto_stream_xor_update(&state, c, PART3, PART3_LEN); 58 | if (ret) return ret; 59 | c += PART3_LEN; 60 | 61 | ret = crypto_stream_xor_final(&state); 62 | if (ret) return ret; 63 | 64 | // Decrypt part 65 | 66 | c -= CIPHERTEXT_LEN; // Rewind c first 67 | 68 | ret = crypto_stream_xor_init(&state, &key, &nonce); 69 | if (ret) return ret; 70 | 71 | ret = crypto_stream_xor_update(&state, p, c, 10); 72 | if (ret) return ret; 73 | c += 10; 74 | p += 10; 75 | 76 | ret = crypto_stream_xor_update(&state, p, c, 15); 77 | if (ret) return ret; 78 | c += 15; 79 | p += 15; 80 | 81 | ret = crypto_stream_xor_update(&state, p, c, 16); 82 | if (ret) return ret; 83 | c += 16; 84 | p += 16; 85 | 86 | ret = crypto_stream_xor_update(&state, p, c, 10); 87 | if (ret) return ret; 88 | c += 10; 89 | p += 10; 90 | 91 | ret = crypto_stream_xor_final(&state); 92 | if (ret) return ret; 93 | 94 | printf("Decrypted: %s\n", plaintext); 95 | return 0; 96 | } 97 | ``` 98 | 99 | ## API 100 | 101 | ```c 102 | int crypto_stream_xor_statebytes() 103 | ``` 104 | 105 | ```c 106 | int crypto_stream_xor_init 107 | (crypto_stream_xor_state *state, 108 | unsigned const char nonce[crypto_stream_NONCEBYTES], 109 | unsigned const char key[crypto_stream_KEYBYTES]) 110 | ``` 111 | 112 | ```c 113 | int crypto_stream_xor_update 114 | (crypto_stream_xor_state *state, 115 | unsigned char *c, 116 | const unsigned char *m, unsigned long long mlen) 117 | ``` 118 | 119 | ```c 120 | int crypto_stream_xor_final 121 | (crypto_stream_xor_state *state) 122 | ``` 123 | 124 | The above three functions are also available in `crypto_stream_xsalsa20_xor_*`, 125 | `crypto_stream_xchacha20_xor_*`, `crypto_stream_salsa20_xor_*` and 126 | `crypto_stream_chacha20_xor_*` flavours. 127 | 128 | ## License 129 | 130 | [ISC](LICENSE) 131 | -------------------------------------------------------------------------------- /crypto-stream-state/src/crypto_stream_chacha20_xor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "crypto_stream_chacha20_xor.h" 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | size_t 9 | crypto_stream_chacha20_xor_keybytes(void) 10 | { 11 | return crypto_stream_chacha20_KEYBYTES; 12 | } 13 | 14 | size_t 15 | crypto_stream_chacha20_xor_noncebytes(void) 16 | { 17 | return crypto_stream_chacha20_NONCEBYTES; 18 | } 19 | 20 | size_t 21 | crypto_stream_chacha20_xor_statebytes(void) 22 | { 23 | return sizeof(crypto_stream_chacha20_xor_state); 24 | } 25 | 26 | int 27 | crypto_stream_chacha20_xor_init(crypto_stream_chacha20_xor_state *state, 28 | unsigned const char nonce[crypto_stream_chacha20_NONCEBYTES], 29 | unsigned const char key[crypto_stream_chacha20_KEYBYTES]) 30 | { 31 | // If arguments are outright dangerous 32 | if (0) { 33 | sodium_misuse(); 34 | } 35 | 36 | state->remainder = 0; 37 | state->block_counter = 0; 38 | memcpy(state->nonce, nonce, sizeof(state->nonce)); 39 | memcpy(state->key, key, sizeof(state->key)); 40 | memset(state->next_block, 0, sizeof(state->next_block)); 41 | 42 | return 0; 43 | } 44 | 45 | int 46 | crypto_stream_chacha20_xor_update(crypto_stream_chacha20_xor_state *state, 47 | unsigned char *c, const unsigned char *m, 48 | unsigned long long mlen) 49 | { 50 | // If we have data left over of the next block 51 | if (state->remainder) { 52 | uint64_t offset = 0; 53 | uint8_t rem = state->remainder; 54 | 55 | while (rem < crypto_stream_chacha20_BLOCKBYTES && offset < mlen) { 56 | c[offset] = state->next_block[rem] ^ 0 ^ m[offset]; 57 | offset++; 58 | rem++; 59 | } 60 | 61 | c += offset; 62 | m += offset; 63 | mlen -= offset; 64 | state->remainder = rem % crypto_stream_chacha20_BLOCKBYTES; // This should never wrap, but always <= crypto_stream_chacha20_BLOCKBYTES 65 | 66 | if (!mlen) return 0; 67 | } 68 | 69 | 70 | state->remainder = mlen & (crypto_stream_chacha20_BLOCKBYTES - 1); 71 | mlen -= state->remainder; 72 | 73 | crypto_stream_chacha20_xor_ic(c, m, mlen, state->nonce, state->block_counter, state->key); 74 | 75 | state->block_counter += mlen / crypto_stream_chacha20_BLOCKBYTES; 76 | 77 | if (state->remainder) { 78 | sodium_memzero(state->next_block + state->remainder, crypto_stream_chacha20_BLOCKBYTES - state->remainder); 79 | memcpy(state->next_block, m + mlen, state->remainder); 80 | 81 | crypto_stream_chacha20_xor_ic(state->next_block, state->next_block, crypto_stream_chacha20_BLOCKBYTES, state->nonce, state->block_counter, state->key); 82 | memcpy(c + mlen, state->next_block, state->remainder); 83 | 84 | state->block_counter++; 85 | } 86 | 87 | return 0; 88 | } 89 | 90 | int 91 | crypto_stream_chacha20_xor_final(crypto_stream_chacha20_xor_state *state) 92 | { 93 | sodium_memzero(state, crypto_stream_chacha20_xor_statebytes()); 94 | 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /crypto-stream-state/src/crypto_stream_chacha20_xor.h: -------------------------------------------------------------------------------- 1 | #ifndef CRYPTO_STREAM_CHACHA20_XOR_H 2 | #define CRYPTO_STREAM_CHACHA20_XOR_H 1 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #define crypto_stream_chacha20_xor_KEYBYTES crypto_stream_chacha20_KEYBYTES 11 | #define crypto_stream_chacha20_xor_NONCEBYTES crypto_stream_chacha20_NONCEBYTES 12 | 13 | #define crypto_stream_chacha20_BLOCKBYTES 64 14 | 15 | // Packing? Alignment? 16 | 17 | typedef struct crypto_stream_chacha20_xor_state { 18 | uint8_t nonce[crypto_stream_chacha20_NONCEBYTES]; 19 | uint8_t key[crypto_stream_chacha20_KEYBYTES]; 20 | uint8_t next_block[crypto_stream_chacha20_BLOCKBYTES]; 21 | uint8_t remainder; 22 | uint64_t block_counter; 23 | } crypto_stream_chacha20_xor_state; 24 | 25 | size_t 26 | crypto_stream_chacha20_xor_keybytes(void); 27 | 28 | size_t 29 | crypto_stream_chacha20_xor_noncebytes(void); 30 | 31 | size_t 32 | crypto_stream_chacha20_xor_statebytes(void); 33 | 34 | int 35 | crypto_stream_chacha20_xor_init(crypto_stream_chacha20_xor_state *state, 36 | unsigned const char nonce[crypto_stream_chacha20_NONCEBYTES], 37 | unsigned const char key[crypto_stream_chacha20_KEYBYTES]); 38 | 39 | int 40 | crypto_stream_chacha20_xor_update(crypto_stream_chacha20_xor_state *state, 41 | unsigned char *c, const unsigned char *m, 42 | unsigned long long mlen); 43 | 44 | int 45 | crypto_stream_chacha20_xor_final(crypto_stream_chacha20_xor_state *state); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /crypto-stream-state/src/crypto_stream_xchacha20_xor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "crypto_stream_xchacha20_xor.h" 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | size_t 9 | crypto_stream_xchacha20_xor_keybytes(void) 10 | { 11 | return crypto_stream_xchacha20_KEYBYTES; 12 | } 13 | 14 | size_t 15 | crypto_stream_xchacha20_xor_noncebytes(void) 16 | { 17 | return crypto_stream_xchacha20_NONCEBYTES; 18 | } 19 | 20 | size_t 21 | crypto_stream_xchacha20_xor_statebytes(void) 22 | { 23 | return sizeof(crypto_stream_xchacha20_xor_state); 24 | } 25 | 26 | int 27 | crypto_stream_xchacha20_xor_init(crypto_stream_xchacha20_xor_state *state, 28 | unsigned const char nonce[crypto_stream_xchacha20_NONCEBYTES], 29 | unsigned const char key[crypto_stream_xchacha20_KEYBYTES]) 30 | { 31 | // If arguments are outright dangerous 32 | if (0) { 33 | sodium_misuse(); 34 | } 35 | 36 | state->remainder = 0; 37 | state->block_counter = 0; 38 | memcpy(state->nonce, nonce, sizeof(state->nonce)); 39 | memcpy(state->key, key, sizeof(state->key)); 40 | memset(state->next_block, 0, sizeof(state->next_block)); 41 | 42 | return 0; 43 | } 44 | 45 | int 46 | crypto_stream_xchacha20_xor_update(crypto_stream_xchacha20_xor_state *state, 47 | unsigned char *c, const unsigned char *m, 48 | unsigned long long mlen) 49 | { 50 | // If we have data left over of the next block 51 | if (state->remainder) { 52 | uint64_t offset = 0; 53 | uint8_t rem = state->remainder; 54 | 55 | while (rem < crypto_stream_xchacha20_BLOCKBYTES && offset < mlen) { 56 | c[offset] = state->next_block[rem] ^ 0 ^ m[offset]; 57 | offset++; 58 | rem++; 59 | } 60 | 61 | c += offset; 62 | m += offset; 63 | mlen -= offset; 64 | state->remainder = rem % crypto_stream_xchacha20_BLOCKBYTES; // This should never wrap, but always <= crypto_stream_xchacha20_BLOCKBYTES 65 | 66 | if (!mlen) return 0; 67 | } 68 | 69 | 70 | state->remainder = mlen & (crypto_stream_xchacha20_BLOCKBYTES - 1); 71 | mlen -= state->remainder; 72 | 73 | crypto_stream_xchacha20_xor_ic(c, m, mlen, state->nonce, state->block_counter, state->key); 74 | 75 | state->block_counter += mlen / crypto_stream_xchacha20_BLOCKBYTES; 76 | 77 | if (state->remainder) { 78 | sodium_memzero(state->next_block + state->remainder, crypto_stream_xchacha20_BLOCKBYTES - state->remainder); 79 | memcpy(state->next_block, m + mlen, state->remainder); 80 | 81 | crypto_stream_xchacha20_xor_ic(state->next_block, state->next_block, crypto_stream_xchacha20_BLOCKBYTES, state->nonce, state->block_counter, state->key); 82 | memcpy(c + mlen, state->next_block, state->remainder); 83 | 84 | state->block_counter++; 85 | } 86 | 87 | return 0; 88 | } 89 | 90 | int 91 | crypto_stream_xchacha20_xor_final(crypto_stream_xchacha20_xor_state *state) 92 | { 93 | sodium_memzero(state, crypto_stream_xchacha20_xor_statebytes()); 94 | 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /crypto-stream-state/src/crypto_stream_xchacha20_xor.h: -------------------------------------------------------------------------------- 1 | #ifndef CRYPTO_STREAM_XCHACHA20_XOR_H 2 | #define CRYPTO_STREAM_XCHACHA20_XOR_H 1 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #define crypto_stream_xchacha20_xor_KEYBYTES crypto_stream_xchacha20_KEYBYTES 11 | #define crypto_stream_xchacha20_xor_NONCEBYTES crypto_stream_xchacha20_NONCEBYTES 12 | 13 | #define crypto_stream_xchacha20_BLOCKBYTES 64 14 | 15 | // Packing? Alignment? 16 | 17 | typedef struct crypto_stream_xchacha20_xor_state { 18 | uint8_t nonce[crypto_stream_xchacha20_NONCEBYTES]; 19 | uint8_t key[crypto_stream_xchacha20_KEYBYTES]; 20 | uint8_t next_block[crypto_stream_xchacha20_BLOCKBYTES]; 21 | uint8_t remainder; 22 | uint64_t block_counter; 23 | } crypto_stream_xchacha20_xor_state; 24 | 25 | size_t 26 | crypto_stream_xchacha20_xor_keybytes(void); 27 | 28 | size_t 29 | crypto_stream_xchacha20_xor_noncebytes(void); 30 | 31 | size_t 32 | crypto_stream_xchacha20_xor_statebytes(void); 33 | 34 | int 35 | crypto_stream_xchacha20_xor_init(crypto_stream_xchacha20_xor_state *state, 36 | unsigned const char nonce[crypto_stream_xchacha20_NONCEBYTES], 37 | unsigned const char key[crypto_stream_xchacha20_KEYBYTES]); 38 | 39 | int 40 | crypto_stream_xchacha20_xor_update(crypto_stream_xchacha20_xor_state *state, 41 | unsigned char *c, const unsigned char *m, 42 | unsigned long long mlen); 43 | 44 | int 45 | crypto_stream_xchacha20_xor_final(crypto_stream_xchacha20_xor_state *state); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /crypto-stream-state/src/crypto_stream_xor.c: -------------------------------------------------------------------------------- 1 | #include "crypto_stream_xor.h" 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | size_t 8 | crypto_stream_xor_keybytes(void) 9 | { 10 | return crypto_stream_xor_KEYBYTES; 11 | } 12 | 13 | size_t 14 | crypto_stream_xor_noncebytes(void) 15 | { 16 | return crypto_stream_xor_NONCEBYTES; 17 | } 18 | 19 | size_t 20 | crypto_stream_xor_statebytes(void) 21 | { 22 | return crypto_stream_xsalsa20_xor_statebytes(); 23 | } 24 | 25 | int 26 | crypto_stream_xor_init(crypto_stream_xor_state *state, 27 | unsigned const char nonce[crypto_stream_NONCEBYTES], 28 | unsigned const char key[crypto_stream_KEYBYTES]) 29 | { 30 | return crypto_stream_xsalsa20_xor_init(state, nonce, key); 31 | } 32 | 33 | int 34 | crypto_stream_xor_update(crypto_stream_xor_state *state, 35 | unsigned char *c, const unsigned char *m, 36 | unsigned long long mlen) 37 | { 38 | return crypto_stream_xsalsa20_xor_update(state, c, m, mlen); 39 | } 40 | 41 | int 42 | crypto_stream_xor_final(crypto_stream_xor_state *state) 43 | { 44 | return crypto_stream_xsalsa20_xor_final(state); 45 | } 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | -------------------------------------------------------------------------------- /crypto-stream-state/src/crypto_stream_xor.h: -------------------------------------------------------------------------------- 1 | #ifndef CRYPTO_STREAM_XOR_H 2 | #define CRYPTO_STREAM_XOR_H 1 3 | 4 | 5 | #include 6 | #include "crypto_stream_xsalsa20_xor.h" 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #define crypto_stream_xor_KEYBYTES crypto_stream_KEYBYTES 13 | #define crypto_stream_xor_NONCEBYTES crypto_stream_NONCEBYTES 14 | 15 | typedef crypto_stream_xsalsa20_xor_state crypto_stream_xor_state; 16 | 17 | size_t 18 | crypto_stream_xor_keybytes(void); 19 | 20 | size_t 21 | crypto_stream_xor_noncebytes(void); 22 | 23 | size_t 24 | crypto_stream_xor_statebytes(void); 25 | 26 | int 27 | crypto_stream_xor_init(crypto_stream_xor_state *state, 28 | unsigned const char nonce[crypto_stream_NONCEBYTES], 29 | unsigned const char key[crypto_stream_KEYBYTES]); 30 | 31 | int 32 | crypto_stream_xor_update(crypto_stream_xor_state *state, 33 | unsigned char *c, const unsigned char *m, 34 | unsigned long long mlen); 35 | 36 | int 37 | crypto_stream_xor_final(crypto_stream_xor_state *state); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /crypto-stream-state/src/crypto_stream_xsalsa20_xor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "crypto_stream_xsalsa20_xor.h" 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | size_t 9 | crypto_stream_xsalsa20_xor_keybytes(void) 10 | { 11 | return crypto_stream_xsalsa20_KEYBYTES; 12 | } 13 | 14 | size_t 15 | crypto_stream_xsalsa20_xor_noncebytes(void) 16 | { 17 | return crypto_stream_xsalsa20_NONCEBYTES; 18 | } 19 | 20 | size_t 21 | crypto_stream_xsalsa20_xor_statebytes(void) 22 | { 23 | return sizeof(crypto_stream_xsalsa20_xor_state); 24 | } 25 | 26 | int 27 | crypto_stream_xsalsa20_xor_init(crypto_stream_xsalsa20_xor_state *state, 28 | unsigned const char nonce[crypto_stream_xsalsa20_NONCEBYTES], 29 | unsigned const char key[crypto_stream_xsalsa20_KEYBYTES]) 30 | { 31 | // If arguments are outright dangerous 32 | if (0) { 33 | sodium_misuse(); 34 | } 35 | 36 | state->remainder = 0; 37 | state->block_counter = 0; 38 | memcpy(state->nonce, nonce, sizeof(state->nonce)); 39 | memcpy(state->key, key, sizeof(state->key)); 40 | memset(state->next_block, 0, sizeof(state->next_block)); 41 | 42 | return 0; 43 | } 44 | 45 | int 46 | crypto_stream_xsalsa20_xor_update(crypto_stream_xsalsa20_xor_state *state, 47 | unsigned char *c, const unsigned char *m, 48 | unsigned long long mlen) 49 | { 50 | // If we have data left over of the next block 51 | if (state->remainder) { 52 | uint64_t offset = 0; 53 | uint8_t rem = state->remainder; 54 | 55 | while (rem < crypto_stream_xsalsa20_BLOCKBYTES && offset < mlen) { 56 | c[offset] = state->next_block[rem] ^ 0 ^ m[offset]; 57 | offset++; 58 | rem++; 59 | } 60 | 61 | c += offset; 62 | m += offset; 63 | mlen -= offset; 64 | state->remainder = rem % crypto_stream_xsalsa20_BLOCKBYTES; // This should never wrap, but always <= 64 65 | 66 | if (!mlen) return 0; 67 | } 68 | 69 | 70 | state->remainder = mlen & (crypto_stream_xsalsa20_BLOCKBYTES - 1); 71 | mlen -= state->remainder; 72 | 73 | crypto_stream_xsalsa20_xor_ic(c, m, mlen, state->nonce, state->block_counter, state->key); 74 | 75 | state->block_counter += mlen / crypto_stream_xsalsa20_BLOCKBYTES; 76 | 77 | if (state->remainder) { 78 | sodium_memzero(state->next_block + state->remainder, crypto_stream_xsalsa20_BLOCKBYTES - state->remainder); 79 | memcpy(state->next_block, m + mlen, state->remainder); 80 | 81 | crypto_stream_xsalsa20_xor_ic(state->next_block, state->next_block, crypto_stream_xsalsa20_BLOCKBYTES, state->nonce, state->block_counter, state->key); 82 | memcpy(c + mlen, state->next_block, state->remainder); 83 | 84 | state->block_counter++; 85 | } 86 | 87 | return 0; 88 | } 89 | 90 | int 91 | crypto_stream_xsalsa20_xor_final(crypto_stream_xsalsa20_xor_state *state) 92 | { 93 | sodium_memzero(state, crypto_stream_xsalsa20_xor_statebytes()); 94 | 95 | return 0; 96 | } 97 | 98 | #ifdef __cplusplus 99 | } 100 | #endif 101 | -------------------------------------------------------------------------------- /crypto-stream-state/src/crypto_stream_xsalsa20_xor.h: -------------------------------------------------------------------------------- 1 | #ifndef CRYPTO_STREAM_XSALSA20_XOR_H 2 | #define CRYPTO_STREAM_XSALSA20_XOR_H 1 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #define crypto_stream_xsalsa20_xor_KEYBYTES crypto_stream_xsalsa20_KEYBYTES 11 | #define crypto_stream_xsalsa20_xor_NONCEBYTES crypto_stream_xsalsa20_NONCEBYTES 12 | 13 | #define crypto_stream_xsalsa20_BLOCKBYTES 64 14 | 15 | // Packing? Alignment? 16 | 17 | typedef struct crypto_stream_xsalsa20_xor_state { 18 | unsigned char nonce[crypto_stream_xsalsa20_NONCEBYTES]; 19 | unsigned char key[crypto_stream_xsalsa20_KEYBYTES]; 20 | unsigned char next_block[crypto_stream_xsalsa20_BLOCKBYTES]; 21 | uint8_t remainder; 22 | uint64_t block_counter; 23 | } crypto_stream_xsalsa20_xor_state; 24 | 25 | size_t 26 | crypto_stream_xsalsa20_xor_keybytes(void); 27 | 28 | size_t 29 | crypto_stream_xsalsa20_xor_noncebytes(void); 30 | 31 | size_t 32 | crypto_stream_xsalsa20_xor_statebytes(void); 33 | 34 | int 35 | crypto_stream_xsalsa20_xor_init(crypto_stream_xsalsa20_xor_state *state, 36 | unsigned const char nonce[crypto_stream_xsalsa20_NONCEBYTES], 37 | unsigned const char key[crypto_stream_xsalsa20_KEYBYTES]); 38 | 39 | int 40 | crypto_stream_xsalsa20_xor_update(crypto_stream_xsalsa20_xor_state *state, 41 | unsigned char *c, const unsigned char *m, 42 | unsigned long long mlen); 43 | 44 | int 45 | crypto_stream_xsalsa20_xor_final(crypto_stream_xsalsa20_xor_state *state); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /crypto-stream-state/test/xsalsa20.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "crypto_stream_xor.h" 3 | 4 | crypto_stream_xor_state state; 5 | 6 | #define PART1 (const unsigned char *) "Arbitrary data to encrypt" 7 | #define PART1_LEN 25 8 | 9 | #define PART2 (const unsigned char *) " split into " 10 | #define PART2_LEN 12 11 | 12 | #define PART3 (const unsigned char *) "three messages" 13 | #define PART3_LEN 14 14 | 15 | #define CIPHERTEXT_LEN PART1_LEN + PART2_LEN + PART3_LEN 16 | 17 | 18 | unsigned char key[crypto_stream_NONCEBYTES]; 19 | unsigned char nonce[crypto_stream_KEYBYTES]; 20 | unsigned char ciphertext[CIPHERTEXT_LEN]; 21 | unsigned char plaintext[CIPHERTEXT_LEN]; 22 | 23 | int main (int argc, char *argv[]) { 24 | crypto_stream_keygen(&key); 25 | randombytes_buf(&nonce, crypto_stream_KEYBYTES); 26 | 27 | unsigned char *c = ciphertext; 28 | unsigned char *p = plaintext; 29 | 30 | memset(c, 0, CIPHERTEXT_LEN); 31 | 32 | int ret; 33 | 34 | // Encrypt part 35 | ret = crypto_stream_xor_init(&state, &key, &nonce); 36 | if (ret) return ret; 37 | 38 | ret = crypto_stream_xor_update(&state, c, PART1, PART1_LEN); 39 | if (ret) return ret; 40 | c += PART1_LEN; 41 | 42 | ret = crypto_stream_xor_update(&state, c, PART2, PART2_LEN); 43 | if (ret) return ret; 44 | c += PART2_LEN; 45 | 46 | ret = crypto_stream_xor_update(&state, c, PART3, PART3_LEN); 47 | if (ret) return ret; 48 | c += PART3_LEN; 49 | 50 | ret = crypto_stream_xor_final(&state); 51 | if (ret) return ret; 52 | 53 | // Decrypt part 54 | 55 | c -= CIPHERTEXT_LEN; // Rewind c first 56 | 57 | ret = crypto_stream_xor_init(&state, &key, &nonce); 58 | if (ret) return ret; 59 | 60 | ret = crypto_stream_xor_update(&state, p, c, 10); 61 | if (ret) return ret; 62 | c += 10; 63 | p += 10; 64 | 65 | ret = crypto_stream_xor_update(&state, p, c, 15); 66 | if (ret) return ret; 67 | c += 15; 68 | p += 15; 69 | 70 | ret = crypto_stream_xor_update(&state, p, c, 16); 71 | if (ret) return ret; 72 | c += 16; 73 | p += 16; 74 | 75 | ret = crypto_stream_xor_update(&state, p, c, 10); 76 | if (ret) return ret; 77 | c += 10; 78 | p += 10; 79 | 80 | ret = crypto_stream_xor_final(&state); 81 | if (ret) return ret; 82 | 83 | printf("Decrypted: %s\n", plaintext); 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /dht.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009-2011 by Juliusz Chroboczek 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | typedef void 28 | dht_callback(void *closure, int event, 29 | const unsigned char *info_hash, 30 | const void *data, size_t data_len); 31 | 32 | #define DHT_EVENT_NONE 0 33 | #define DHT_EVENT_VALUES 1 34 | #define DHT_EVENT_VALUES6 2 35 | #define DHT_EVENT_SEARCH_DONE 3 36 | #define DHT_EVENT_SEARCH_DONE6 4 37 | 38 | extern FILE *dht_debug; 39 | 40 | int dht_init(int s, int s6, const unsigned char *id, const unsigned char *v); 41 | int dht_insert_node(const unsigned char *id, struct sockaddr *sa, int salen); 42 | int dht_ping_node(const struct sockaddr *sa, int salen); 43 | int dht_periodic(const void *buf, size_t buflen, 44 | const struct sockaddr *from, int fromlen, 45 | time_t *tosleep, dht_callback *callback, void *closure); 46 | int dht_search(const unsigned char *id, int port, int af, 47 | dht_callback *callback, void *closure); 48 | int dht_nodes(int af, 49 | int *good_return, int *dubious_return, int *cached_return, 50 | int *incoming_return); 51 | void dht_dump_tables(FILE *f); 52 | int dht_get_nodes(struct sockaddr_in *sin, int *num, 53 | struct sockaddr_in6 *sin6, int *num6); 54 | int dht_uninit(void); 55 | 56 | /* This must be provided by the user. */ 57 | int dht_sendto(int sockfd, const void *buf, int len, int flags, 58 | const struct sockaddr *to, int tolen); 59 | int dht_blacklisted(const struct sockaddr *sa, int salen); 60 | void dht_hash(void *hash_return, int hash_size, 61 | const void *v1, int len1, 62 | const void *v2, int len2, 63 | const void *v3, int len3); 64 | int dht_random_bytes(void *buf, size_t size); 65 | 66 | #ifdef __cplusplus 67 | } 68 | #endif 69 | -------------------------------------------------------------------------------- /dht_wrapper.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include "log.h" 14 | #include "net.h" 15 | #include "utils.h" 16 | #include "dht.h" 17 | 18 | 19 | // Needed for dht.c 20 | int dht_sendto(int sockfd, const void *buf, int len, int flags, 21 | const struct sockaddr *to, int tolen) 22 | { 23 | return sendto(sockfd, buf, len, flags, to, tolen); 24 | } 25 | 26 | // Needed for dht.c 27 | int dht_blacklisted( const struct sockaddr *sa, int salen ) { 28 | return 0; 29 | } 30 | 31 | // Needed for dht.c 32 | // Hashing for the DHT - implementation does not matter for interoperability 33 | void dht_hash( void *hash_return, int hash_size, 34 | const void *v1, int len1, 35 | const void *v2, int len2, 36 | const void *v3, int len3 ) { 37 | uint8_t hash[crypto_generichash_BYTES]; 38 | crypto_generichash_state state; 39 | 40 | crypto_generichash_init(&state, NULL, 0, sizeof(hash)); 41 | 42 | crypto_generichash_update(&state, v1, len1); 43 | crypto_generichash_update(&state, v2, len2); 44 | crypto_generichash_update(&state, v3, len3); 45 | crypto_generichash_final(&state, hash, sizeof(hash)); 46 | 47 | memcpy( hash_return, hash, 8); 48 | } 49 | 50 | // Needed for dht.c 51 | int dht_random_bytes(void *buf, size_t size) { 52 | randombytes_buf(buf, size); 53 | return 0; 54 | } 55 | 56 | 57 | /* 58 | * Put an address and port into a sockaddr_storages struct. 59 | * Both addr and port are in network byte order. 60 | */ 61 | void to_addr( IP *addr, const void *ip, size_t len, uint16_t port ) { 62 | memset( addr, '\0', sizeof(IP) ); 63 | 64 | if( len == 4 ) { 65 | IP4 *a = (IP4 *) addr; 66 | a->sin_family = AF_INET; 67 | a->sin_port = port; 68 | memcpy( &a->sin_addr.s_addr, ip, 4 ); 69 | } 70 | 71 | if( len == 16 ) { 72 | IP6 *a = (IP6 *) addr; 73 | a->sin6_family = AF_INET6; 74 | a->sin6_port = port; 75 | memcpy( &a->sin6_addr.s6_addr, ip, 16 ); 76 | } 77 | } 78 | 79 | typedef struct { 80 | uint8_t addr[16]; 81 | uint16_t port; 82 | } dht_addr6_t; 83 | 84 | typedef struct { 85 | uint8_t addr[4]; 86 | uint16_t port; 87 | } dht_addr4_t; 88 | 89 | 90 | // This callback is called when a search result arrives or a search completes 91 | void dht_callback_func( void *closure, int event, const uint8_t *info_hash, const void *data, size_t data_len ) { 92 | //struct search_t *search; 93 | dht_addr4_t *data4; 94 | dht_addr6_t *data6; 95 | IP addr; 96 | size_t i; 97 | 98 | /* 99 | search = searches_find_by_id( info_hash ); 100 | 101 | if( search == NULL ) { 102 | return; 103 | } 104 | */ 105 | switch( event ) { 106 | case DHT_EVENT_VALUES: 107 | data4 = (dht_addr4_t *) data; 108 | for( i = 0; i < (data_len / sizeof(dht_addr4_t)); ++i ) { 109 | to_addr( &addr, &data4[i].addr, 4, data4[i].port ); 110 | //searches_add_addr( search, &addr ); 111 | } 112 | break; 113 | case DHT_EVENT_VALUES6: 114 | data6 = (dht_addr6_t *) data; 115 | for( i = 0; i < (data_len / sizeof(dht_addr6_t)); ++i ) { 116 | to_addr( &addr, &data6[i].addr, 16, data6[i].port ); 117 | //searches_add_addr( search, &addr ); 118 | } 119 | break; 120 | case DHT_EVENT_SEARCH_DONE: 121 | case DHT_EVENT_SEARCH_DONE6: 122 | // Ignore.. 123 | break; 124 | } 125 | } 126 | 127 | time_t g_dht_maintenance = 0; 128 | 129 | void dht_handle(int revents, int fd) { 130 | size_t buflen = 0; 131 | uint8_t buf[12]; 132 | int rc; 133 | IP from; 134 | socklen_t fromlen; 135 | time_t time_wait; 136 | 137 | if( buflen > 0 ) { 138 | // Handle incoming data 139 | fromlen = sizeof(from); 140 | rc = dht_periodic( buf, buflen, (struct sockaddr*) &from, fromlen, &time_wait, dht_callback_func, NULL ); 141 | 142 | if( rc < 0 && errno != EINTR ) { 143 | if( rc == EINVAL || rc == EFAULT ) { 144 | log_err( "KAD: Error calling dht_periodic." ); 145 | exit( 1 ); 146 | } 147 | g_dht_maintenance = g_now + 1; 148 | } else { 149 | g_dht_maintenance = g_now + time_wait; 150 | } 151 | } else if( g_dht_maintenance <= g_now ) { 152 | // Do a maintenance call 153 | rc = dht_periodic( NULL, 0, NULL, 0, &time_wait, dht_callback_func, NULL ); 154 | 155 | // Wait for the next maintenance call 156 | g_dht_maintenance = g_now + time_wait; 157 | log_debug( "KAD: Next maintenance call in %u seconds.", (unsigned int) time_wait ); 158 | } else { 159 | rc = 0; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /dht_wrapper.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _DHT_WRAPPER 3 | #define _DHT_WRAPPER 4 | 5 | 6 | 7 | #endif // _DHT_WRAPPER 8 | -------------------------------------------------------------------------------- /log.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "log.h" 9 | 10 | int g_verbosity = VERBOSITY_VERBOSE; 11 | int g_use_syslog = 0; 12 | #define MAIN_SRVNAME "" 13 | 14 | #ifdef DEBUG 15 | 16 | // Program start time 17 | static struct timespec log_start = { 0, 0 }; 18 | 19 | const char *log_time() { 20 | struct timespec now = { 0, 0 }; 21 | clock_gettime( CLOCK_MONOTONIC, &now ); 22 | 23 | // Initialize clock 24 | if( log_start.tv_sec == 0 && log_start.tv_nsec == 0 ) { 25 | clock_gettime( CLOCK_MONOTONIC, &log_start ); 26 | } 27 | 28 | static char buf[10]; 29 | sprintf( buf, "[%8.2f] ", 30 | ((double) now.tv_sec + 1.0e-9 * now.tv_nsec) - 31 | ((double) log_start.tv_sec + 1.0e-9 * log_start.tv_nsec) 32 | ); 33 | 34 | return buf; 35 | } 36 | 37 | #endif 38 | 39 | void log_print( int priority, const char format[], ... ) { 40 | char buf[1024]; 41 | //const char *prefix; 42 | const char *time; 43 | va_list vlist; 44 | 45 | va_start( vlist, format ); 46 | vsnprintf( buf, sizeof(buf), format, vlist ); 47 | va_end( vlist ); 48 | 49 | #ifdef DEBUG 50 | time = log_time(); 51 | #else 52 | time = ""; 53 | #endif 54 | 55 | if( g_use_syslog ) { 56 | // Write messages to e.g. /var/log/syslog 57 | openlog( MAIN_SRVNAME, LOG_PID | LOG_CONS, LOG_USER | LOG_PERROR ); 58 | syslog( priority, "%s%s", time, buf ); 59 | closelog(); 60 | } else { 61 | FILE *out = (priority == LOG_ERR) ? stderr : stdout; 62 | fprintf( out, "%s %s\n", time, buf ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /log.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _LOG_H_ 3 | #define _LOG_H_ 4 | 5 | 6 | #include 7 | 8 | extern int g_verbosity; 9 | 10 | // Verbosity levels 11 | #define VERBOSITY_DEBUG LOG_DEBUG 12 | #define VERBOSITY_VERBOSE LOG_INFO 13 | #define VERBOSITY_QUIET LOG_WARNING 14 | 15 | #define log_err(...) { log_print( LOG_ERR, __VA_ARGS__ ); } 16 | #define log_info(...) if( g_verbosity >= LOG_INFO ) { log_print( LOG_INFO, __VA_ARGS__ ); } 17 | #define log_warn(...) if( g_verbosity >= LOG_WARNING ) { log_print( LOG_WARNING, __VA_ARGS__ ); } 18 | #ifdef DEBUG 19 | #define log_debug(...) if( g_verbosity >= LOG_DEBUG ) { log_print( LOG_DEBUG, __VA_ARGS__ ); } 20 | #else 21 | #define log_debug(...) // Exclude debug messages from debug build 22 | #endif 23 | 24 | // Print a log message 25 | void log_print( int priority, const char format[], ... ); 26 | 27 | 28 | #endif // _LOG_H_ 29 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | /* This contains the mmap calls. */ 17 | #include 18 | /* These are for error printing. */ 19 | #include 20 | #include 21 | #include 22 | /* This is for open. */ 23 | #include 24 | #include 25 | /* For exit. */ 26 | #include 27 | /* For the final part of the example. */ 28 | #include 29 | #include 30 | 31 | #include "metadata.pb-c.h" 32 | #include "utils.h" 33 | #include "crypto-stream-state/src/crypto_stream_xor.h" 34 | 35 | 36 | enum { 37 | LEAF, 38 | PARENT, 39 | ROOT 40 | }; 41 | 42 | #define TREE_ENTRY_SIZE 40 43 | #define SIGNATURES_ENTRY_SIZE 64 44 | #define BITFIELD_ENTRY_SIZE 3328 45 | 46 | uint8_t signatures_header[32] = { 47 | 0x05, 0x02, 0x57, 0x01, 0x00, 0x00, 0x40, 0x07, 48 | 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x00, 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 51 | }; 52 | 53 | uint8_t tree_header[32] = { 54 | 0x05, 0x02, 0x57, 0x02, 0x00, 0x00, 0x28, 0x07, 55 | 0x42, 0x4c, 0x41, 0x4b, 0x45, 0x32, 0x62, 0x00, 56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 58 | }; 59 | 60 | uint8_t bitfield_header[32] = { 61 | 0x05, 0x02, 0x57, 0x00, 0x00, 0x0d, 0x00, 0x00, 62 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 63 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 64 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 65 | }; 66 | 67 | uint32_t readU32(const char *m) { 68 | uint32_t n; 69 | memcpy(&n, m, 4); 70 | return ntohl(n); 71 | } 72 | 73 | uint64_t readU64(const char *m) { 74 | uint64_t n; 75 | memcpy(&n, m, 8); 76 | return be64toh(n); 77 | } 78 | 79 | uint16_t readU16(const char *m) { 80 | uint16_t n; 81 | memcpy(&n, m, 2); 82 | return ntohs(n); 83 | } 84 | 85 | uint8_t readU8(const char *m) { 86 | uint8_t n; 87 | memcpy(&n, m, 1); 88 | return n; 89 | } 90 | 91 | void readHash(uint8_t hash[], const char *m) { 92 | memcpy(hash, m, 32); 93 | } 94 | 95 | void bytes_from_hex( uint8_t bin[], const char hex[], size_t length ) { 96 | size_t i; 97 | size_t xv = 0; 98 | 99 | for( i = 0; i < length; ++i ) { 100 | const char c = hex[i]; 101 | if( c >= 'a' ) { 102 | xv += (c - 'a') + 10; 103 | } else if ( c >= 'A') { 104 | xv += (c - 'A') + 10; 105 | } else { 106 | xv += c - '0'; 107 | } 108 | 109 | if( i % 2 ) { 110 | bin[i / 2] = xv; 111 | xv = 0; 112 | } else { 113 | xv *= 16; 114 | } 115 | } 116 | } 117 | 118 | char *bytes_to_hex( char hex[], const uint8_t bin[], size_t len ) { 119 | static const char hexchars[16] = "0123456789abcdef"; 120 | size_t i; 121 | 122 | for( i = 0; i < len; ++i ) { 123 | hex[2 * i] = hexchars[bin[i] / 16]; 124 | hex[2 * i + 1] = hexchars[bin[i] % 16]; 125 | } 126 | hex[2 * len] = '\0'; 127 | return hex; 128 | } 129 | 130 | 131 | #include 132 | 133 | 134 | struct __attribute__((__packed__)) Node { 135 | uint8_t hash[32]; 136 | uint64_t size; 137 | }; 138 | 139 | /* 140 | struct __attribute__((__packed__)) Header { 141 | uint32_t id; 142 | uint8_t version; 143 | uint16_t entry_size; 144 | uint8_t length_prefix; 145 | char name[24]; 146 | };*/ 147 | 148 | void printHash(const uint8_t *hash) { 149 | int i; 150 | for(i = 0; i < 32; i++) { 151 | printf("%02x", hash[i]); 152 | } 153 | } 154 | 155 | void printHashBuf(uint8_t *buf, const uint8_t *hash) { 156 | int i; 157 | for(i = 0; i < 32; i++) { 158 | sprintf(((char*) buf) + 2 * i, "%02x", hash[i]); 159 | } 160 | } 161 | 162 | void printBits(size_t const size, void const * const ptr) { 163 | unsigned char *b = (unsigned char*) ptr; 164 | unsigned char byte; 165 | int i, j; 166 | 167 | for (i=size-1;i>=0;i--) { 168 | for (j=7;j>=0;j--) { 169 | byte = (b[i] >> j) & 1; 170 | printf("%u", byte); 171 | } 172 | } 173 | puts(""); 174 | } 175 | 176 | void printNode(const struct Node *e) { 177 | printf("Node: "); 178 | printHash(e->hash); 179 | printf(" %"PRIu64"\n", be64toh(e->size)); 180 | } 181 | 182 | void printNodes(const struct Node *nodes, uint32_t count) { 183 | for(uint32_t i = 0; i < count; i++) { 184 | printNode(&nodes[i]); 185 | } 186 | } 187 | 188 | /* 189 | int writeFile(const char *oPath, struct Node *tree, uint32_t blocks) { 190 | const char *name = "BLAKE2b"; 191 | struct stat s; 192 | 193 | // Open the file for reading. 194 | int fd = open (oPath, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 195 | if (fd < 0) { 196 | printf("open %s failed: %s\n", oPath, strerror (errno)); 197 | return 1; 198 | } 199 | 200 | struct Header header = { 201 | .id = htonl(0x05025702), 202 | .version = 0, 203 | .entry_size = htons(sizeof(struct Node)), 204 | .length_prefix = strlen(name), 205 | .name = { 0 } 206 | }; 207 | 208 | memcpy(&header.name, name, header.length_prefix); 209 | 210 | printf("written header:\n"); 211 | printHexDump((uint8_t*) &header, sizeof(struct Header)); 212 | 213 | const uint64_t lenh = sizeof(struct Header); 214 | if (write(fd, &header, lenh) != lenh) { 215 | printf("failed to write header to %s: %s\n", oPath, strerror (errno)); 216 | goto fail; 217 | } 218 | 219 | const uint64_t lenb = sizeof(struct Node) * blocks; 220 | if (write(fd, tree, lenb) != lenb) { 221 | printf("failed to write nodes to %s: %s\n", oPath, strerror (errno)); 222 | goto fail; 223 | } 224 | 225 | printf("Wrote %lu nodes to %s\n", blocks, oPath); 226 | close(fd); 227 | return 0; 228 | 229 | fail: 230 | close(fd); 231 | return 1; 232 | }*/ 233 | 234 | void hashNodePair(struct Node *out, const struct Node *left, const struct Node *right) { 235 | struct __attribute__((__packed__)) { 236 | uint8_t type; 237 | uint64_t size; 238 | uint8_t left_hash[32]; 239 | uint8_t right_hash[32]; 240 | } be; 241 | be.type = 1; 242 | be.size = htobe64(be64toh(left->size) + be64toh(right->size)); 243 | 244 | memcpy(be.left_hash, left->hash, 32); 245 | memcpy(be.right_hash, right->hash, 32); 246 | 247 | //uint8_t hash[crypto_generichash_BYTES]; // has to be 32 248 | crypto_generichash(out->hash, 32, (const uint8_t *) &be, sizeof(be), NULL, 0); 249 | out->size = be.size; 250 | } 251 | 252 | // first try to create a 253 | int hash_file(struct Node *nodes, const uint8_t *mapped, const uint64_t len, const uint64_t block_size) { 254 | struct __attribute__((__packed__)) { 255 | uint8_t type; 256 | uint64_t size; 257 | } data = { 0 }; 258 | 259 | crypto_generichash_state state; 260 | 261 | // compute child nodes 262 | uint64_t pos, index; 263 | for (pos = 0, index = 0; pos < len; pos += block_size, index += 2) { 264 | uint64_t read = MIN(block_size, len - pos); 265 | data.size = htobe64(read); 266 | struct Node *e = &nodes[index]; 267 | crypto_generichash_init(&state, NULL, 0, 32); 268 | crypto_generichash_update(&state, (uint8_t*) &data, sizeof(data)); 269 | crypto_generichash_update(&state, &mapped[pos], read); 270 | crypto_generichash_final(&state, e->hash, 32); 271 | e->size = data.size; 272 | } 273 | 274 | // compute parent nodes 275 | const uint64_t blocks = index; 276 | for (uint64_t depth = 1; depth < 64; depth++) { 277 | const uint64_t start = (1 << depth) - 1; // All last depth bits are set to 1 278 | const uint64_t step = (2 << depth); 279 | 280 | if (start >= blocks) { 281 | break; 282 | } 283 | 284 | for (uint64_t n = start; n < blocks; n += step) { 285 | const uint64_t r = n - step / 4; 286 | const uint64_t l = n + step / 4; 287 | //printBits(sizeof(n), &n); 288 | if (l < blocks) { 289 | hashNodePair(&nodes[n], &nodes[r], &nodes[l]); 290 | } else { 291 | memset(&nodes[n], 0, sizeof(struct Node)); 292 | } 293 | //printf("depth: %d, n: %d\n", depth, n); 294 | } 295 | } 296 | 297 | return 0; 298 | } 299 | 300 | uint64_t getChildSize(struct file *file, size_t index) { 301 | return be64toh( 302 | ((struct Node*) &file->mem[32])[index].size 303 | ); 304 | } 305 | 306 | // rename to openSleep? 307 | int openTree(struct file *file, const char path[], const uint8_t header[32], const uint32_t entry_size) { 308 | if (openFile(file, path)) { 309 | return 1; 310 | } 311 | 312 | if (file->size < 32 || ((file->size - 32) % entry_size) != 0) { 313 | return 1; 314 | } 315 | 316 | return (memcmp(file->mem, header, 32) != 0); 317 | } 318 | 319 | int print_tree_file(const char path[], uint64_t max) { 320 | struct file tree; 321 | 322 | if (openTree(&tree, path, tree_header, TREE_ENTRY_SIZE) == 0) { 323 | const int nodes = (tree.size - 32) / TREE_ENTRY_SIZE; 324 | printf("%d nodes:\n", nodes); 325 | struct Node* e = (struct Node*) &tree.mem[32]; 326 | 327 | for (int i = 0; i < MIN(nodes, max); i++) { 328 | printNode(&e[i]); 329 | } 330 | 331 | closeFile(&tree); 332 | printf("------------\n"); 333 | } 334 | 335 | return 0; 336 | } 337 | 338 | int read_metadata(const char *meta_path, const char *tree_path) { 339 | struct file file; 340 | 341 | if (openFile(&file, meta_path)) { 342 | return 1; 343 | } 344 | 345 | //printHexDump(file.mem, file.size); 346 | 347 | Header *header; 348 | Node *node; 349 | 350 | struct file tree; 351 | if (openTree(&tree, tree_path, tree_header, TREE_ENTRY_SIZE) != 0) { 352 | return 1; 353 | } 354 | 355 | printf("unpack header:\n"); 356 | size_t header_size = getChildSize(&tree, 0); 357 | header = header__unpack(NULL, header_size, (uint8_t*) file.mem); 358 | if (header == NULL) { 359 | fprintf(stderr, "error unpacking header message\n"); 360 | exit(1); 361 | } 362 | 363 | printf("type: %s\n", header->type); 364 | if (header->has_content) { 365 | printf("content.len: %lu\n", header->content.len); 366 | //printf("data: %llu\n", header->content.data); 367 | } 368 | 369 | header__free_unpacked(header, NULL); 370 | 371 | //printBase(&header->base); 372 | printf("unpack node:\n"); 373 | 374 | size_t nodes_count = (tree.size - 32) / TREE_ENTRY_SIZE; 375 | size_t offset = header_size; 376 | for (size_t index = 2; index < nodes_count; index += 2) { 377 | size_t node_size = getChildSize(&tree, index); 378 | node = node__unpack(NULL, node_size, ((uint8_t*) file.mem) + offset); 379 | offset += node_size; 380 | 381 | if (node == NULL) { 382 | fprintf(stderr, "error unpacking node message\n"); 383 | goto fail; 384 | } 385 | //printBase(&node->base); 386 | 387 | printf(" path: %s\n", node->path); 388 | 389 | Stat *stat = node->value; 390 | printf(" mode: %"PRIu32"\n", stat->mode); 391 | if (stat->has_uid) { 392 | printf(" uid: %"PRIu32"\n", stat->uid); 393 | } 394 | if (stat->has_gid) { 395 | printf(" gid: %"PRIu32"\n", stat->gid); 396 | } 397 | if (stat->has_size) { 398 | printf(" size: %"PRIu64"\n", stat->size); 399 | } 400 | if (stat->has_blocks) { 401 | printf(" blocks: %"PRIu64"\n", stat->blocks); 402 | } 403 | //... 404 | 405 | if (node->has_trie) { 406 | printf(" trie len: %lu\n", node->trie.len); 407 | } 408 | 409 | node__free_unpacked(node, NULL); 410 | } 411 | 412 | return 0; 413 | 414 | fail:; 415 | 416 | if (header) { 417 | header__free_unpacked(header, NULL); 418 | } 419 | 420 | if (node) { 421 | node__free_unpacked(node, NULL); 422 | } 423 | 424 | closeFile(&file); 425 | closeFile(&tree); 426 | return 1; 427 | } 428 | 429 | int read_key(const char path[]) { 430 | struct file file; 431 | if (openFile(&file, path)) { 432 | return 0; 433 | } 434 | 435 | printf("secret key:\n"); 436 | printHexDump(file.mem, file.size); 437 | 438 | closeFile(&file); 439 | 440 | return 0; 441 | } 442 | 443 | int read_signatures(const char path[]) { 444 | struct file tree; 445 | 446 | if (openTree(&tree, path, signatures_header, SIGNATURES_ENTRY_SIZE)) { 447 | return 1; 448 | } 449 | 450 | printf("signatures:\n"); 451 | printHexDump(tree.mem, tree.size); 452 | 453 | closeFile(&tree); 454 | 455 | return 0; 456 | } 457 | 458 | // Read last signature from file 459 | int read_signature(uint8_t signature[SIGNATURES_ENTRY_SIZE], const char path[]) { 460 | struct file sig; 461 | 462 | if (openTree(&sig, path, signatures_header, SIGNATURES_ENTRY_SIZE)) { 463 | return 1; 464 | } 465 | 466 | if (sig.size <= 32) { 467 | return 1; 468 | } 469 | 470 | memcpy(signature, sig.mem + sig.size - SIGNATURES_ENTRY_SIZE, SIGNATURES_ENTRY_SIZE); 471 | 472 | closeFile(&sig); 473 | 474 | return 0; 475 | } 476 | 477 | /* 478 | //TODO: test 479 | int bitfield_has_data_entry(struct file *file, size_t index) { 480 | if (index < 1024) { 481 | return 0; 482 | } 483 | return file->mem[index / 8] & (1 << index % 8); 484 | } 485 | 486 | int bitfield_has_tree_entry(struct file *file, size_t index) { 487 | if (index < 2048) { 488 | return 0; 489 | } 490 | index += 1024; 491 | return file->mem[index / 8] & (1 << index % 8); 492 | }*/ 493 | 494 | int read_bitfield(const char path[]) { 495 | struct file tree; 496 | 497 | if (openTree(&tree, path, bitfield_header, BITFIELD_ENTRY_SIZE)) { 498 | return 1; 499 | } 500 | 501 | printf("bitfield:\n"); 502 | printHexDump(tree.mem, tree.size); 503 | 504 | closeFile(&tree); 505 | 506 | return 0; 507 | } 508 | 509 | int read_public_key(uint8_t pkey[32], const char path[]) { 510 | struct file file; 511 | 512 | if (openFile(&file, path)) { 513 | return 1; 514 | } 515 | 516 | if (file.size != 32) { 517 | //printf("unexpected file size: %llu\n", file.size); 518 | closeFile(&file); 519 | return 1; 520 | } 521 | 522 | memcpy(pkey, file.mem, 32); 523 | 524 | closeFile(&file); 525 | 526 | return 0; 527 | } 528 | 529 | int read_secret_key(uint8_t skey[64], const char path[]) { 530 | struct file file; 531 | 532 | if (openFile(&file, path)) { 533 | return 1; 534 | } 535 | 536 | if (file.size != 64) { 537 | //printf("unexpected file size: %llu\n", file.size); 538 | closeFile(&file); 539 | return 1; 540 | } 541 | 542 | memcpy(skey, file.mem, 64); 543 | 544 | closeFile(&file); 545 | 546 | return 0; 547 | } 548 | 549 | 550 | int printFile(const char path[]) { 551 | struct file file; 552 | 553 | if (openFile(&file, path)) { 554 | return 1; 555 | } 556 | 557 | printf("%s (%lu):\n", path, file.size); 558 | printHexDump(file.mem, file.size); 559 | 560 | closeFile(&file); 561 | 562 | return 0; 563 | } 564 | 565 | //------- 566 | 567 | uint32_t hibit(uint64_t n) { 568 | n |= (n >> 1); 569 | n |= (n >> 2); 570 | n |= (n >> 4); 571 | n |= (n >> 8); 572 | n |= (n >> 16); 573 | n |= (n >> 32); 574 | return n - (n >> 1); //n ^ (n >> 1) 575 | } 576 | 577 | uint64_t getIndex (uint64_t depth, uint64_t offset) { 578 | return (offset << (depth + 1)) | ((1 << depth) - 1); 579 | } 580 | 581 | // Needed for signing root keys 582 | void next_root_index(const uint64_t max) { 583 | /* 584 | size_t v = max_index; 585 | size_t depth = 0; 586 | while (v >>= 1) { 587 | depth++; 588 | }*/ 589 | 590 | uint64_t idx = max; 591 | 592 | idx /= 2; 593 | 594 | uint64_t offset = 0; 595 | while (idx) { 596 | uint32_t factor = hibit(idx); 597 | //printf("idx: %llu\n", idx); 598 | printf("offset; %lu, factor: %u, %lu\n", offset, factor, offset + factor - 1); 599 | offset += 2 * factor; 600 | idx -= factor; //unset highest bit 601 | } 602 | } 603 | 604 | int root_indexes() { 605 | uint64_t node_count = 10; 606 | uint64_t idx = node_count; 607 | 608 | next_root_index(node_count); 609 | //101 610 | 611 | printf("hibit: %"PRIu32"\n", hibit(idx)); 612 | //lowbit 613 | uint64_t offset = 0; 614 | int highbit = 4; 615 | 616 | idx /= 2; //not needed when we do highbit - 1? 617 | for (int i = highbit; i >= 0; i--) { 618 | if (idx & (1 << i)) { 619 | //0xffffffffffffffff 620 | //TODO: efficient offset: i-te bit und höher weg 621 | printf("offset: %lu, factor: %d, %lu\n", offset, 1 << i, offset + (1 << i) - 1); 622 | offset += 2 << i; 623 | // 624 | } 625 | } 626 | 627 | return 0; 628 | } 629 | 630 | /* 631 | const uint64_t blocks = index; 632 | for (uint64_t depth = 1; depth < 64; depth++) { 633 | const uint64_t start = (1 << depth) - 1; 634 | const uint64_t step = (2 << depth); 635 | 636 | if (start >= blocks) { 637 | break; 638 | } 639 | 640 | for (uint64_t n = start; n < blocks; n += step) { 641 | const uint64_t r = n - step / 4; 642 | const uint64_t l = n + step / 4; 643 | if (l < blocks) { 644 | printf("pair %llu %llu => %llu\n", r, l, n); 645 | } else { 646 | printf("zero %llu\n", r); 647 | } 648 | } 649 | } 650 | */ 651 | 652 | /* 653 | exports.fullRoots = function (index, result) { 654 | if (index & 1Q) throw new Error('You can only look up roots for depth(0) blocks') 655 | if (!result) result = [] 656 | 657 | index /= 2 658 | 659 | var offset = 0 660 | var factor = 1 661 | 662 | while (true) { 663 | if (!index) return result 664 | while (factor * 2 <= index) factor *= 2 665 | result.push(offset + factor - 1) 666 | offset = offset + 2 * factor 667 | index -= factor 668 | factor = 1 669 | } 670 | } 671 | */ 672 | 673 | void rootHash(uint8_t hash[crypto_generichash_BYTES], struct file *tree) { 674 | // compute hash 675 | crypto_generichash_state state; 676 | 677 | crypto_generichash_init(&state, NULL, 0, crypto_generichash_BYTES); 678 | 679 | const struct Node *nodes = (const struct Node*) (tree->mem + 32); 680 | 681 | uint64_t c = ((tree->size - 32) / TREE_ENTRY_SIZE) / 2; //number of child nodes 682 | uint64_t offset = 0; 683 | 684 | printf("nodes: %lu\n", (tree->size - 32) / TREE_ENTRY_SIZE); 685 | 686 | // iterate over root nodes 687 | while (c) { 688 | uint32_t factor = hibit(c); 689 | const size_t index = offset + factor - 1; 690 | const struct Node *root = &nodes[index]; 691 | printf("root index: %lu\n", index); 692 | 693 | uint8_t type = 2; // root node 694 | //printHexDump(&type, 1); 695 | crypto_generichash_update(&state, &type, 1); 696 | //printHexDump(&root->hash, 32); 697 | crypto_generichash_update(&state, (uint8_t*) &root->hash, 32); 698 | uint64_t idx = htobe64(index); 699 | //printHexDump(&idx, 8); 700 | crypto_generichash_update(&state, (uint8_t*) &idx, 8); 701 | //printHexDump(&root->size, 8); 702 | crypto_generichash_update(&state, (uint8_t*) &root->size, 8); 703 | 704 | break; 705 | offset += 2 * factor; 706 | c -= factor; 707 | } 708 | crypto_generichash_final(&state, hash, crypto_generichash_BYTES); 709 | } 710 | 711 | int rootHashFromTree(uint8_t hash[crypto_generichash_BYTES], const char path[]) { 712 | struct file tree; 713 | 714 | if (openTree(&tree, path, tree_header, TREE_ENTRY_SIZE)) { 715 | return 1; 716 | } 717 | 718 | // Get hash o root nodes 719 | rootHash(hash, &tree); 720 | 721 | closeFile(&tree); 722 | 723 | return 0; 724 | } 725 | 726 | /* 727 | int sign_root(uint8_t sk[crypto_sign_SECRETKEYBYTES], uint8_t hash[crypto_generichash_BYTES]) { 728 | unsigned long long smlen; 729 | if( crypto_sign(sm, &smlen, hash, crypto_generichash_BYTES, sk) != 0) { 730 | return 1; 731 | } 732 | } 733 | */ 734 | int verify_root(uint8_t pk[crypto_sign_PUBLICKEYBYTES], uint8_t *m, size_t mlen) { //, uint8_t hash[crypto_generichash_BYTES]) { 735 | uint8_t encrypted_hash[crypto_generichash_BYTES]; 736 | long long unsigned encrypted_hash_len; 737 | if( crypto_sign_open(encrypted_hash, &encrypted_hash_len, m, mlen, pk) != 0) { 738 | return 1; 739 | } 740 | 741 | return 0; 742 | //return !((encrypted_hash_len == 32) && (memcmp(encrypted_hash, hash, 32) == 0)); 743 | } 744 | 745 | int signRootHash(uint8_t hash[crypto_generichash_BYTES]) { 746 | uint8_t sk[crypto_sign_SECRETKEYBYTES]; 747 | uint8_t pk[crypto_sign_PUBLICKEYBYTES]; 748 | uint8_t sm[crypto_generichash_BYTES+crypto_sign_BYTES]; 749 | uint8_t encrypted_hash[crypto_generichash_BYTES]; 750 | 751 | //memset(m, '\0', MAX_MSG_LEN); 752 | //snprintf(m, MAX_MSG_LEN, "%s", "Hello World!"); 753 | 754 | int rc = crypto_sign_keypair(pk, sk); 755 | if(rc < 0) { 756 | return 1; 757 | } 758 | 759 | unsigned long long smlen; 760 | if( crypto_sign(sm, &smlen, hash, crypto_generichash_BYTES, sk) != 0) { 761 | return 1; 762 | } 763 | 764 | printf("signed hash:\n"); 765 | printHexDump(sm, smlen); 766 | 767 | unsigned long long mlen; 768 | if( crypto_sign_open(encrypted_hash, &mlen, sm, smlen, pk) != 0) { 769 | return 1; 770 | } 771 | printf("smlen: %d, mlen: %d\n", (int) smlen, (int) mlen); 772 | printf("Verified!\n"); 773 | 774 | return 0; 775 | } 776 | 777 | int verify(const char signature_path[], const char tree_path[], const char pkey_path[]) { 778 | uint8_t signature[SIGNATURES_ENTRY_SIZE]; 779 | uint8_t pkey[32]; 780 | uint8_t hash[32]; 781 | 782 | // compute root hash of tree file 783 | if (rootHashFromTree(hash, tree_path)) { 784 | return 1; 785 | } 786 | 787 | printf("hash:\n"); 788 | printHexDump(hash, sizeof(hash)); 789 | 790 | if (read_public_key(pkey, pkey_path)) { 791 | return 1; 792 | } 793 | 794 | printf("pkey:\n"); 795 | printHexDump(pkey, sizeof(pkey)); 796 | 797 | if (read_signature(signature, signature_path)) { 798 | return 1; 799 | } 800 | 801 | printf("signature:\n"); 802 | printHexDump(signature, sizeof(signature)); 803 | 804 | uint8_t encrypted_hash[crypto_generichash_BYTES]; 805 | long long unsigned encrypted_hash_len; 806 | if (crypto_sign_open(encrypted_hash, &encrypted_hash_len, signature, sizeof(signature), pkey) != 0) { 807 | printf("crypto_sign_open failed\n"); 808 | return 1; 809 | } 810 | 811 | if (encrypted_hash_len != 32) { 812 | printf("unexpected enrypted hash len: %llu\n", encrypted_hash_len); 813 | return 1; 814 | } 815 | 816 | if (memcmp(hash, encrypted_hash, 32) != 0) { 817 | printf("unexpected enrypted hash:\n"); 818 | printHexDump(encrypted_hash, 32); 819 | return 1; 820 | } 821 | 822 | return 0; 823 | } 824 | 825 | int main(int argc, char **argv) { 826 | 827 | if (verify( 828 | "foo/.dat/metadata.signatures", 829 | "foo/.dat/metadata.tree", 830 | "foo/.dat/metadata.key")) { 831 | printf("failed\n"); 832 | } else { 833 | printf("verified\n"); 834 | } 835 | 836 | return 0; 837 | 838 | const char *root_entry = "ab27d45f509274ce0d08f4f09ba2d0e0d8df61a0c2a78932e81b5ef26ef398df"; 839 | struct Node root; 840 | bytes_from_hex((void*) &root, root_entry, strlen(root_entry)); 841 | 842 | uint8_t hash[crypto_generichash_BYTES]; 843 | crypto_generichash_state state; 844 | 845 | crypto_generichash_init(&state, NULL, 0, crypto_generichash_BYTES); 846 | 847 | uint8_t type = 2; // root node 848 | printHexDump(&type, 1); 849 | crypto_generichash_update(&state, &type, 1); 850 | 851 | printHexDump(&root.hash, 32); 852 | crypto_generichash_update(&state, (uint8_t*) &root.hash, crypto_generichash_BYTES); 853 | 854 | uint64_t idx = htobe64(0); 855 | printHexDump(&idx, 8); 856 | crypto_generichash_update(&state, (uint8_t*) &idx, 8); 857 | 858 | //printHexDump(&root.size, 8); 859 | uint64_t size = htobe64(1); 860 | crypto_generichash_update(&state, (uint8_t*) &size, 8); 861 | 862 | crypto_generichash_final(&state, hash, crypto_generichash_BYTES); 863 | 864 | printf("hash:\n"); 865 | printHexDump(hash, sizeof(hash)); 866 | 867 | 868 | const char *pkey_str = "9718a1ff1c4ca79feac551c0c7212a65e4091278ec886b88be01ee4039682238"; 869 | uint8_t pkey[64]; 870 | bytes_from_hex((void*) &pkey, pkey_str, strlen(pkey_str)); 871 | printf("pkey:\n"); 872 | printHexDump(pkey, sizeof(pkey)); 873 | 874 | const char *skey_str = "53729c0311846cca9cc0eded07aaf9e6689705b6a0b1bb8c3a2a839b72fda3839718a1ff1c4ca79feac551c0c7212a65e4091278ec886b88be01ee4039682238"; 875 | uint8_t skey[64]; 876 | bytes_from_hex((void*) &skey, skey_str, strlen(skey_str)); 877 | printf("skey:\n"); 878 | printHexDump(skey, sizeof(skey)); 879 | 880 | uint8_t signature[crypto_generichash_BYTES+crypto_sign_BYTES]; 881 | unsigned long long signaturelen; 882 | if( crypto_sign(signature, &signaturelen, hash, crypto_generichash_BYTES, skey) != 0) { 883 | return 1; 884 | } 885 | 886 | printf("signature:\n"); 887 | printHexDump(signature, signaturelen); 888 | 889 | uint8_t encrypted_hash[crypto_generichash_BYTES]; 890 | long long unsigned encrypted_hash_len; 891 | if (crypto_sign_open(encrypted_hash, &encrypted_hash_len, signature, signaturelen, pkey) != 0) { 892 | printf("crypto_sign_open failed\n"); 893 | return 1; 894 | } 895 | 896 | printf("encrypted_hash:\n"); 897 | printHexDump(encrypted_hash, encrypted_hash_len); 898 | 899 | return 0; 900 | 901 | printFile("foo/.dat/metadata.signatures"); 902 | 903 | //int has_skey = !read_secret_key(skey, "foo/.dat/content.secret_key"); 904 | //int has_pkey = !read_public_key(pkey, "foo/.dat/content.key"); 905 | //return print_tree_file("foo/.dat/metadata.tree", 9999); 906 | 907 | return read_bitfield("foo/.dat/metadata.bitfield"); 908 | return read_signatures("foo/.dat/metadata.signatures"); 909 | 910 | return read_metadata("foo/.dat/metadata.data", "foo/.dat/metadata.tree"); 911 | 912 | //read_key("foo/.dat/content.secret_key); 913 | 914 | 915 | //print_tree_file("foo/.dat/content.tree", 9999); 916 | 917 | const char *paths[] = {"foo/cat.png", "foo/welcome.txt"}; 918 | const char *oPath = "content.tree"; 919 | 920 | const uint64_t block_size = 65536; 921 | /* 922 | // Prepare output header 923 | const char *name = "BLAKE2b"; 924 | struct Header header = { 925 | .id = htonl(0x05025702), 926 | .version = 0, 927 | .entry_size = htons(sizeof(struct Node)), 928 | .length_prefix = strlen(name), 929 | .name = { 0 } 930 | }; 931 | memcpy(&header.name, name, sizeof()); 932 | */ 933 | // Open output file 934 | int ofd = open (oPath, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 935 | if (ofd < 0) { 936 | printf("open %s failed: %s\n", oPath, strerror (errno)); 937 | return 1; 938 | } 939 | 940 | // Write header 941 | //const uint64_t olenh = sizeof(struct Header); 942 | if (write(ofd, &tree_header, sizeof(tree_header)) != sizeof(tree_header)) { 943 | printf("failed to write header to %s: %s\n", oPath, strerror (errno)); 944 | close(ofd); 945 | return 1; 946 | } 947 | 948 | struct stat s; 949 | for(int i = 0; i < 2; i++) { 950 | const char *path = paths[i]; 951 | 952 | // Open infput file 953 | int ifd = open (path, O_RDONLY); 954 | if (ifd < 0) { 955 | printf("open %s failed: %s\n", path, strerror (errno)); 956 | return 1; 957 | } 958 | 959 | // Get the size of the file. 960 | int status = fstat (ifd, &s); 961 | if (status < 0) { 962 | printf("stat %s failed: %s\n", path, strerror (errno)); 963 | return 1; 964 | } 965 | 966 | char *mapped = mmap (0, s.st_size, PROT_READ, MAP_SHARED, ifd, 0); 967 | if (mapped == MAP_FAILED) { 968 | printf("mmap %s failed: %s\n", path, strerror (errno)); 969 | return 1; 970 | } 971 | 972 | uint32_t nodes_count = 2 - (s.st_size < block_size) + 2 * (s.st_size / block_size); 973 | struct Node *nodes = (struct Node*) malloc(nodes_count * sizeof(struct Node)); 974 | 975 | printf("Path: %s\n", path); 976 | 977 | hash_file(nodes, (uint8_t*) mapped, s.st_size, block_size); 978 | 979 | // Write nodes 980 | const uint64_t olenb = sizeof(struct Node) * nodes_count; 981 | if (write(ofd, nodes, olenb) != olenb) { 982 | printf("failed to write nodes to %s: %s\n", oPath, strerror (errno)); 983 | close(ofd); 984 | return 1; 985 | } 986 | 987 | printf("nodes_count: %u\n", nodes_count); 988 | printNodes(nodes, nodes_count); 989 | 990 | munmap(mapped, s.st_size); 991 | free(nodes); 992 | close(ifd); 993 | } 994 | 995 | close(ofd); 996 | 997 | // Read SLEEP files: *.signatures, *.bitfield and *.tree 998 | // *.key data for *.signatures, *.data raw data of *.tree 999 | 1000 | return 0; 1001 | } 1002 | -------------------------------------------------------------------------------- /metadata.proto: -------------------------------------------------------------------------------- 1 | 2 | syntax = "proto2"; 3 | 4 | message Header { 5 | required string type = 1; 6 | optional bytes content = 2; 7 | /* 8 | root: 9 | 1 = "hyperdrive" 10 | 2 = bytes (32) 11 | 0000 CE F0 96 9F 67 DB 0E 97 3F 70 90 56 97 87 53 B8 83 E7 6D 9D 33 89 77 F0 ....g...?p.V..S...m.3.w. 12 | 0018 45 39 DF 57 D3 78 E4 D7 E9.W.x.. 13 | 1 = "/cat.png" 14 | 2 = message: 15 | 1 = 33188 16 | 2 = 0 17 | 3 = 0 18 | 4 = 2747904 19 | 5 = 42 20 | 6 = 0 21 | 7 = 0 22 | 8 = 1515863450935 23 | 9 = 1515863450935 24 | 3 = bytes (3) 25 | 0000 01 00 00 ... 26 | 1 = "/welcome.txt" 27 | 2 = message: 28 | 1 = 33188 29 | 2 = 0 30 | 3 = 0 31 | 4 = 317 32 | 5 = 1 33 | 6 = 42 34 | 7 = 2747904 35 | 8 = 1515863450953 36 | 9 = 1515863450953 37 | 3 = bytes (4) 38 | 0000 01 01 01 00 39 | */ 40 | } 41 | 42 | message Node { 43 | required string path = 1; 44 | optional Stat value = 2; 45 | optional bytes trie = 3; 46 | //repeated Writer writers = 4; 47 | //optional uint64 writersSequence = 5; 48 | } 49 | 50 | message Writer { 51 | required bytes publicKey = 1; 52 | optional string permission = 2; 53 | } 54 | 55 | message Stat { 56 | required uint32 mode = 1; 57 | optional uint32 uid = 2; 58 | optional uint32 gid = 3; 59 | optional uint64 size = 4; 60 | optional uint64 blocks = 5; 61 | optional uint64 offset = 6; 62 | optional uint64 byteOffset = 7; 63 | optional uint64 mtime = 8; 64 | optional uint64 ctime = 9; 65 | } 66 | -------------------------------------------------------------------------------- /net.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include // close() 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "utils.h" 19 | #include "log.h" 20 | #include "net.h" 21 | 22 | // Callback for event loop 23 | typedef void net_callback( int rc, int fd ); 24 | 25 | static struct pollfd g_fds[16] = { { .fd = -1, .events = POLLIN, .revents = 0 } }; 26 | static net_callback* g_cbs[16] = { NULL }; 27 | int is_running = 0; 28 | time_t g_now = 0; 29 | 30 | 31 | // Set a socket non-blocking 32 | int net_set_nonblocking( int fd ) { 33 | return fcntl( fd, F_SETFL, fcntl( fd, F_GETFL ) | O_NONBLOCK ); 34 | } 35 | 36 | void net_add_handler(int fd, net_callback *cb) { 37 | int i; 38 | 39 | if (cb == NULL) { 40 | fprintf(stderr, "Invalid arguments."); 41 | exit(1); 42 | } 43 | 44 | for (i = 0; i < N_ELEMS(g_cbs); i++) { 45 | if (g_cbs[i] == NULL) { 46 | g_cbs[i] = cb; 47 | g_fds[i].fd = fd; 48 | g_fds[i].events = POLLIN; 49 | //printf("added: i: %d, cb: %d, fd: %d\n", i, !!g_cbs[i], g_fds[i].fd); 50 | return; 51 | } 52 | } 53 | 54 | fprintf(stderr, "No more space for handlers."); 55 | exit(1); 56 | } 57 | 58 | 59 | void list_handler() { 60 | int i; 61 | 62 | printf("list:\n"); 63 | for (i = 0; i < N_ELEMS(g_cbs); i++) { 64 | printf("i: %d, cb: %d, fd: %d\n", i, !!g_cbs[i], g_fds[i].fd); 65 | } 66 | } 67 | 68 | 69 | void net_remove_handler(int fd, net_callback *cb) { 70 | int i; 71 | 72 | if (cb == NULL) { 73 | fprintf(stderr, "Invalid arguments.\n"); 74 | exit(1); 75 | } 76 | 77 | for (i = 0; i < N_ELEMS(g_cbs); i++) { 78 | if (g_cbs[i] == cb && g_fds[i].fd == fd) { 79 | g_cbs[i] = NULL; 80 | g_fds[i].fd = -1; 81 | return; 82 | } 83 | } 84 | 85 | fprintf(stderr, "Handler not found to remove.\n"); 86 | exit(1); 87 | } 88 | 89 | void net_loop( void ) { 90 | int rc; 91 | int i; 92 | g_now = time( NULL ); 93 | 94 | is_running = 1; 95 | while (is_running) { 96 | //printf("Waiting on poll()...\n"); 97 | rc = poll(g_fds, N_ELEMS(g_fds), 1000); 98 | 99 | if (rc < 0) { 100 | //fprintf(stderr, "poll() failed"); 101 | break; 102 | } 103 | 104 | time_t n = time( NULL ); 105 | int call_all = (n > g_now); 106 | g_now = n; 107 | 108 | for (i = 0; i < N_ELEMS(g_cbs); i++) { 109 | if (g_cbs[i]) { 110 | int revents = g_fds[i].revents; 111 | /* 112 | int events = g_fds[i].events; 113 | if(revents & POLLWRBAND) printf("POLLWRBAND "); 114 | if(revents & POLLOUT) printf("POLLOUT "); 115 | if(revents & POLLHUP) printf("POLLHUP "); 116 | if(revents & POLLIN) printf("POLLIN "); 117 | if(revents & POLLERR) printf("POLLERR "); 118 | if(revents & POLLNVAL) printf("POLLNVAL "); 119 | printf("\n");*/ 120 | 121 | /*if (revents != 0 && revents != POLLIN) { 122 | fprintf(stderr, "revents = %d\n", revents); 123 | is_running = 0; 124 | } else*/ if (revents || call_all) { 125 | g_cbs[i](revents, g_fds[i].fd); 126 | } 127 | } 128 | } 129 | } 130 | } 131 | 132 | void net_free( void ) { 133 | int i; 134 | 135 | for (i = 0; i < N_ELEMS(g_cbs); i++) { 136 | g_cbs[i] = NULL; 137 | close(g_fds[i].fd); 138 | g_fds[i] = (struct pollfd){ .fd = -1, .events = POLLIN, .revents = 0 }; 139 | } 140 | } 141 | 142 | 143 | int net_socket( const char name[], const char ifname[], const int protocol, const int af ) { 144 | const int opt_on = 1; 145 | int sock; 146 | /* 147 | // Disable IPv6 or IPv4 148 | if( gconf->af != AF_UNSPEC && gconf->af != af ) { 149 | return -1; 150 | } 151 | */ 152 | if( (sock = socket( af, (protocol == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM, protocol ) ) < 0 ) { 153 | log_err( "%s: Failed to create socket: %s", name, strerror( errno ) ); 154 | goto fail; 155 | } 156 | 157 | if( net_set_nonblocking( sock ) < 0 ) { 158 | log_err( "%s: Failed to make socket nonblocking: %s", name, strerror( errno ) ); 159 | goto fail; 160 | } 161 | 162 | #if defined(__APPLE__) || defined(__CYGWIN__) || defined(__FreeBSD__) 163 | if( ifname ) { 164 | log_err( "%s: Bind to device not supported on Windows and MacOSX.", name ); 165 | goto fail; 166 | } 167 | #else 168 | if( ifname && setsockopt( sock, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen( ifname ) ) ) { 169 | log_err( "%s: Unable to bind to device %s: %s", name, ifname, strerror( errno ) ); 170 | goto fail; 171 | } 172 | #endif 173 | 174 | if( setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &opt_on, sizeof(opt_on) ) < 0 ) { 175 | log_err( "%s: Unable to set SO_REUSEADDR for %s: %s", name, ifname, strerror( errno ) ); 176 | goto fail; 177 | } 178 | 179 | return sock; 180 | 181 | fail: 182 | close( sock ); 183 | 184 | return -1; 185 | } 186 | 187 | int net_bind( 188 | const char name[], 189 | const char addr[], 190 | const int port, 191 | const char ifname[], 192 | const int protocol 193 | ) { 194 | const int opt_on = 1; 195 | socklen_t addrlen; 196 | IP sockaddr; 197 | int sock = -1; 198 | 199 | if( addr_parse( &sockaddr, addr, "0", AF_UNSPEC ) != 0 ) { 200 | log_err( "%s: Failed to parse IP address '%s'", 201 | name, addr 202 | ); 203 | goto fail; 204 | } 205 | 206 | port_set( &sockaddr, port ); 207 | 208 | if( (sock = net_socket( name, ifname, protocol, sockaddr.ss_family )) < 0 ) { 209 | goto fail; 210 | } 211 | 212 | if( sockaddr.ss_family == AF_INET6 ) { 213 | if( setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt_on, sizeof(opt_on) ) < 0 ) { 214 | log_err( "%s: Failed to set IPV6_V6ONLY for %s: %s", 215 | name, str_addr( &sockaddr ), strerror( errno ) ); 216 | goto fail; 217 | } 218 | } 219 | 220 | addrlen = addr_len( &sockaddr ); 221 | if( bind( sock, (struct sockaddr*) &sockaddr, addrlen ) < 0 ) { 222 | log_err( "%s: Failed to bind socket to %s: %s", 223 | name, str_addr( &sockaddr ), strerror( errno ) 224 | ); 225 | goto fail; 226 | } 227 | 228 | if( protocol == IPPROTO_TCP && listen( sock, 5 ) < 0 ) { 229 | log_err( "%s: Failed to listen on %s: %s (%s)", 230 | name, str_addr( &sockaddr ), strerror( errno ) 231 | ); 232 | goto fail; 233 | } 234 | 235 | log_info( ifname ? "%s: Bind to %s, interface %s" : "%s: Bind to %s", 236 | name, str_addr( &sockaddr ), ifname 237 | ); 238 | 239 | return sock; 240 | 241 | fail: 242 | close( sock ); 243 | return -1; 244 | } 245 | -------------------------------------------------------------------------------- /net.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _NET_H 3 | #define _NET_H 4 | 5 | extern int is_running; 6 | extern time_t g_now; 7 | 8 | typedef struct sockaddr_storage IP; 9 | typedef struct sockaddr_in IP4; 10 | typedef struct sockaddr_in6 IP6; 11 | 12 | // Callback for event loop 13 | typedef void net_callback(int revents, int fd); 14 | 15 | // Create a socket and bind to interface 16 | int net_socket( 17 | const char name[], 18 | const char ifname[], 19 | const int protocol, 20 | const int af 21 | ); 22 | 23 | // Create a socket and bind to address/interface 24 | int net_bind( 25 | const char name[], 26 | const char addr[], 27 | const int port, 28 | const char ifname[], 29 | const int protocol 30 | ); 31 | 32 | int net_set_nonblocking(int fd); 33 | 34 | // Add callback with file descriptor to listen for packets 35 | void net_add_handler(int fd, net_callback *callback); 36 | 37 | // Remove callback 38 | void net_remove_handler(int fd, net_callback *callback); 39 | 40 | // Start loop for all network events 41 | void net_loop(void); 42 | 43 | // Close sockets 44 | void net_free(void); 45 | 46 | #endif // _NET_H 47 | -------------------------------------------------------------------------------- /schema.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | // wire format is (
) 4 | // header is a varint, channel << 4 | <4-bit-type> 5 | 6 | // type=0, should be the first message sent on a channel 7 | message Feed { 8 | required bytes discoveryKey = 1; 9 | optional bytes nonce = 2; 10 | } 11 | 12 | // type=1, overall connection handshake. should be send just after the feed message on the first channel only 13 | message Handshake { 14 | optional bytes id = 1; 15 | optional bool live = 2; // keep the connection open forever? both ends have to agree 16 | optional bytes userData = 3; 17 | repeated string extensions = 4; 18 | optional bool ack = 5; // Should all blocks be explicitly acknowledged? 19 | } 20 | 21 | // type=2, message indicating state changes etc. 22 | // initial state for uploading/downloading is true 23 | // if both ends are not downloading and not live it is safe to consider the stream ended 24 | message Info { 25 | optional bool uploading = 1; 26 | optional bool downloading = 2; 27 | } 28 | 29 | // type=3, what do we have? 30 | message Have { 31 | required uint64 start = 1; 32 | optional uint64 length = 2 [default = 1]; // defaults to 1 33 | optional bytes bitfield = 3; 34 | } 35 | 36 | // type=4, what did we lose? 37 | message Unhave { 38 | required uint64 start = 1; 39 | optional uint64 length = 2 [default = 1]; // defaults to 1 40 | } 41 | 42 | // type=5, what do we want? remote should start sending have messages in this range 43 | message Want { 44 | required uint64 start = 1; 45 | optional uint64 length = 2; // defaults to Infinity or feed.length (if not live) 46 | } 47 | 48 | // type=6, what don't we want anymore? 49 | message Unwant { 50 | required uint64 start = 1; 51 | optional uint64 length = 2; // defaults to Infinity or feed.length (if not live) 52 | } 53 | 54 | // type=7, ask for data 55 | message Request { 56 | required uint64 index = 1; 57 | optional uint64 bytes = 2; 58 | optional bool hash = 3; 59 | optional uint64 nodes = 4; 60 | } 61 | 62 | // type=8, cancel a request 63 | message Cancel { 64 | required uint64 index = 1; 65 | optional uint64 bytes = 2; 66 | optional bool hash = 3; 67 | } 68 | 69 | // type=9, get some data 70 | message Data { 71 | message Node { 72 | required uint64 index = 1; 73 | required bytes hash = 2; 74 | required uint64 size = 3; 75 | } 76 | 77 | required uint64 index = 1; 78 | optional bytes value = 2; 79 | repeated Node nodes = 3; 80 | optional bytes signature = 4; 81 | } 82 | 83 | // type=15 (last massage) is an extension message 84 | // that is encoded like this 85 | -------------------------------------------------------------------------------- /server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include // close() 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "crypto-stream-state/src/crypto_stream_xor.h" 31 | #include "schema.pb-c.h" 32 | #include "utils.h" 33 | 34 | #include "net.h" 35 | #include "utils.h" 36 | #include "varint.h" 37 | #include "dht_wrapper.h" 38 | 39 | 40 | #define DEBUGIO 0 41 | 42 | 43 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) 44 | #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) 45 | #define SERVER_PORT 12345 46 | 47 | 48 | void createDiscoveryKey(uint8_t hash[32], const uint8_t pkey[32]) 49 | { 50 | crypto_generichash(hash, 32, (uint8_t*) "hypercore", 9, pkey, 32); 51 | } 52 | 53 | enum MessageType { 54 | TYPE_FEED, 55 | TYPE_HANDSHAKE, 56 | TYPE_INFO, 57 | TYPE_HAVE, 58 | TYPE_UNHAVE, 59 | TYPE_WANT, 60 | TYPE_UNWANT, 61 | TYPE_REQUEST, 62 | TYPE_CANCEL, 63 | TYPE_DATA 64 | }; 65 | 66 | struct Register 67 | { 68 | char *pkey_path; 69 | uint8_t pkey[32]; 70 | uint8_t discovery_key[32]; 71 | }; 72 | 73 | enum ConnectionDirection { 74 | OUTGOING_CONNECTION, 75 | INCOMING_CONNECTION 76 | }; 77 | 78 | const char *direction_str(enum ConnectionDirection d) 79 | { 80 | switch (d) { 81 | case OUTGOING_CONNECTION: 82 | return "OUTGOING"; 83 | case INCOMING_CONNECTION: 84 | return "INCOMING"; 85 | default: 86 | return ""; 87 | } 88 | } 89 | 90 | /* 91 | INCOMING: 92 | enum State 93 | { 94 | RECEIVE_FEED 95 | SEND_FEED 96 | RECEIVE_HANDSHAKE 97 | SEND_HANDSHAKE 98 | RECEIVE_HAVE 99 | SEND_INFO 100 | //SEND_WANT 101 | }; 102 | 103 | OUTGOING: 104 | enum State 105 | { 106 | SEND_FEED 107 | RECEIVE_FEED 108 | SEND_HANDSHAKE 109 | RECEIVE_HANDSHAKE 110 | SEND_INFO 111 | RECEIVE_HAVE 112 | //SEND_WANT 113 | }; 114 | 115 | enum State 116 | { 117 | WAIT_FEED 118 | WAIT_HANDSHAKE 119 | INFO 120 | HAVE 121 | //SEND_WANT 122 | }; 123 | 124 | if (session->direction == OUTGOING_CONNECTION) { 125 | //we can send a feed 126 | switch(session->state) { 127 | case RECEIVE_FEED: 128 | sendHandshake(); 129 | session->state = RECEIVE_HANDSHAKE; 130 | break; 131 | case RECEIVE_HANDSHAKE: 132 | session->state = SEND_HANDSHAKE; 133 | break; 134 | } 135 | } 136 | 137 | */ 138 | 139 | struct Session { 140 | struct Session *next; 141 | struct sockaddr_storage clientaddr; 142 | int clientsock; 143 | enum ConnectionDirection direction; //not used yet 144 | 145 | uint8_t buffer[1024]; //in_buffer 146 | uint8_t buffer_len; 147 | 148 | // Register of the last FEED message 149 | struct Register *reg; //current register 150 | 151 | // Peer crypto parameters/state 152 | int in_nonce_received; 153 | uint8_t in_nonce[crypto_stream_xor_NONCEBYTES]; 154 | crypto_stream_xor_state in_state; 155 | 156 | // Own crypto parameters/state 157 | int out_nonce_send; 158 | uint8_t out_nonce[crypto_stream_xor_NONCEBYTES]; 159 | crypto_stream_xor_state out_state; 160 | }; 161 | 162 | 163 | struct Session *g_sessions = NULL; 164 | static struct Register g_metadata = {0}; 165 | static struct Register g_content = {0}; 166 | 167 | 168 | static struct Session *findSession(int fd) 169 | { 170 | struct Session *session; 171 | 172 | session = g_sessions; 173 | while (session) { 174 | if (session->clientsock == fd) { 175 | return session; 176 | } 177 | session = session->next; 178 | } 179 | 180 | return NULL; 181 | } 182 | 183 | static void removeSession(struct Session *s) 184 | { 185 | struct Session *session; 186 | struct Session *prev; 187 | 188 | prev = NULL; 189 | session = g_sessions; 190 | while (session) { 191 | if (session == s) { 192 | if (prev) { 193 | prev->next = session->next; 194 | } else { 195 | g_sessions = session->next; 196 | } 197 | free(session); 198 | return; 199 | } 200 | prev = session; 201 | session = session->next; 202 | } 203 | } 204 | 205 | static struct Session *addSession(const struct sockaddr_storage *addr, int clientsock, enum ConnectionDirection direction) 206 | { 207 | struct Session *session; 208 | 209 | session = (struct Session*) calloc(1, sizeof(struct Session)); 210 | memcpy(&session->clientaddr, addr, sizeof(struct sockaddr_storage)); 211 | bytes_random(&session->out_nonce[0], crypto_stream_xor_NONCEBYTES); 212 | session->clientsock = clientsock; 213 | session->direction = direction; 214 | 215 | // Setup out_state for crypto (int_state init requires in_nonce to be received) 216 | #if DEBUGIO 217 | printf("addSession:\n"); 218 | printf(" crypto out pkey:\n"); 219 | printHexDump(&g_metadata.pkey[0], 32); 220 | printf(" crypto out nonce:\n"); 221 | printHexDump(&session->out_nonce[0], crypto_stream_xor_NONCEBYTES); 222 | printf(" direction: %s\n", direction_str(direction)); 223 | #endif 224 | 225 | crypto_stream_xor_init(&session->out_state, &session->out_nonce[0], &g_metadata.pkey[0]); 226 | 227 | if (g_sessions) { 228 | session->next = g_sessions; 229 | } 230 | g_sessions = session; 231 | 232 | return session; 233 | } 234 | 235 | int send_msg(struct Session *session, int type, int channel, uint8_t data[], size_t offset, size_t msgsize) 236 | { 237 | uint8_t cbuf[1000]; 238 | int rc; 239 | 240 | uint32_t header = (channel << 4) + (type & 15); 241 | size_t header_len = uint32_size(header); 242 | size_t bodysize = header_len + msgsize; 243 | size_t bodysize_len = uint32_size(bodysize); 244 | 245 | if (offset < (header_len + bodysize_len)) { 246 | printf("message offset too small (%ld > %ld + %ld)\n", offset, header_len, bodysize_len); 247 | return EXIT_FAILURE; 248 | } 249 | 250 | uint32_pack(bodysize, &data[offset - header_len - bodysize_len]); 251 | uint32_pack(header, &data[offset - header_len]); 252 | 253 | size_t packet_offset = offset - header_len - bodysize_len; 254 | size_t packet_size = header_len + bodysize_len + msgsize; 255 | 256 | //printf("packet_size: %llu (packet_offset: %d)\n", packet_size, packet_offset); 257 | 258 | if (packet_size > sizeof(cbuf)) { 259 | printf("Message too big for crypto buffer\n"); 260 | return EXIT_FAILURE; 261 | } 262 | 263 | #if DEBUGIO 264 | printf("send:\n"); 265 | printHexDump(&data[packet_offset], packet_size); 266 | #endif 267 | 268 | // Always send feed unecrypted 269 | if (type == TYPE_FEED) { 270 | memcpy(cbuf, &data[packet_offset], packet_size); 271 | } else if (session->out_nonce_send) { 272 | crypto_stream_xor_update(&session->out_state, cbuf, &data[packet_offset], packet_size); 273 | } else { 274 | printf("Should not send message. Other side hasn't received feed yet\n"); 275 | return EXIT_FAILURE; 276 | } 277 | 278 | #if DEBUGIO 279 | printf("send raw:\n"); 280 | printHexDump(cbuf, packet_size); 281 | #endif 282 | 283 | rc = send(session->clientsock, cbuf, packet_size, 0); 284 | 285 | if (rc != packet_size) { 286 | printf("send(): %s\n", strerror(errno)); 287 | return EXIT_FAILURE; 288 | } else { 289 | // Assume first packet sends nonce 290 | if (!session->out_nonce_send) { 291 | // From now on all send messages over this connection are encrypted 292 | session->out_nonce_send = 1; 293 | } 294 | return EXIT_SUCCESS; 295 | } 296 | } 297 | 298 | int send_feed(struct Session *session, uint8_t discovery_key[32]) 299 | { 300 | uint8_t buf[1000]; 301 | int channel = 0; 302 | 303 | printf("Send FEED\n"); 304 | // Send Feed 305 | Feed feed = FEED__INIT; 306 | 307 | //if (session->reg) { 308 | // feed.discoverykey.data = &session->reg->discovery_key[0]; 309 | //} else { 310 | // printf("No feed message received yet, send content discovery key\n"); 311 | // feed.discoverykey.data = &g_metadata.discovery_key[0]; 312 | //} 313 | 314 | feed.discoverykey.data = discovery_key; 315 | feed.discoverykey.len = 32; 316 | feed.has_nonce = 1; 317 | feed.nonce.data = &session->out_nonce[0]; 318 | feed.nonce.len = crypto_stream_xor_NONCEBYTES; 319 | 320 | int len = feed__get_packed_size(&feed); 321 | feed__pack(&feed, buf + 8); 322 | 323 | return send_msg(session, TYPE_FEED, channel, buf, 8, len); 324 | } 325 | 326 | int send_handshake(struct Session *session) 327 | { 328 | uint8_t buf[1000]; 329 | uint8_t id[32]; 330 | int channel = 0; 331 | 332 | printf("Send HANDSHAKE\n"); 333 | // Send Handshake 334 | Handshake handshake = HANDSHAKE__INIT; 335 | 336 | // just to identify if we connect to ourselves 337 | bytes_random(&id[0], 32); 338 | 339 | // Keep connection open forever (both side have to agree) 340 | handshake.has_id = 1; 341 | handshake.id.data = id; 342 | handshake.id.len = 32; 343 | handshake.has_live = 1; 344 | handshake.live = 0; 345 | handshake.has_ack = 1; 346 | handshake.ack = 0; 347 | handshake.has_userdata = 0; 348 | handshake.n_extensions = 0; 349 | 350 | int len = handshake__get_packed_size(&handshake); 351 | handshake__pack(&handshake, buf + 8); 352 | 353 | return send_msg(session, TYPE_HANDSHAKE, channel, buf, 8, len); 354 | } 355 | 356 | int send_info(struct Session *session) 357 | { 358 | uint8_t buf[1000]; 359 | int channel = 0; 360 | 361 | printf("Send INFO\n"); 362 | Info info = INFO__INIT; 363 | 364 | info.has_uploading = 1; 365 | info.uploading = 0; 366 | info.has_downloading = 1; 367 | info.downloading = 1; 368 | 369 | int len = info__get_packed_size(&info); 370 | info__pack(&info, buf + 8); 371 | 372 | return send_msg(session, TYPE_INFO, channel, buf, 8, len); 373 | } 374 | 375 | int send_have(struct Session *session) 376 | { 377 | uint8_t buf[1000]; 378 | int channel = 0; 379 | 380 | printf("Send HAVE\n"); 381 | Have have = HAVE__INIT; 382 | 383 | have.start = 0; 384 | have.has_length = 1; 385 | have.length = 0; 386 | have.has_bitfield = 0; 387 | 388 | int len = have__get_packed_size(&have); 389 | have__pack(&have, buf + 8); 390 | 391 | return send_msg(session, TYPE_HAVE, channel, buf, 8, len); 392 | } 393 | 394 | int send_want(struct Session *session) 395 | { 396 | uint8_t buf[1000]; 397 | int channel = 0; 398 | 399 | printf("Send WANT\n"); 400 | Want want = WANT__INIT; 401 | 402 | want.start = 0; 403 | want.has_length = 0; 404 | 405 | int len = want__get_packed_size(&want); 406 | want__pack(&want, buf + 8); 407 | 408 | return send_msg(session, TYPE_WANT, channel, buf, 8, len); 409 | } 410 | 411 | // parse incoming connection 412 | int parse_message(struct Session *session, const uint8_t *src, size_t size) 413 | { 414 | int i; 415 | 416 | //printf("parse_message: %llu\n", size); 417 | 418 | if (size == 0) { 419 | return 0; 420 | } 421 | 422 | // [] 423 | 424 | // Size of the following data 425 | size_t msgsize_len = varint_scan(src, size); 426 | 427 | if (msgsize_len == 0) { 428 | return 0; 429 | } 430 | 431 | uint32_t msgsize = varint_parse_uint32(src, msgsize_len); 432 | 433 | if (msgsize > 8*1000*1000) { 434 | printf("msgsize > 8MB\n"); 435 | return -1; 436 | } 437 | 438 | // Enough data 439 | if (msgsize > size) { 440 | //printHexDump(src, size); 441 | printf("More data needed!! (needed: %u, got: %lu)\n", msgsize, size); 442 | return 0; 443 | } 444 | 445 | size_t header_len = varint_scan(src + msgsize_len, size - msgsize_len); 446 | 447 | if (header_len == 0) { 448 | return 0; 449 | } 450 | 451 | uint32_t header = varint_parse_uint32(src + msgsize_len, header_len); 452 | 453 | //int channel = header >> 4; 454 | int type = header & 15; 455 | 456 | const uint8_t *pb = src + msgsize_len + header_len; 457 | const size_t pbsize = msgsize - header_len; 458 | 459 | //printf("parse_message: type: %d, channel: %d, pbsize: %llu, header_len: %llu, msgsize_len: %llu, msgsize: %llu\n", type, channel, pbsize, header_len, msgsize_len, msgsize); 460 | #if DEBUGIO 461 | printf("received:\n"); 462 | printHexDump(src, size); 463 | #endif 464 | 465 | switch (type) { 466 | case TYPE_FEED: 467 | { 468 | Feed *feed = feed__unpack(NULL, pbsize, pb); 469 | if (!feed) { 470 | printf("Invalid feed message\n"); 471 | return -1; 472 | } 473 | printf("Received FEED:\n"); 474 | 475 | if (feed->discoverykey.len != 32) { 476 | return -1; 477 | } 478 | 479 | //printf("got discoveryKey:\n"); 480 | //printHexDump(feed->discoverykey.data, 32); 481 | 482 | if (0 == memcmp(&g_metadata.discovery_key[0], feed->discoverykey.data, 32)) { 483 | printf("Got metadata discovery key\n"); 484 | session->reg = &g_metadata; 485 | } else if (0 == memcmp(&g_content.discovery_key[0], feed->discoverykey.data, 32)) { 486 | printf("Got content discovery key\n"); 487 | session->reg = &g_content; 488 | } else { 489 | printf("Peer asked for unknown discoverykey\n"); 490 | printHexDump(feed->discoverykey.data, 32); 491 | return -1; 492 | } 493 | 494 | //printf("got discoveryKey:\n"); 495 | //printHexDump(feed->discoverykey.data, 32); 496 | 497 | if (!session->in_nonce_received) { 498 | if (!feed->has_nonce) 499 | return -1; 500 | if (feed->nonce.len != crypto_stream_xor_NONCEBYTES) 501 | return -1; 502 | 503 | memcpy(&session->in_nonce[0], feed->nonce.data, crypto_stream_xor_NONCEBYTES); 504 | session->in_nonce_received = 1; 505 | 506 | printf("Got nonce:\n"); 507 | printHexDump(&session->in_nonce[0], crypto_stream_xor_NONCEBYTES); 508 | } 509 | 510 | feed__free_unpacked(feed, NULL); 511 | break; 512 | } 513 | case TYPE_HANDSHAKE: 514 | { 515 | Handshake *handshake = handshake__unpack(NULL, pbsize, pb); 516 | if (!handshake) { 517 | printf("Invalid handshake message\n"); 518 | return -1; 519 | } 520 | printf("Received HANDSHAKE:\n"); 521 | 522 | if (handshake->has_id) { 523 | printf("id:\n"); 524 | printHexDump(handshake->id.data, handshake->id.len); 525 | } 526 | 527 | if (handshake->has_live) { 528 | printf(" live: %d\n", handshake->live); 529 | } 530 | 531 | if (handshake->has_userdata) { 532 | printf("userdata:\n"); 533 | printHexDump(handshake->userdata.data, handshake->userdata.len); 534 | } 535 | 536 | for (i = 0; i < handshake->n_extensions; i++) { 537 | printf(" extension: %s\n", handshake->extensions[i]); 538 | } 539 | 540 | if (handshake->has_ack) { 541 | printf(" ack: %d\n", handshake->ack); 542 | } 543 | 544 | handshake__free_unpacked(handshake, NULL); 545 | break; 546 | } 547 | case TYPE_INFO: 548 | { 549 | Info *info = info__unpack(NULL, pbsize, pb); 550 | if (!info) { 551 | printf("Invalid info message\n"); 552 | return -1; 553 | } 554 | printf("Received INFO:\n"); 555 | 556 | if (info->has_uploading) { 557 | printf(" uploading: %d\n", info->uploading); 558 | } 559 | if (info->has_downloading) { 560 | printf(" downloading: %d\n", info->downloading); 561 | } 562 | 563 | info__free_unpacked(info, NULL); 564 | break; 565 | } 566 | case TYPE_HAVE: 567 | { 568 | Have *have = have__unpack(NULL, pbsize, pb); 569 | if (!have) { 570 | printf("Invalid have message\n"); 571 | return -1; 572 | } 573 | printf("Received HAVE:\n"); 574 | 575 | printf(" start: %lu\n", have->start); 576 | printf(" length: %lu\n", have->length); 577 | if (have->has_bitfield) { 578 | printHexDump(have->bitfield.data, have->bitfield.len); 579 | } 580 | 581 | have__free_unpacked(have, NULL); 582 | break; 583 | } 584 | case TYPE_UNHAVE: 585 | { 586 | Unhave *unhave = unhave__unpack(NULL, pbsize, pb); 587 | if (!unhave) { 588 | printf("Invalid unhave message\n"); 589 | return -1; 590 | } 591 | printf("Received UNHAVE:\n"); 592 | 593 | printf(" start: %lu\n", unhave->start); 594 | if (unhave->has_length) { 595 | printf(" length: %lu\n", unhave->length); //is default set? 596 | } 597 | unhave__free_unpacked(unhave, NULL); 598 | break; 599 | } 600 | case TYPE_WANT: 601 | { 602 | Want *want = want__unpack(NULL, pbsize, pb); 603 | if (!want) { 604 | printf("Invalid want message\n"); 605 | return -1; 606 | } 607 | printf("Received WANT:\n"); 608 | 609 | printf(" start: %lu\n", want->start); 610 | if (want->has_length) { 611 | printf(" length: %lu\n", want->length); 612 | } 613 | want__free_unpacked(want, NULL); 614 | break; 615 | } 616 | case TYPE_UNWANT: 617 | { 618 | Unwant *unwant = unwant__unpack(NULL, pbsize, pb); 619 | if (!unwant) { 620 | printf("Invalid unwant message\n"); 621 | return -1; 622 | } 623 | printf("Received UNWANT:\n"); 624 | 625 | printf(" start: %lu\n", unwant->start); 626 | if (unwant->has_length) { 627 | printf(" length: %lu\n", unwant->length); 628 | } 629 | 630 | unwant__free_unpacked(unwant, NULL); 631 | break; 632 | } 633 | case TYPE_REQUEST: 634 | { 635 | Request *request = request__unpack(NULL, pbsize, pb); 636 | if (!request) { 637 | printf("Invalid request message\n"); 638 | return -1; 639 | } 640 | printf("Received REQUEST:\n"); 641 | 642 | printf(" index: %lu\n", request->index); 643 | if (request->has_bytes) { 644 | printf(" bytes: %lu\n", request->bytes); 645 | } 646 | if (request->has_hash) { 647 | printf(" hash: %d\n", request->hash); 648 | } 649 | if (request->has_nodes) { 650 | printf(" nodes: %lu\n", request->nodes); 651 | } 652 | 653 | request__free_unpacked(request, NULL); 654 | break; 655 | } 656 | case TYPE_CANCEL: 657 | { 658 | Cancel *cancel = cancel__unpack(NULL, pbsize, pb); 659 | if (!cancel) { 660 | printf("Invalid cancel message\n"); 661 | return -1; 662 | } 663 | printf("Received CANCEL:\n"); 664 | 665 | printf(" index: %lu\n", cancel->index); 666 | if (cancel->bytes) { 667 | printf(" bytes: %lu\n", cancel->bytes); 668 | } 669 | if (cancel->hash) { 670 | printf(" hash: %d\n", cancel->hash); 671 | } 672 | 673 | cancel__free_unpacked(cancel, NULL); 674 | break; 675 | } 676 | case TYPE_DATA: 677 | { 678 | Data *data = data__unpack(NULL, pbsize, pb); 679 | if (!data) { 680 | printf("Invalid data message\n"); 681 | return -1; 682 | } 683 | printf("Received DATA:\n"); 684 | 685 | printf(" index: %lu\n", data->index); 686 | if (data->has_value) { 687 | printHexDump(data->value.data, data->value.len); 688 | } 689 | 690 | for (i = 0; i < data->n_nodes; i++) { 691 | Data__Node *node = data->nodes[i]; 692 | printf(" node: index: %lu\n", node->index); 693 | printHexDump(node->hash.data, node->hash.len); 694 | printf(" node: size: %lu\n", node->size); 695 | } 696 | 697 | if (data->has_signature) { 698 | printHexDump(data->signature.data, data->signature.len); 699 | } 700 | 701 | data__free_unpacked(data, NULL); 702 | break; 703 | } 704 | default: 705 | printf("Invalid message type\n"); 706 | return -1; 707 | } 708 | 709 | return msgsize_len + header_len + pbsize; 710 | } 711 | 712 | int handle_connection3(struct Session *session, uint8_t *data, size_t size) 713 | { 714 | #if DEBUGIO 715 | printf("received raw:\n"); 716 | printHexDump(data, size); 717 | #endif 718 | 719 | if (size > (FIELD_SIZEOF(struct Session, buffer) - session->buffer_len)) { 720 | printf("Buffer full\n"); 721 | return -1; 722 | } 723 | 724 | if (session->in_nonce_received) { 725 | printf("decrypt received\n"); 726 | //printf("crypto_stream_xor_update %llu, to_copy: %llu\n", session->buffer_len, to_copy); 727 | int rc = crypto_stream_xor_update(&session->in_state, &session->buffer[session->buffer_len], data, size); 728 | if (rc) return -1; 729 | } else { 730 | // Append data 731 | memcpy(&session->buffer[session->buffer_len], data, size); 732 | } 733 | 734 | session->buffer_len += size; 735 | 736 | while (1) { 737 | int prev_in_nonce_received = session->in_nonce_received; 738 | int consumed = parse_message(session, &session->buffer[0], session->buffer_len); 739 | if (consumed < 0) { 740 | printf("parsing error => close connection\n"); 741 | return -1; 742 | } 743 | 744 | if (consumed == 0) { 745 | // need more data or no dat left 746 | break; 747 | } 748 | 749 | // Remove consumed data from buffer 750 | size_t newlen = session->buffer_len - consumed; 751 | memmove(&session->buffer[0], &session->buffer[consumed], newlen); 752 | session->buffer_len = newlen; 753 | 754 | // Switch to encryption as we have just received the encryption nonce 755 | if (0 == prev_in_nonce_received && session->in_nonce_received) { 756 | uint8_t tmp[FIELD_SIZEOF(struct Session, buffer)]; 757 | 758 | #if DEBUGIO 759 | printf("switch to encrypt:\n"); 760 | printHexDump(&session->buffer[0], newlen); 761 | 762 | printf("g_content.pkey:\n"); 763 | //printHexDump(&session->reg->pkey[0], 32); 764 | printHexDump(&g_content.pkey[0], 32); 765 | printf("session->in_nonce:\n"); 766 | printHexDump(&session->in_nonce[0], crypto_stream_xor_NONCEBYTES); 767 | #endif 768 | 769 | crypto_stream_xor_init(&session->in_state, &session->in_nonce[0], &session->reg->pkey[0]); 770 | crypto_stream_xor_update(&session->in_state, &tmp[0], &session->buffer[0], newlen); 771 | memcpy(&session->buffer[0], tmp, newlen); 772 | #if DEBUGIO 773 | printf("encrypted:\n"); 774 | printHexDump(&session->buffer[0], newlen); 775 | #endif 776 | } 777 | } 778 | 779 | return 0; 780 | } 781 | 782 | 783 | static void dat_client_handler(int revents, int clientsock); 784 | 785 | 786 | static int loadPKey(uint8_t pkey[32], const char pkey_path[]) 787 | { 788 | struct file pkey_file; 789 | 790 | if (0 != openFile(&pkey_file, pkey_path)) { 791 | return EXIT_FAILURE; 792 | } 793 | 794 | if (pkey_file.size != 32) { 795 | closeFile(&pkey_file); 796 | return EXIT_FAILURE; 797 | } 798 | 799 | memcpy(pkey, pkey_file.mem, 32); 800 | 801 | closeFile(&pkey_file); 802 | 803 | return EXIT_SUCCESS; 804 | } 805 | 806 | static int initRegister(struct Register *reg, const char pkey_path[]) 807 | { 808 | uint8_t pkey[32]; 809 | int rc; 810 | 811 | rc = loadPKey(pkey, pkey_path); 812 | if (rc == EXIT_FAILURE) { 813 | return EXIT_FAILURE; 814 | } 815 | 816 | memcpy(®->pkey, pkey, sizeof(pkey)); 817 | createDiscoveryKey(®->discovery_key[0], pkey); 818 | reg->pkey_path = strdup(pkey_path); 819 | 820 | //printf("discoverykey:\n"); 821 | //printHexDump(®->discovery_key[0], 32); 822 | 823 | return EXIT_SUCCESS; 824 | } 825 | 826 | int loadRegisterPath(const char path[]) 827 | { 828 | char buf[512]; 829 | int rc; 830 | 831 | snprintf(buf, sizeof(buf), "%s/%s", path, ".dat/content.key"); 832 | rc = initRegister(&g_metadata, buf); 833 | if (rc == EXIT_FAILURE) { 834 | return EXIT_FAILURE; 835 | } 836 | //printf("Loaded %s\n", buf); 837 | 838 | snprintf(buf, sizeof(buf), "%s/%s", path, ".dat/metadata.key"); 839 | rc = initRegister(&g_content, buf); 840 | if (rc == EXIT_FAILURE) { 841 | return EXIT_FAILURE; 842 | } 843 | //printf("Loaded %s\n", buf); 844 | 845 | return EXIT_SUCCESS; 846 | } 847 | 848 | int open_connection(const struct sockaddr_storage *addr) 849 | { 850 | socklen_t addrlen; 851 | struct Session *session; 852 | 853 | int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 854 | if (fd < 0) { 855 | printf("socket: %s\n", strerror(errno)); 856 | return EXIT_FAILURE; 857 | } 858 | 859 | addrlen = addr_len(addr); 860 | if (connect(fd, (struct sockaddr*) addr, addrlen) < 0) { 861 | close(fd); 862 | printf("connect: %s\n", strerror(errno)); 863 | return EXIT_FAILURE; 864 | } 865 | 866 | net_set_nonblocking(fd); 867 | 868 | session = addSession(addr, fd, OUTGOING_CONNECTION); 869 | if (!session) { 870 | return EXIT_FAILURE; 871 | } 872 | 873 | net_add_handler(fd, dat_client_handler); 874 | 875 | return EXIT_SUCCESS; 876 | } 877 | 878 | static void dat_client_handler(int revents, int clientsock) 879 | { 880 | struct Session *session; 881 | uint8_t data[1024]; 882 | ssize_t size; 883 | int rc; 884 | 885 | session = findSession(clientsock); 886 | if (!session) { 887 | printf("Cannot find session\n"); 888 | goto abort; 889 | } 890 | 891 | if (revents > 0) { 892 | size = read(clientsock, data, sizeof(data)); 893 | 894 | if (size < 0) { 895 | // Nothing to read now 896 | return; 897 | } 898 | 899 | if (size == 0) { 900 | printf("Remote closed connection\n"); 901 | goto abort; 902 | } 903 | 904 | //printHexDump(data, size); 905 | rc = handle_connection3(session, data, size); 906 | if (rc < 0) { 907 | printf("Parse error => close connection\n"); 908 | goto abort; 909 | } 910 | } 911 | 912 | // Let's also send data 913 | if (!session->out_nonce_send) { 914 | if (session->reg) { 915 | printf("send feed (discoverykey for %s)\n", session->reg->pkey_path); 916 | send_feed(session, &session->reg->discovery_key[0]); 917 | } else { 918 | printf("send feed (content discoverykey)\n"); 919 | send_feed(session, &g_content.discovery_key[0]); 920 | //printf("send metadata discoverykey\n"); 921 | //send_feed(session, &g_metadata.discovery_key[0]); 922 | } 923 | send_handshake(session); 924 | //send_info(session); 925 | //send_have(session); 926 | //send_want(session); 927 | } 928 | 929 | return; 930 | 931 | abort: 932 | close(clientsock); 933 | removeSession(session); 934 | net_remove_handler(clientsock, &dat_client_handler); 935 | } 936 | 937 | static void dat_server_handler(int rc, int serversock) 938 | { 939 | struct sockaddr_storage addr; 940 | struct Session *session; 941 | socklen_t addrlen; 942 | int clientsock; 943 | 944 | if (rc <= 0) { 945 | return; 946 | } 947 | 948 | memset(&addr, 0, sizeof(struct sockaddr_storage)); 949 | 950 | addrlen = sizeof(struct sockaddr_in); 951 | clientsock = accept(serversock, (struct sockaddr *) &addr, &addrlen); 952 | if (clientsock < 0) { 953 | printf("accept(): %s\n", strerror(errno)); 954 | return; 955 | } 956 | 957 | session = addSession(&addr, clientsock, INCOMING_CONNECTION); 958 | 959 | if (session) { 960 | net_add_handler(clientsock, &dat_client_handler); 961 | } else { 962 | close(clientsock); 963 | } 964 | } 965 | 966 | static void unix_signal_handler(int signo) 967 | { 968 | // exit on second stop request 969 | if (is_running == 0) { 970 | exit(1); 971 | } 972 | 973 | is_running = 0; 974 | 975 | printf("Shutting down...\n"); 976 | } 977 | 978 | void unix_signals(void) 979 | { 980 | struct sigaction sig_stop; 981 | struct sigaction sig_term; 982 | 983 | // STRG+C aka SIGINT => Stop the program 984 | sig_stop.sa_handler = unix_signal_handler; 985 | sig_stop.sa_flags = 0; 986 | if ((sigemptyset(&sig_stop.sa_mask) == -1) || (sigaction(SIGINT, &sig_stop, NULL) != 0)) { 987 | printf("Failed to set SIGINT handler: %s\n", strerror(errno)); 988 | exit(1); 989 | } 990 | 991 | // SIGTERM => Stop the program gracefully 992 | sig_term.sa_handler = unix_signal_handler; 993 | sig_term.sa_flags = 0; 994 | if ((sigemptyset(&sig_term.sa_mask) == -1) || (sigaction(SIGTERM, &sig_term, NULL) != 0)) { 995 | printf("Failed to set SIGTERM handler: %s\n", strerror(errno)); 996 | exit(1); 997 | } 998 | } 999 | 1000 | static void cmd_exec(FILE* fp, const char cmd[]) 1001 | { 1002 | char buf[256]; 1003 | struct sockaddr_storage addr = {0}; 1004 | struct Session *session; 1005 | char d; 1006 | int rc; 1007 | 1008 | // insert default 1009 | if (0 == strcmp("connect\n", cmd)) { 1010 | cmd = "connect 127.0.0.1:3282\n"; 1011 | } 1012 | 1013 | if (1 == sscanf(cmd, "connect %255s %c", buf, &d)) { 1014 | rc = addr_parse_full(&addr, buf, "3282", AF_UNSPEC); 1015 | if (rc == 0) { 1016 | rc = open_connection(&addr); 1017 | if (rc == EXIT_FAILURE) { 1018 | fprintf(fp, "Connection failure.\n"); 1019 | } 1020 | } else { 1021 | fprintf(fp, "Invalid address.\n"); 1022 | return; 1023 | } 1024 | } else if (0 == strncmp(cmd, "list", 4)) { 1025 | session = g_sessions; 1026 | if (!session) { 1027 | fprintf(fp, "No sessions\n"); 1028 | } 1029 | while (session) { 1030 | fprintf(fp, "clientaddr: %s\n", str_addr(&session->clientaddr)); 1031 | fprintf(fp, " in_nonce_received: %s\n", session->in_nonce_received ? "yes" : "no"); 1032 | fprintf(fp, " out_nonce_send: %s\n", session->out_nonce_send ? "yes" : "no"); 1033 | session = session->next; 1034 | } 1035 | 1036 | fprintf(fp, "metadata publickey: %s\n", toHex(&g_metadata.pkey[0], 32)); 1037 | fprintf(fp, "metadata discoverykey: %s\n", toHex(&g_metadata.discovery_key[0], 32)); 1038 | fprintf(fp, "content publickey: %s\n", toHex(&g_content.pkey[0], 32)); 1039 | fprintf(fp, "content discoverykey: %s\n", toHex(&g_content.discovery_key[0], 32)); 1040 | } else { 1041 | fprintf(fp, "\n" 1042 | "connect \n" 1043 | "list\n" 1044 | ); 1045 | } 1046 | } 1047 | 1048 | static void cmd_server_handler(int rc, int serversock) 1049 | { 1050 | char request[64]; 1051 | 1052 | if (rc <= 0) { 1053 | return; 1054 | } 1055 | 1056 | if (serversock == STDIN_FILENO) { 1057 | rc = read(serversock, request, sizeof(request)); 1058 | if (rc > 0) { 1059 | request[rc] = '\0'; 1060 | cmd_exec(stdout, request); 1061 | } 1062 | } else { 1063 | close(serversock); 1064 | } 1065 | } 1066 | 1067 | int main(int argc, char *argv[]) 1068 | { 1069 | int sock; 1070 | int rc; 1071 | 1072 | rc = loadRegisterPath("foo"); 1073 | if (rc == EXIT_FAILURE) { 1074 | return 1; 1075 | } 1076 | 1077 | unix_signals(); 1078 | srand(time(NULL)); 1079 | 1080 | sock = net_bind("Server", "127.0.0.1", (argc == 2) ? atoi(argv[1]) : 12345, NULL, IPPROTO_TCP); 1081 | if (sock < 0) { 1082 | return 1; 1083 | } 1084 | 1085 | net_add_handler(sock, dat_server_handler); 1086 | net_add_handler(STDIN_FILENO, cmd_server_handler); 1087 | 1088 | net_loop(); 1089 | net_free(); 1090 | 1091 | return 0; 1092 | } 1093 | -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "utils.h" 17 | 18 | 19 | // Fill buffer with random bytes 20 | int bytes_random(uint8_t buffer[], size_t size) { 21 | int fd; 22 | int rc; 23 | 24 | fd = open("/dev/urandom", O_RDONLY); 25 | if(fd < 0) { 26 | //log_error("Failed to open /dev/urandom"); 27 | exit(1); 28 | } 29 | 30 | rc = read(fd, buffer, size); 31 | 32 | close(fd); 33 | 34 | return rc; 35 | } 36 | 37 | const char *str_addr(const IP *addr) { 38 | static char addrbuf[FULL_ADDSTRLEN + 1]; 39 | char buf[INET6_ADDRSTRLEN + 1]; 40 | const char *fmt; 41 | int port; 42 | 43 | switch (addr->ss_family) { 44 | case AF_INET6: 45 | port = ((IP6 *)addr)->sin6_port; 46 | inet_ntop( AF_INET6, &((IP6 *)addr)->sin6_addr, buf, sizeof(buf) ); 47 | fmt = "[%s]:%d"; 48 | break; 49 | case AF_INET: 50 | port = ((IP4 *)addr)->sin_port; 51 | inet_ntop( AF_INET, &((IP4 *)addr)->sin_addr, buf, sizeof(buf) ); 52 | fmt = "%s:%d"; 53 | break; 54 | default: 55 | return ""; 56 | } 57 | 58 | sprintf(addrbuf, fmt, buf, ntohs(port)); 59 | 60 | return addrbuf; 61 | } 62 | 63 | /* 64 | * Parse/Resolve an IP address. 65 | * The port must be specified separately. 66 | */ 67 | int addr_parse(IP *addr, const char addr_str[], const char port_str[], int af) 68 | { 69 | struct addrinfo hints; 70 | struct addrinfo *info = NULL; 71 | struct addrinfo *p = NULL; 72 | 73 | memset(&hints, '\0', sizeof(struct addrinfo)); 74 | hints.ai_socktype = SOCK_STREAM; 75 | hints.ai_family = af; 76 | 77 | if (getaddrinfo(addr_str, port_str, &hints, &info) != 0) { 78 | return -2; 79 | } 80 | 81 | p = info; 82 | while (p != NULL) { 83 | if(p->ai_family == AF_INET6) { 84 | memcpy(addr, p->ai_addr, sizeof(IP6)); 85 | freeaddrinfo(info); 86 | return 0; 87 | } 88 | if(p->ai_family == AF_INET ) { 89 | memcpy(addr, p->ai_addr, sizeof(IP4)); 90 | freeaddrinfo(info); 91 | return 0; 92 | } 93 | } 94 | 95 | freeaddrinfo(info); 96 | return -3; 97 | } 98 | 99 | int addr_parse_full(IP *addr, const char full_addr_str[], const char default_port[], int af) 100 | { 101 | char addr_buf[256]; 102 | char *addr_beg; 103 | char *addr_tmp; 104 | char *last_colon; 105 | const char *addr_str = NULL; 106 | const char *port_str = NULL; 107 | size_t len; 108 | 109 | len = strlen(full_addr_str); 110 | if (len >= (sizeof(addr_buf) - 1)) { 111 | // address too long 112 | return -1; 113 | } else { 114 | addr_beg = addr_buf; 115 | } 116 | 117 | memset(addr_buf, '\0', sizeof(addr_buf)); 118 | memcpy(addr_buf, full_addr_str, len); 119 | 120 | last_colon = strrchr(addr_buf, ':'); 121 | 122 | if (addr_beg[0] == '[') { 123 | // [] or []: 124 | addr_tmp = strrchr(addr_beg, ']'); 125 | 126 | if (addr_tmp == NULL) { 127 | // broken format 128 | return -1; 129 | } 130 | 131 | *addr_tmp = '\0'; 132 | addr_str = addr_beg + 1; 133 | 134 | if (*(addr_tmp+1) == '\0') { 135 | port_str = default_port; 136 | } else if (*(addr_tmp+1) == ':') { 137 | port_str = addr_tmp + 2; 138 | } else { 139 | // port expected 140 | return -1; 141 | } 142 | } else if (last_colon && last_colon == strchr(addr_buf, ':')) { 143 | // : 144 | addr_tmp = last_colon; 145 | if (addr_tmp) { 146 | *addr_tmp = '\0'; 147 | addr_str = addr_buf; 148 | port_str = addr_tmp+1; 149 | } else { 150 | addr_str = addr_buf; 151 | port_str = default_port; 152 | } 153 | } else { 154 | // 155 | addr_str = addr_buf; 156 | port_str = default_port; 157 | } 158 | 159 | return addr_parse(addr, addr_str, port_str, af); 160 | } 161 | 162 | int addr_port(const IP *addr) { 163 | switch (addr->ss_family) { 164 | case AF_INET: 165 | return ntohs(((IP4 *)addr)->sin_port); 166 | case AF_INET6: 167 | return ntohs(((IP6 *)addr)->sin6_port); 168 | default: 169 | return 0; 170 | } 171 | } 172 | 173 | int addr_len(const IP *addr) { 174 | switch (addr->ss_family) { 175 | case AF_INET: 176 | return sizeof(IP4); 177 | case AF_INET6: 178 | return sizeof(IP6); 179 | default: 180 | return 0; 181 | } 182 | } 183 | 184 | int port_set(IP *addr, uint16_t port) { 185 | switch (addr->ss_family) { 186 | case AF_INET: 187 | ((IP4 *)addr)->sin_port = htons(port); 188 | return 0; 189 | case AF_INET6: 190 | ((IP6 *)addr)->sin6_port = htons(port); 191 | return 0; 192 | default: 193 | return 1; 194 | } 195 | } 196 | 197 | char *bytes_to_base16hex(char dst[], size_t dstsize, const uint8_t src[], size_t srcsize) 198 | { 199 | static const char hexchars[16] = "0123456789abcdef"; 200 | size_t i; 201 | 202 | // + 1 for the '\0' 203 | if (dstsize != 2 * srcsize + 1) { 204 | return NULL; 205 | } 206 | 207 | for (i = 0; i < srcsize; ++i) { 208 | dst[2 * i] = hexchars[src[i] / 16]; 209 | dst[2 * i + 1] = hexchars[src[i] % 16]; 210 | } 211 | 212 | dst[2 * srcsize] = '\0'; 213 | 214 | return dst; 215 | } 216 | 217 | const char *toHex(const uint8_t src[], size_t srcsize) 218 | { 219 | static char buf[65]; 220 | 221 | if (srcsize == 32) 222 | return bytes_to_base16hex(buf, sizeof(buf), src, srcsize); 223 | 224 | return NULL; 225 | } 226 | 227 | void printHexDump(const void *addr, int len) { 228 | int i; 229 | unsigned char buff[17]; 230 | unsigned char *pc = (unsigned char*)addr; 231 | 232 | if (len == 0) { 233 | printf(" ZERO LENGTH\n"); 234 | return; 235 | } 236 | if (len < 0) { 237 | printf(" NEGATIVE LENGTH: %i\n",len); 238 | return; 239 | } 240 | 241 | // Process every byte in the data. 242 | for (i = 0; i < len; i++) { 243 | // Multiple of 16 means new line (with line offset). 244 | 245 | if ((i % 16) == 0) { 246 | // Just don't print ASCII for the zeroth line. 247 | if (i != 0) 248 | printf (" %s\n", buff); 249 | 250 | // Output the offset. 251 | printf (" %04x ", i); 252 | } 253 | 254 | // Now the hex code for the specific character. 255 | printf (" %02x", pc[i]); 256 | 257 | // And store a printable ASCII character for later. 258 | if ((pc[i] < 0x20) || (pc[i] > 0x7e)) 259 | buff[i % 16] = '.'; 260 | else 261 | buff[i % 16] = pc[i]; 262 | buff[(i % 16) + 1] = '\0'; 263 | } 264 | 265 | // Pad out last line if not exactly 16 characters. 266 | while ((i % 16) != 0) { 267 | printf (" "); 268 | i++; 269 | } 270 | 271 | // And print the final ASCII bit. 272 | printf (" %s\n", buff); 273 | } 274 | 275 | int openFile(struct file *file, const char path[]) { 276 | struct stat s = {0}; 277 | char *mem = NULL; 278 | 279 | int fd = open (path, O_RDONLY); 280 | if (fd < 0) { 281 | printf("open %s failed: %s\n", path, strerror (errno)); 282 | goto fail; 283 | } 284 | 285 | int status = fstat (fd, &s); 286 | if (status < 0) { 287 | printf("stat %s failed: %s\n", path, strerror (errno)); 288 | goto fail; 289 | } 290 | 291 | if (s.st_size) { 292 | mem = mmap (0, s.st_size, PROT_READ, MAP_SHARED, fd, 0); 293 | if (mem == MAP_FAILED) { 294 | printf("mmap %s failed: %s\n", path, strerror (errno)); 295 | goto fail; 296 | } 297 | } 298 | 299 | file->path = path; 300 | file->fd = fd; 301 | file->mem = mem; 302 | file->size = s.st_size; 303 | 304 | return 0; 305 | 306 | fail:; 307 | if (mem) { 308 | munmap(mem, s.st_size); 309 | } 310 | close(fd); 311 | return 1; 312 | } 313 | 314 | int closeFile(struct file *file) { 315 | munmap(file->mem, file->size); 316 | close(file->fd); 317 | return 0; 318 | } 319 | 320 | 321 | int bytes_from_base16hex( uint8_t dst[], size_t dstsize, const char src[], size_t srcsize ) { 322 | size_t i; 323 | size_t xv = 0; 324 | 325 | if (dstsize * 2 != srcsize) { 326 | return -1; 327 | } 328 | 329 | for( i = 0; i < srcsize; ++i ) { 330 | const char c = src[i]; 331 | if ( c >= '0' && c <= '9' ) { 332 | xv += c - '0'; 333 | } else if( c >= 'a' && c <= 'f') { 334 | xv += (c - 'a') + 10; 335 | } else { 336 | return -1; 337 | } 338 | 339 | if( i % 2 ) { 340 | dst[i / 2] = xv; 341 | xv = 0; 342 | } else { 343 | xv *= 16; 344 | } 345 | } 346 | 347 | return 0; 348 | } 349 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef _UTILS_H_ 4 | #define _UTILS_H_ 5 | 6 | #include "net.h" 7 | 8 | #define N_ELEMS(x) (sizeof(x) / sizeof(x[0])) 9 | #define MAX(x, y) ((x) >= (y) ? (x) : (y)) 10 | #define MIN(x, y) ((x) <= (y) ? (x) : (y)) 11 | #define FULL_ADDSTRLEN (INET6_ADDRSTRLEN + 8) 12 | 13 | 14 | struct file { 15 | const char *path; 16 | int fd; 17 | char *mem; 18 | size_t size; 19 | }; 20 | 21 | int bytes_random(uint8_t buffer[], size_t size); 22 | 23 | int openFile(struct file *file, const char path[]); 24 | int closeFile(struct file *file); 25 | 26 | const char *str_addr(const IP *addr); 27 | 28 | int port_set(IP *addr, uint16_t port); 29 | int addr_parse(IP *addr, const char addr_str[], const char port_str[], int af); 30 | int addr_parse_full(IP *addr, const char full_addr_str[], const char default_port[], int af); 31 | 32 | int addr_port(const IP *addr); 33 | int addr_len(const IP *addr); 34 | 35 | void printHexDump(const void *addr, int len); 36 | const char *toHex(const uint8_t src[], size_t srcsize); 37 | 38 | int bytes_from_base16hex( uint8_t dst[], size_t dstsize, const char src[], size_t srcsize ); 39 | 40 | #endif // _UTILS_H_ 41 | -------------------------------------------------------------------------------- /varint.c: -------------------------------------------------------------------------------- 1 | 2 | // Source: protobuf-c 3 | // TODO: Need to be replaced 4 | 5 | #include 6 | 7 | #include "varint.h" 8 | 9 | 10 | size_t uint64_size(uint64_t v) 11 | { 12 | uint32_t upper_v = (uint32_t) (v >> 32); 13 | 14 | if (upper_v == 0) { 15 | return uint32_size((uint32_t) v); 16 | } else if (upper_v < (1UL << 3)) { 17 | return 5; 18 | } else if (upper_v < (1UL << 10)) { 19 | return 6; 20 | } else if (upper_v < (1UL << 17)) { 21 | return 7; 22 | } else if (upper_v < (1UL << 24)) { 23 | return 8; 24 | } else if (upper_v < (1UL << 31)) { 25 | return 9; 26 | } else { 27 | return 10; 28 | } 29 | } 30 | 31 | size_t uint32_size(uint32_t v) 32 | { 33 | if (v < (1UL << 7)) { 34 | return 1; 35 | } else if (v < (1UL << 14)) { 36 | return 2; 37 | } else if (v < (1UL << 21)) { 38 | return 3; 39 | } else if (v < (1UL << 28)) { 40 | return 4; 41 | } else { 42 | return 5; 43 | } 44 | } 45 | 46 | size_t uint64_pack(uint64_t value, uint8_t *out) 47 | { 48 | uint32_t hi = (uint32_t) (value >> 32); 49 | uint32_t lo = (uint32_t) value; 50 | unsigned rv; 51 | 52 | if (hi == 0) 53 | return uint32_pack((uint32_t) lo, out); 54 | out[0] = (lo) | 0x80; 55 | out[1] = (lo >> 7) | 0x80; 56 | out[2] = (lo >> 14) | 0x80; 57 | out[3] = (lo >> 21) | 0x80; 58 | if (hi < 8) { 59 | out[4] = (hi << 4) | (lo >> 28); 60 | return 5; 61 | } else { 62 | out[4] = ((hi & 7) << 4) | (lo >> 28) | 0x80; 63 | hi >>= 3; 64 | } 65 | rv = 5; 66 | while (hi >= 128) { 67 | out[rv++] = hi | 0x80; 68 | hi >>= 7; 69 | } 70 | out[rv++] = hi; 71 | return rv; 72 | } 73 | 74 | size_t uint32_pack(uint32_t value, uint8_t *out) 75 | { 76 | unsigned rv = 0; 77 | 78 | if (value >= 0x80) { 79 | out[rv++] = value | 0x80; 80 | value >>= 7; 81 | if (value >= 0x80) { 82 | out[rv++] = value | 0x80; 83 | value >>= 7; 84 | if (value >= 0x80) { 85 | out[rv++] = value | 0x80; 86 | value >>= 7; 87 | if (value >= 0x80) { 88 | out[rv++] = value | 0x80; 89 | value >>= 7; 90 | } 91 | } 92 | } 93 | } 94 | /* assert: value<128 */ 95 | out[rv++] = value; 96 | return rv; 97 | } 98 | 99 | unsigned varint_scan(const uint8_t *data, unsigned len) { 100 | unsigned i; 101 | if (len > 10) { 102 | len = 10; 103 | } 104 | 105 | for (i = 0; i < len; i++) { 106 | if ((data[i] & 0x80) == 0) { 107 | break; 108 | } 109 | } 110 | 111 | if (i == len) { 112 | return 0; 113 | } 114 | 115 | return i + 1; 116 | } 117 | 118 | uint32_t varint_parse_uint32(const uint8_t *data, unsigned len) { 119 | uint32_t rv = data[0] & 0x7f; 120 | if (len > 1) { 121 | rv |= ((uint32_t) (data[1] & 0x7f) << 7); 122 | if (len > 2) { 123 | rv |= ((uint32_t) (data[2] & 0x7f) << 14); 124 | if (len > 3) { 125 | rv |= ((uint32_t) (data[3] & 0x7f) << 21); 126 | if (len > 4) 127 | rv |= ((uint32_t) (data[4]) << 28); 128 | } 129 | } 130 | } 131 | return rv; 132 | } 133 | 134 | uint64_t varint_parse_uint64(const uint8_t *data, unsigned len) { 135 | unsigned shift, i; 136 | uint64_t rv; 137 | 138 | if (len < 5) 139 | return varint_parse_uint32(data, len); 140 | rv = ((uint64_t) (data[0] & 0x7f)) | 141 | ((uint64_t) (data[1] & 0x7f) << 7) | 142 | ((uint64_t) (data[2] & 0x7f) << 14) | 143 | ((uint64_t) (data[3] & 0x7f) << 21); 144 | shift = 28; 145 | for (i = 4; i < len; i++) { 146 | rv |= (((uint64_t) (data[i] & 0x7f)) << shift); 147 | shift += 7; 148 | } 149 | return rv; 150 | } 151 | -------------------------------------------------------------------------------- /varint.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _VARINT_H_ 3 | #define _VARINT_H_ 4 | 5 | #include 6 | 7 | size_t uint64_size(uint64_t v); 8 | size_t uint32_size(uint32_t v); 9 | size_t uint64_pack(uint64_t value, uint8_t *out); 10 | size_t uint32_pack(uint32_t value, uint8_t *out); 11 | unsigned varint_scan(const uint8_t *data, unsigned len); 12 | uint32_t varint_parse_uint32(const uint8_t *data, unsigned len); 13 | uint64_t varint_parse_uint64(const uint8_t *data, unsigned len); 14 | 15 | #endif // _VARINT_H_ 16 | --------------------------------------------------------------------------------