dedup

deduplicating backup program
git clone git://git.2f30.org/dedup.git
Log | Files | Refs | README | LICENSE

bencrypt.c (7144B)


      1 /* Encryption layer implementation */
      2 #include <sys/types.h>
      3 #include <sys/stat.h>
      4 
      5 #include <assert.h>
      6 #include <fcntl.h>
      7 #include <stdint.h>
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <string.h>
     11 #include <strings.h>
     12 #include <unistd.h>
     13 
     14 #include <sodium.h>
     15 
     16 #include "block.h"
     17 #include "config.h"
     18 #include "misc.h"
     19 #include "state.h"
     20 
     21 extern struct param param;
     22 
     23 #define EDNONETYPE	0x300
     24 #define EDCHACHATYPE	0x301
     25 #define NONCESIZE	crypto_aead_xchacha20poly1305_ietf_NPUBBYTES
     26 #define EDSIZE		(8 + 8 + NONCESIZE)
     27 
     28 extern int pack(unsigned char *, char *, ...);
     29 extern int unpack(unsigned char *, char *, ...);
     30 
     31 static int becreat(struct bctx *bctx, char *path, int mode);
     32 static int beopen(struct bctx *bctx, char *path, int flags, int mode);
     33 static int beput(struct bctx *bctx, void *buf, size_t n, unsigned char *md);
     34 static int beget(struct bctx *bctx, unsigned char *md, void *buf, size_t *n);
     35 static int berm(struct bctx *bctx, unsigned char *md);
     36 static int begc(struct bctx *bctx);
     37 static int besync(struct bctx *bctx);
     38 static int beclose(struct bctx *bctx);
     39 
     40 static struct bops bops = {
     41 	.creat = becreat,
     42 	.open = beopen,
     43 	.put = beput,
     44 	.get = beget,
     45 	.rm = berm,
     46 	.gc = begc,
     47 	.sync = besync,
     48 	.close = beclose,
     49 };
     50 
     51 /* Encryption layer context */
     52 struct ectx {
     53 	int type;		/* encryption algorithm type for new blocks */
     54 };
     55 
     56 /* Encryption descriptor */
     57 struct ed {
     58 	uint16_t type;			/* encryption algorithm type */
     59 	unsigned char reserved[6];	/* should be set to 0 when writing */
     60 	uint64_t size;			/* size of encrypted block */
     61 	unsigned char nonce[NONCESIZE];	/* unpredictable nonce used when encrypting */
     62 };
     63 
     64 /* Unpack encryption descriptor */
     65 static int
     66 unpacked(unsigned char *buf, struct ed *ed)
     67 {
     68 	char fmt[BUFSIZ];
     69 	int n;
     70 
     71 	snprintf(fmt, sizeof(fmt), "s'6q'%d", NONCESIZE);
     72 	n = unpack(buf, fmt,
     73 	           &ed->type,
     74 	           ed->reserved,
     75 	           &ed->size,
     76 	           ed->nonce);
     77 
     78 	assert(n == EDSIZE);
     79 	return n;
     80 }
     81 
     82 /* Pack encryption descriptor */
     83 static int
     84 packed(unsigned char *buf, struct ed *ed)
     85 {
     86 	char fmt[BUFSIZ];
     87 	int n;
     88 
     89 	snprintf(fmt, sizeof(fmt), "s'6q'%d", NONCESIZE);
     90 	n = pack(buf, fmt,
     91 	         ed->type,
     92 	         ed->reserved,
     93 	         ed->size,
     94 	         ed->nonce);
     95 
     96 	assert(n == EDSIZE);
     97 	return n;
     98 }
     99 
    100 static int
    101 becreat(struct bctx *bctx, char *path, int mode)
    102 {
    103 	struct ectx *ectx;
    104 	int type;
    105 
    106 	/* Determine algorithm type */
    107 	if (strcasecmp(param.ealgo, "none") == 0) {
    108 		type = EDNONETYPE;
    109 	} else if (strcasecmp(param.ealgo, "XChaCha20-Poly1305") == 0) {
    110 		type = EDCHACHATYPE;
    111 	} else {
    112 		seterr("invalid encryption type: %s", param.ealgo);
    113 		return -1;
    114 	}
    115 
    116 	/* Ensure a key has been provided if caller requested encryption */
    117 	if (type != EDNONETYPE && !param.keyloaded) {
    118 		seterr("expected encryption key");
    119 		return -1;
    120 	}
    121 
    122 	if (sodium_init() < 0) {
    123 		seterr("sodium_init: failed");
    124 		return -1;
    125 	}
    126 
    127 	bctx->ectx = calloc(1, sizeof(struct ectx));
    128 	if (bctx->ectx == NULL) {
    129 		seterr("calloc: out of memory");
    130 		return -1;
    131 	}
    132 	ectx = bctx->ectx;
    133 	ectx->type = type;
    134 
    135 	if (bstorageops()->creat(bctx, path, mode) < 0) {
    136 		free(ectx);
    137 		return -1;
    138 	}
    139 	return 0;
    140 }
    141 
    142 static int
    143 beopen(struct bctx *bctx, char *path, int flags, int mode)
    144 {
    145 	struct ectx *ectx;
    146 	int type;
    147 
    148 	/* Determine algorithm type */
    149 	if (strcasecmp(param.ealgo, "none") == 0) {
    150 		type = EDNONETYPE;
    151 	} else if (strcasecmp(param.ealgo, "XChaCha20-Poly1305") == 0) {
    152 		type = EDCHACHATYPE;
    153 	} else {
    154 		seterr("invalid encryption type: %s", param.ealgo);
    155 		return -1;
    156 	}
    157 
    158 	/* Ensure a key has been provided if caller requested encryption */
    159 	if (type != EDNONETYPE && !param.keyloaded) {
    160 		seterr("expected encryption key");
    161 		return -1;
    162 	}
    163 
    164 	if (sodium_init() < 0) {
    165 		seterr("sodium_init: failed");
    166 		return -1;
    167 	}
    168 
    169 	bctx->ectx = calloc(1, sizeof(struct ectx));
    170 	if (bctx->ectx == NULL) {
    171 		seterr("calloc: out of memory");
    172 		return -1;
    173 	}
    174 	ectx = bctx->ectx;
    175 	ectx->type = type;
    176 
    177 	if (bstorageops()->open(bctx, path, flags, mode) < 0) {
    178 		free(ectx);
    179 		return -1;
    180 	}
    181 	return 0;
    182 }
    183 
    184 static int
    185 beput(struct bctx *bctx, void *buf, size_t n, unsigned char *md)
    186 {
    187 	struct ectx *ectx;
    188 	struct ed ed;
    189 	unsigned char *ebuf;
    190 	unsigned long long elen;
    191 	size_t en;
    192 
    193 	/* Calculate size of encrypted block */
    194 	ectx = bctx->ectx;
    195 	switch (ectx->type) {
    196 	case EDNONETYPE:
    197 		en = n;
    198 		break;
    199 	case EDCHACHATYPE:
    200 		en = n + crypto_aead_xchacha20poly1305_ietf_ABYTES;
    201 		break;
    202 	}
    203 
    204 	ebuf = malloc(EDSIZE + en);
    205 	if (ebuf == NULL) {
    206 		seterr("malloc: out of memory");
    207 		return -1;
    208 	}
    209 
    210 	/* Prepare encryption descriptor */
    211 	ed.type = ectx->type;
    212 	memset(ed.reserved, 0, sizeof(ed.reserved));
    213 	ed.size = en;
    214 
    215 	/* Fill nonce buffer */
    216 	switch (ectx->type) {
    217 	case EDNONETYPE:
    218 		memset(ed.nonce, 0, sizeof(ed.nonce));
    219 		break;
    220 	case EDCHACHATYPE:
    221 		randombytes_buf(ed.nonce, sizeof(ed.nonce));
    222 		break;
    223 	}
    224 
    225 	/* Prepend encryption descriptor */
    226 	packed(ebuf, &ed);
    227 
    228 	/* Encrypt block */
    229 	switch (ectx->type) {
    230 	case EDNONETYPE:
    231 		memcpy(&ebuf[EDSIZE], buf, en);
    232 		break;
    233 	case EDCHACHATYPE:
    234 		crypto_aead_xchacha20poly1305_ietf_encrypt(&ebuf[EDSIZE], &elen,
    235 		                                           buf, n, ebuf, EDSIZE, NULL,
    236 		                                           ed.nonce, param.key);
    237 		assert(elen == en);
    238 		break;
    239 	}
    240 
    241 	if (bstorageops()->put(bctx, ebuf, EDSIZE + en, md) < 0) {
    242 		free(ebuf);
    243 		return -1;
    244 	}
    245 
    246 	free(ebuf);
    247 	return ed.size;
    248 }
    249 
    250 static int
    251 beget(struct bctx *bctx, unsigned char *md, void *buf, size_t *n)
    252 {
    253 	struct ed ed;
    254 	struct ectx *ectx;
    255 	unsigned char *ebuf;
    256 	unsigned long long dlen;
    257 	size_t dn, size;
    258 
    259 	/* Calculate maximum size of encrypted block */
    260 	size = EDSIZE + *n + crypto_aead_xchacha20poly1305_ietf_ABYTES;
    261 
    262 	ebuf = malloc(size);
    263 	if (ebuf == NULL) {
    264 		seterr("malloc: out of memory");
    265 		return -1;
    266 	}
    267 
    268 	if (bstorageops()->get(bctx, md, ebuf, &size) < 0) {
    269 		free(ebuf);
    270 		return -1;
    271 	}
    272 
    273 	unpacked(ebuf, &ed);
    274 
    275 	/* Decrypt block */
    276 	ectx = bctx->ectx;
    277 	switch (ed.type) {
    278 	case EDNONETYPE:
    279 		dn = ed.size;
    280 		if (*n < dn) {
    281 			free(ebuf);
    282 			seterr("buffer too small");
    283 			return -1;
    284 		}
    285 		memcpy(buf, &ebuf[EDSIZE], dn);
    286 		break;
    287 	case EDCHACHATYPE:
    288 		dn = ed.size - crypto_aead_xchacha20poly1305_ietf_ABYTES;
    289 		if (*n < dn) {
    290 			free(ebuf);
    291 			seterr("buffer too small");
    292 			return -1;
    293 		}
    294 
    295 		if (crypto_aead_xchacha20poly1305_ietf_decrypt(buf, &dlen,
    296 		                                               NULL,
    297 		                                               &ebuf[EDSIZE], ed.size,
    298 		                                               ebuf, EDSIZE,
    299 		                                               ed.nonce, param.key) < 0) {
    300 			free(ebuf);
    301 			seterr("authentication failed");
    302 			return -1;
    303 		}
    304 
    305 		assert(dn == dlen);
    306 		break;
    307 	}
    308 
    309 	free(ebuf);
    310 	*n = dn;
    311 	return 0;
    312 }
    313 
    314 static int
    315 berm(struct bctx *bctx, unsigned char *md)
    316 {
    317 	return bstorageops()->rm(bctx, md);
    318 }
    319 
    320 static int
    321 begc(struct bctx *bctx)
    322 {
    323 	return bstorageops()->gc(bctx);
    324 }
    325 
    326 static int
    327 besync(struct bctx *bctx)
    328 {
    329 	return bstorageops()->sync(bctx);
    330 }
    331 
    332 static int
    333 beclose(struct bctx *bctx)
    334 {
    335 	struct ectx *ectx = bctx->ectx;
    336 
    337 	free(ectx);
    338 	return bstorageops()->close(bctx);
    339 }
    340 
    341 struct bops *
    342 bencryptops(void)
    343 {
    344 	return &bops;
    345 }