static void choose_enc(Enc *enc, char *client, char *server) { char *name = match_list(client, server, NULL); if (name == NULL) fatal("no matching cipher found: client %s server %s", client, server); if ((enc->cipher = cipher_by_name(name)) == NULL) fatal("matching cipher is not supported: %s", name); enc->name = name; enc->enabled = 0; enc->iv = NULL; enc->key = NULL; enc->key_len = cipher_keylen(enc->cipher); enc->block_size = cipher_blocksize(enc->cipher); }
static int choose_enc(Enc *enc, char *client, char *server) { char *name = match_list(client, server, NULL); if (name == NULL) return SSH_ERR_NO_CIPHER_ALG_MATCH; if ((enc->cipher = cipher_by_name(name)) == NULL) return SSH_ERR_INTERNAL_ERROR; enc->name = name; enc->enabled = 0; enc->iv = NULL; enc->key = NULL; enc->key_len = cipher_keylen(enc->cipher); enc->block_size = cipher_blocksize(enc->cipher); return 0; }
int sshkey_xmss_encrypt_state(const struct sshkey *k, struct sshbuf *b, struct sshbuf **retp) { struct ssh_xmss_state *state = k->xmss_state; struct sshbuf *encrypted = NULL, *encoded = NULL, *padded = NULL; struct sshcipher_ctx *ciphercontext = NULL; const struct sshcipher *cipher; u_char *cp, *key, *iv = NULL; size_t i, keylen, ivlen, blocksize, authlen, encrypted_len, aadlen; int r = SSH_ERR_INTERNAL_ERROR; if (retp != NULL) *retp = NULL; if (state == NULL || state->enc_keyiv == NULL || state->enc_ciphername == NULL) return SSH_ERR_INTERNAL_ERROR; if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { r = SSH_ERR_INTERNAL_ERROR; goto out; } blocksize = cipher_blocksize(cipher); keylen = cipher_keylen(cipher); ivlen = cipher_ivlen(cipher); authlen = cipher_authlen(cipher); if (state->enc_keyiv_len != keylen + ivlen) { r = SSH_ERR_INVALID_FORMAT; goto out; } key = state->enc_keyiv; if ((encrypted = sshbuf_new()) == NULL || (encoded = sshbuf_new()) == NULL || (padded = sshbuf_new()) == NULL || (iv = malloc(ivlen)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } /* replace first 4 bytes of IV with index to ensure uniqueness */ memcpy(iv, key + keylen, ivlen); POKE_U32(iv, state->idx); if ((r = sshbuf_put(encoded, XMSS_MAGIC, sizeof(XMSS_MAGIC))) != 0 || (r = sshbuf_put_u32(encoded, state->idx)) != 0) goto out; /* padded state will be encrypted */ if ((r = sshbuf_putb(padded, b)) != 0) goto out; i = 0; while (sshbuf_len(padded) % blocksize) { if ((r = sshbuf_put_u8(padded, ++i & 0xff)) != 0) goto out; } encrypted_len = sshbuf_len(padded); /* header including the length of state is used as AAD */ if ((r = sshbuf_put_u32(encoded, encrypted_len)) != 0) goto out; aadlen = sshbuf_len(encoded); /* concat header and state */ if ((r = sshbuf_putb(encoded, padded)) != 0) goto out; /* reserve space for encryption of encoded data plus auth tag */ /* encrypt at offset addlen */ if ((r = sshbuf_reserve(encrypted, encrypted_len + aadlen + authlen, &cp)) != 0 || (r = cipher_init(&ciphercontext, cipher, key, keylen, iv, ivlen, 1)) != 0 || (r = cipher_crypt(ciphercontext, 0, cp, sshbuf_ptr(encoded), encrypted_len, aadlen, authlen)) != 0) goto out; /* success */ r = 0; out: if (retp != NULL) { *retp = encrypted; encrypted = NULL; } sshbuf_free(padded); sshbuf_free(encoded); sshbuf_free(encrypted); cipher_free(ciphercontext); free(iv); return r; }
int sshkey_xmss_decrypt_state(const struct sshkey *k, struct sshbuf *encoded, struct sshbuf **retp) { struct ssh_xmss_state *state = k->xmss_state; struct sshbuf *copy = NULL, *decrypted = NULL; struct sshcipher_ctx *ciphercontext = NULL; const struct sshcipher *cipher = NULL; u_char *key, *iv = NULL, *dp; size_t keylen, ivlen, authlen, aadlen; u_int blocksize, encrypted_len, index; int r = SSH_ERR_INTERNAL_ERROR; if (retp != NULL) *retp = NULL; if (state == NULL || state->enc_keyiv == NULL || state->enc_ciphername == NULL) return SSH_ERR_INTERNAL_ERROR; if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { r = SSH_ERR_INVALID_FORMAT; goto out; } blocksize = cipher_blocksize(cipher); keylen = cipher_keylen(cipher); ivlen = cipher_ivlen(cipher); authlen = cipher_authlen(cipher); if (state->enc_keyiv_len != keylen + ivlen) { r = SSH_ERR_INTERNAL_ERROR; goto out; } key = state->enc_keyiv; if ((copy = sshbuf_fromb(encoded)) == NULL || (decrypted = sshbuf_new()) == NULL || (iv = malloc(ivlen)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } /* check magic */ if (sshbuf_len(encoded) < sizeof(XMSS_MAGIC) || memcmp(sshbuf_ptr(encoded), XMSS_MAGIC, sizeof(XMSS_MAGIC))) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* parse public portion */ if ((r = sshbuf_consume(encoded, sizeof(XMSS_MAGIC))) != 0 || (r = sshbuf_get_u32(encoded, &index)) != 0 || (r = sshbuf_get_u32(encoded, &encrypted_len)) != 0) goto out; /* check size of encrypted key blob */ if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* check that an appropriate amount of auth data is present */ if (sshbuf_len(encoded) < encrypted_len + authlen) { r = SSH_ERR_INVALID_FORMAT; goto out; } aadlen = sshbuf_len(copy) - sshbuf_len(encoded); /* replace first 4 bytes of IV with index to ensure uniqueness */ memcpy(iv, key + keylen, ivlen); POKE_U32(iv, index); /* decrypt private state of key */ if ((r = sshbuf_reserve(decrypted, aadlen + encrypted_len, &dp)) != 0 || (r = cipher_init(&ciphercontext, cipher, key, keylen, iv, ivlen, 0)) != 0 || (r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(copy), encrypted_len, aadlen, authlen)) != 0) goto out; /* there should be no trailing data */ if ((r = sshbuf_consume(encoded, encrypted_len + authlen)) != 0) goto out; if (sshbuf_len(encoded) != 0) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* remove AAD */ if ((r = sshbuf_consume(decrypted, aadlen)) != 0) goto out; /* XXX encrypted includes unchecked padding */ /* success */ r = 0; if (retp != NULL) { *retp = decrypted; decrypted = NULL; } out: cipher_free(ciphercontext); sshbuf_free(copy); sshbuf_free(decrypted); free(iv); return r; }
int ENTRY_NAME(int argc, const char* argv[]) { const char **p = alloca(argc * sizeof(char*)); struct master_config config; char* keybuf; memcpy(p, argv + 1, (argc - 1) * sizeof(char*)); p[argc - 1] = 0; if (--argc == 0) { fprintf(stderr, "Usage:\n"); fprintf(stderr, "\tmultex --dev <name> --interface <name> \n"); return 2; } config.interfaces.next = &config.interfaces; config.sessions.next = &config.sessions; config.endpoints.next = &config.endpoints; config.rendpoints.next = &config.rendpoints; config.port = 1389; config.event_base = event_base_new(); config.tracker = tracker_create(config.event_base, &config, (tracker_callback_t)tracker_callback); if (config.tracker == 0) { return 1; } config.cipher = cipher_bf(); config.cipher_keysize = cipher_keysize(config.cipher); config.cipher_size = cipher_blocksize(config.cipher); keybuf = alloca(config.cipher_keysize); config.trackerhost = "tracker.publicbt.com:80"; memset(keybuf, 0, config.cipher_keysize); config.key0 = cipher_context_create(config.cipher, keybuf); random_bytes(keybuf, config.cipher_keysize); config.keyX = cipher_context_create(config.cipher, keybuf); config.digest = digest_context_create(digest_sha()); config.digest_size = digest_size(digest_sha()); while (*p != 0) { const char* cmd = *p++; if (strcmp(cmd, "--tracker") == 0) { if (*p == 0) { fprintf(stderr, "tracker address expected\n"); return 2; } tracker_add(config.tracker, *p++); continue; } if (strcmp(cmd, "--remote") == 0) { struct udpaddress address; if (*p == 0) { fprintf(stderr, "remote address expected\n"); return 2; } udpaddress_resolve(&address, *p++); tracker_callback(&config, &address, 0); continue; } if (strcmp(cmd, "--dev") == 0) { if (*p == 0) { fprintf(stderr, "Device name expected\n"); return 2; } fprintf(stderr, "Creating device %s...\n", *p); config.master_fd = tun_create(*p++); if (config.master_fd < 0) { return 1; } config.master_event = event_new(config.event_base, config.master_fd, EV_READ | EV_PERSIST, (event_callback_fn)master_callback, &config); event_add(config.master_event, 0); continue; } if (strcmp(cmd, "--interface") == 0 || strcmp(cmd, "-i") == 0) { const char *name = *p++; struct interface *interface = malloc(sizeof(struct interface)); if (name == 0) { fprintf(stderr, "interface name expected\n"); return 2; } interface->priority = 1; interface->weight = 1; interface->name = strdup(name); interface->next = config.interfaces.next; interface->active = 0; config.interfaces.next = interface; continue; } fprintf(stderr, "Unknown option: %s\n", cmd); return 2; } /*open interfaces*/ config.inotify = inotify_create(config.event_base, &config, (inotification_callback_t)inotify_callback); if (config.inotify == 0) { return 1; } { struct if_nameindex *ifp = if_nameindex(); struct if_nameindex *p = ifp; struct ifaddrs *ifaddr; struct ifaddrs *ifa; if (getifaddrs(&ifaddr) == -1) { perror("getifaddrs"); return 1; } while (p->if_index > 0 && p->if_name != 0) { struct inotification notification; notification.device = p->if_name; notification.type = INOTIFY_INT_ADDED; inotify_callback(&config, ¬ification); for (ifa = ifaddr; ifa != 0; ifa = ifa->ifa_next) { notification.address.family = ifa->ifa_addr->sa_family; if (strcmp(ifa->ifa_name, p->if_name) != 0) { continue; } notification.type = INOTIFY_ADDR_ADDED; /* For an AF_INET* interface address, display the address */ if (notification.address.family == AF_INET) { notification.address.addr4 = ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr; } else if (notification.address.family == AF_INET6) { notification.address.addr6 = ((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr; } else { continue; } inotify_callback(&config, ¬ification); } p++; } if_freenameindex(ifp); freeifaddrs(ifaddr); } fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); config.stdin_event = event_new(config.event_base, STDIN_FILENO, EV_READ | EV_PERSIST, (event_callback_fn)stdin_callback, &config); event_add(config.stdin_event, 0); { struct timeval timeval; timeval.tv_sec = 10; timeval.tv_usec = 0; config.reconnect_event = event_new(config.event_base, -1, EV_PERSIST, (event_callback_fn)reconnect_callback, &config); evtimer_add(config.reconnect_event, &timeval); } reconnect_callback(-1, EV_TIMEOUT, &config); event_base_dispatch(config.event_base); return 0; }