├── 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 | [](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 |
--------------------------------------------------------------------------------