|
|
state.c - dedup - deduplicating backup program |
|
|
 |
git clone git://bitreich.org/dedup/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/dedup/ (git://bitreich.org) |
|
|
 |
Log |
|
|
 |
Files |
|
|
 |
Refs |
|
|
 |
Tags |
|
|
 |
README |
|
|
 |
LICENSE |
|
|
|
--- |
|
|
|
state.c (5150B) |
|
|
|
--- |
|
|
|
1 /* Routines to read and write repository parameters */ |
|
|
|
2 #include <assert.h> |
|
|
|
3 #include <errno.h> |
|
|
|
4 #include <stdint.h> |
|
|
|
5 #include <stdio.h> |
|
|
|
6 #include <string.h> |
|
|
|
7 #include <strings.h> |
|
|
|
8 |
|
|
|
9 #include <sodium.h> |
|
|
|
10 |
|
|
|
11 #include "config.h" |
|
|
|
12 #include "misc.h" |
|
|
|
13 #include "state.h" |
|
|
|
14 |
|
|
|
15 #define VMIN 0 |
|
|
|
16 #define VMAJ 1 |
|
|
|
17 #define VMINMASK 0xff |
|
|
|
18 #define VMAJSHIFT 8 |
|
|
|
19 #define VMAJMASK 0xff |
|
|
|
20 |
|
|
|
21 #define CALGOSHIFT 16 |
|
|
|
22 #define CALGOMASK 0x7 |
|
|
|
23 #define CNONETYPE 0 |
|
|
|
24 #define CSNAPPYTYPE 1 |
|
|
|
25 #define CLZ4TYPE 2 |
|
|
|
26 |
|
|
|
27 #define EALGOSHIFT 19 |
|
|
|
28 #define EALGOMASK 0x7 |
|
|
|
29 #define ENONETYPE 0 |
|
|
|
30 #define ECHACHATYPE 1 |
|
|
|
31 |
|
|
|
32 #define NONCESIZE crypto_aead_xchacha20poly1305_ietf_NPUBBYTES |
|
|
|
33 #define MSEEDSIZE 4 |
|
|
|
34 #define CSEEDSIZE (MSEEDSIZE + crypto_aead_xchacha20poly1305_ietf_ABYTES) |
|
|
|
35 #define SHDRSIZE (8 + NONCESIZE + CSEEDSIZE) |
|
|
|
36 |
|
|
|
37 /* misc helpers */ |
|
|
|
38 extern int pack(unsigned char *, char *, ...); |
|
|
|
39 extern int unpack(unsigned char *, char *, ...); |
|
|
|
40 |
|
|
|
41 struct shdr { |
|
|
|
42 uint64_t flags; |
|
|
|
43 unsigned char nonce[NONCESIZE]; |
|
|
|
44 unsigned char seed[CSEEDSIZE]; |
|
|
|
45 }; |
|
|
|
46 |
|
|
|
47 /* Unpack state header */ |
|
|
|
48 static int |
|
|
|
49 unpackshdr(unsigned char *buf, struct shdr *shdr) |
|
|
|
50 { |
|
|
|
51 char fmt[BUFSIZ]; |
|
|
|
52 int n; |
|
|
|
53 |
|
|
|
54 snprintf(fmt, sizeof(fmt), "q'%d'%d", NONCESIZE, CSEEDSIZE); |
|
|
|
55 n = unpack(buf, fmt, |
|
|
|
56 &shdr->flags, |
|
|
|
57 shdr->nonce, |
|
|
|
58 shdr->seed); |
|
|
|
59 assert(n == SHDRSIZE); |
|
|
|
60 return n; |
|
|
|
61 } |
|
|
|
62 |
|
|
|
63 /* Pack state header */ |
|
|
|
64 static int |
|
|
|
65 packshdr(unsigned char *buf, struct shdr *shdr) |
|
|
|
66 { |
|
|
|
67 char fmt[BUFSIZ]; |
|
|
|
68 int n; |
|
|
|
69 |
|
|
|
70 snprintf(fmt, sizeof(fmt), "q'%d'%d", NONCESIZE, CSEEDSIZE); |
|
|
|
71 n = pack(buf, fmt, |
|
|
|
72 shdr->flags, |
|
|
|
73 shdr->nonce, |
|
|
|
74 shdr->seed); |
|
|
|
75 assert(n == SHDRSIZE); |
|
|
|
76 return n; |
|
|
|
77 } |
|
|
|
78 |
|
|
|
79 int |
|
|
|
80 writestate(int fd, struct param *par) |
|
|
|
81 { |
|
|
|
82 unsigned char buf[SHDRSIZE]; |
|
|
|
83 struct shdr shdr; |
|
|
|
84 |
|
|
|
85 if (sodium_init() < 0) { |
|
|
|
86 seterr("sodium_init: failed"); |
|
|
|
87 return -1; |
|
|
|
88 } |
|
|
|
89 |
|
|
|
90 /* Set version */ |
|
|
|
91 shdr.flags = (VMAJ << VMAJSHIFT) | VMIN; |
|
|
|
92 |
|
|
|
93 /* Set compression type */ |
|
|
|
94 if (strcasecmp(par->calgo, "none") == 0) { |
|
|
|
95 shdr.flags |= CNONETYPE << CALGOSHIFT; |
|
|
|
96 } else if (strcasecmp(par->calgo, "snappy") == 0) { |
|
|
|
97 shdr.flags |= CSNAPPYTYPE << CALGOSHIFT; |
|
|
|
98 } else if (strcasecmp(par->calgo, "lz4") == 0) { |
|
|
|
99 shdr.flags |= CLZ4TYPE << CALGOSHIFT; |
|
|
|
100 } else { |
|
|
|
101 seterr("invalid compression type: %s", par->calgo); |
|
|
|
102 return -1; |
|
|
|
103 } |
|
|
|
104 |
|
|
|
105 /* Clear seed + authentication tag */ |
|
|
|
106 memset(shdr.seed, 0, sizeof(shdr.seed)); |
|
|
|
107 |
|
|
|
108 /* Pack seed */ |
|
|
|
109 shdr.seed[0] = par->seed; |
|
|
|
110 shdr.seed[1] = par->seed >> 8; |
|
|
|
111 shdr.seed[2] = par->seed >> 16; |
|
|
|
112 shdr.seed[3] = par->seed >> 24; |
|
|
|
113 |
|
|
|
114 /* Set encryption type */ |
|
|
|
115 if (strcasecmp(par->ealgo, "none") == 0) { |
|
|
|
116 shdr.flags |= ENONETYPE << EALGOSHIFT; |
|
|
|
117 memset(shdr.nonce, 0, sizeof(shdr.nonce)); |
|
|
|
118 } else if (strcasecmp(par->ealgo, "XChaCha20-Poly1305") == 0) { |
|
|
|
119 unsigned long long elen; |
|
|
|
120 |
|
|
|
121 shdr.flags |= ECHACHATYPE << EALGOSHIFT; |
|
|
|
122 randombytes_buf(shdr.nonce, sizeof(shdr.nonce)); |
|
|
|
123 crypto_aead_xchacha20poly1305_ietf_encrypt(shdr.seed, &elen, |
|
|
|
124 shdr.seed, MSEEDSIZE, |
|
|
|
125 NULL, 0, NULL, |
|
|
|
126 shdr.nonce, par->key); |
|
|
|
127 assert(elen == CSEEDSIZE); |
|
|
|
128 } else { |
|
|
|
129 seterr("invalid encryption type: %s", par->ealgo); |
|
|
|
130 return -1; |
|
|
|
131 } |
|
|
|
132 |
|
|
|
133 packshdr(buf, &shdr); |
|
|
|
134 if (xwrite(fd, buf, SHDRSIZE) != SHDRSIZE) { |
|
|
|
135 seterr("failed to write state header: %s", strerror(errno)); |
|
|
|
136 return -1; |
|
|
|
137 } |
|
|
|
138 return 0; |
|
|
|
139 } |
|
|
|
140 |
|
|
|
141 int |
|
|
|
142 readstate(int fd, struct param *par) |
|
|
|
143 { |
|
|
|
144 unsigned char buf[SHDRSIZE]; |
|
|
|
145 struct shdr shdr; |
|
|
|
146 unsigned long long dlen; |
|
|
|
147 int algo; |
|
|
|
148 |
|
|
|
149 if (sodium_init() < 0) { |
|
|
|
150 seterr("sodium_init: failed"); |
|
|
|
151 return -1; |
|
|
|
152 } |
|
|
|
153 |
|
|
|
154 if (xread(fd, buf, SHDRSIZE) != SHDRSIZE) { |
|
|
|
155 seterr("failed to read state header: %s", strerror(errno)); |
|
|
|
156 return -1; |
|
|
|
157 } |
|
|
|
158 unpackshdr(buf, &shdr); |
|
|
|
159 |
|
|
|
160 /* If the major version is different, the format is incompatible */ |
|
|
|
161 if (((shdr.flags >> VMAJSHIFT) & VMAJMASK) != VMAJ) { |
|
|
|
162 seterr("state header version mismatch"); |
|
|
|
163 return -1; |
|
|
|
164 } |
|
|
|
165 |
|
|
|
166 /* Populate param compression algo */ |
|
|
|
167 algo = (shdr.flags >> CALGOSHIFT) & CALGOMASK; |
|
|
|
168 switch (algo) { |
|
|
|
169 case CNONETYPE: |
|
|
|
170 par->calgo = "none"; |
|
|
|
171 break; |
|
|
|
172 case CSNAPPYTYPE: |
|
|
|
173 par->calgo = "snappy"; |
|
|
|
174 break; |
|
|
|
175 case CLZ4TYPE: |
|
|
|
176 par->calgo = "lz4"; |
|
|
|
177 break; |
|
|
|
178 default: |
|
|
|
179 seterr("invalid compression type: %d", algo); |
|
|
|
180 return -1; |
|
|
|
181 } |
|
|
|
182 |
|
|
|
183 /* Populate param encryption algo */ |
|
|
|
184 algo = (shdr.flags >> EALGOSHIFT) & EALGOMASK; |
|
|
|
185 switch (algo) { |
|
|
|
186 case ENONETYPE: |
|
|
|
187 par->ealgo = "none"; |
|
|
|
188 break; |
|
|
|
189 case ECHACHATYPE: |
|
|
|
190 par->ealgo = "XChaCha20-Poly1305"; |
|
|
|
191 if (crypto_aead_xchacha20poly1305_ietf_decrypt(shdr.seed, &dlen, |
|
|
|
192 NULL, |
|
|
|
193 shdr.seed, CSEEDSIZE, |
|
|
|
194 NULL, 0, |
|
|
|
195 shdr.nonce, par->key) < 0) { |
|
|
|
196 seterr("authentication failed"); |
|
|
|
197 return -1; |
|
|
|
198 } |
|
|
|
199 assert(dlen == MSEEDSIZE); |
|
|
|
200 break; |
|
|
|
201 default: |
|
|
|
202 seterr("invalid encryption type: %d", algo); |
|
|
|
203 return -1; |
|
|
|
204 } |
|
|
|
205 |
|
|
|
206 /* Unpack seed */ |
|
|
|
207 par->seed = (uint32_t)shdr.seed[0]; |
|
|
|
208 par->seed |= (uint32_t)shdr.seed[1] << 8; |
|
|
|
209 par->seed |= (uint32_t)shdr.seed[2] << 16; |
|
|
|
210 par->seed |= (uint32_t)shdr.seed[3] << 24; |
|
|
|
211 |
|
|
|
212 return 0; |
|
|
|
213 } |
|