summaryrefslogtreecommitdiff
path: root/crypto.h
blob: 729bbf52f6e0017d4ddba9c74ac66192faafdd6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#pragma once

/* WARNING: none of these functions is reentrant because all use the
   same scratch buffer */

#include <fcntl.h>
#include <strings.h>

#include "nacl/crypto_box.h"

#include "common.h"

/* scratchpad for crypto operations */
byte crypto_buf[MAXBUFLEN]; 

char *key_path(char *task, char *type) {
  char *base = getenv("HBBP_KEYDIR"),
    *res = (char*) crypto_buf;
  if (!base) base = "/etc/hbbp/keys";
  if ((unsigned) snprintf(res, MAXBUFLEN, "%s/%s/%s", base, task, type)
      > MAXBUFLEN)
    return NULL;
  return res;  
}

int key_load(char *task, char *type, byte *key, int key_len) {
  int fd = open(key_path(task, type), O_RDONLY);
  if (fd == -1) /* no specific key? -> try default */
    fd = open(key_path("default", type), O_RDONLY);
  if (fd == -1) return 0;
  if (read(fd, key, key_len) != key_len) {
    fprintf(stderr, "invalid key %s\n", crypto_buf);
    return 0;
  }
  ENP(close(fd), "close");
  return 1;
}

/* return error msg or null on sucess */
char* encipher(char *task, byte *data, int *len) {
  byte key_priv[crypto_box_SECRETKEYBYTES],
       key_pub [crypto_box_PUBLICKEYBYTES];
  switch(key_load(task, "send.priv", key_priv, crypto_box_SECRETKEYBYTES)
       + key_load(task, "recv.pub",  key_pub,  crypto_box_PUBLICKEYBYTES)) {
  case 0: return NULL; /* no keys -> no encryption required */
  case 1: return "missing key";
  }

  /* copy data to scratch buffer */
  if ((*len + crypto_box_ZEROBYTES > MAXBUFLEN)
   || (*len + crypto_box_ZEROBYTES + crypto_box_NONCEBYTES + strlen(task) + 1 > MAXBUFLEN))
    return "payload to large (no space left for crypto)";
  bzero (crypto_buf, crypto_box_ZEROBYTES);
  memcpy(crypto_buf + crypto_box_ZEROBYTES, data, *len);

  /* encrypt */
  byte *nonce = data,
       *cdata = data + crypto_box_NONCEBYTES;
  memset(nonce, 42, crypto_box_NONCEBYTES); /* URGENT TODO: random nonce */
  if (crypto_box(cdata, crypto_buf, *len + crypto_box_ZEROBYTES, nonce, key_pub, key_priv) != 0) return "oooh";
  memmove(data + crypto_box_NONCEBYTES,
	  data + crypto_box_NONCEBYTES + crypto_box_BOXZEROBYTES,
	  *len + crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES);
  *len += crypto_box_NONCEBYTES + crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES;
  return NULL;
}

int decipher(char *task, byte **data, int *len) {
  byte key_priv[crypto_box_SECRETKEYBYTES],
       key_pub [crypto_box_PUBLICKEYBYTES];
  switch(key_load(task, "recv.priv", key_priv, crypto_box_SECRETKEYBYTES)
       + key_load(task, "send.pub",  key_pub,  crypto_box_PUBLICKEYBYTES)) {
  case 0: return 1; /* no keys -> no decryption required */
  case 1: return 0; /* one missing key -> error */
  }

  byte nonce[crypto_box_NONCEBYTES];
  memcpy(nonce, *data, crypto_box_NONCEBYTES);
  byte *cdata   = *data + (crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES);
  int cdata_len = *len  - (crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES);
  if (cdata_len < crypto_box_BOXZEROBYTES) return 0;
  bzero(cdata, crypto_box_BOXZEROBYTES);
  if (crypto_box_open(crypto_buf, cdata, cdata_len, nonce,
		      key_pub, key_priv) == -1) return 0;

  *data = crypto_buf + crypto_box_ZEROBYTES;
  *len = cdata_len - crypto_box_ZEROBYTES;
  return 1;
}
contact: Jan Huwald // Impressum