static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
		       struct scatterlist *src, unsigned int nbytes)
{
	struct crypto_aes_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
	int err, first, rounds = 6 + ctx->key1.key_length / 4;
	struct blkcipher_walk walk;
	unsigned int blocks;

	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
	blkcipher_walk_init(&walk, dst, src, nbytes);
	err = blkcipher_walk_virt(desc, &walk);

	kernel_neon_begin();
	for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) {
		aes_xts_decrypt(walk.dst.virt.addr, walk.src.virt.addr,
				(u8 *)ctx->key1.key_dec, rounds, blocks,
				(u8 *)ctx->key2.key_enc, walk.iv, first);
		err = blkcipher_walk_done(desc, &walk, walk.nbytes % AES_BLOCK_SIZE);
	}
	kernel_neon_end();

	return err;
}
Exemple #2
0
void
horus_crypt (char *buf, ssize_t size, unsigned long long offset, int op)
{
  unsigned long long prev_horus_align, next_horus_align;
  unsigned long long ioffset = 0;
  unsigned long sblock, eblock, block_id;
  int ret, verbose = 0, debug = 0;
  unsigned long x, y;
  int horus = 0, aescrypt = 0, nowriteback = 0, aggregate = 0, spinwait = 0;
  char *addr, *filename, *hostname, *level;

  char block_key[HORUS_KEY_LEN];
  size_t block_key_len;

  /* AES */
  unsigned long aes_sblock, aes_eblock, aes_block_id;
  u_int8_t aeskey[AES_KEYSIZE_128 * 2];
  u_int8_t iv[AES_KEYSIZE_128 * 2];
  char crypt_buf[HORUS_BLOCK_SIZE];

  if (getenv ("HORUS_VERBOSE"))
    verbose++;
  if (getenv ("HORUS_DEBUG"))
    debug++;
  if (getenv ("DISABLE_WRITEBACK"))
    nowriteback++;

  if (getenv ("ENABLE_AES"))
    aescrypt++;
  if (getenv ("ENABLE_HORUS"))
    horus++;
  if (getenv ("ENABLE_AGGREGATE"))
    aggregate++;
  if (getenv ("ENABLE_SPINWAIT"))
    spinwait++;
  level = getenv ("REQUEST_LEVEL");
  if (level)
    request_level = atoi(level);

  hostname = getenv ("HOSTNAME");

  addr = getenv ("HORUS_KDS_SERVER");
  if (addr)
    kds_serv_addr = addr;
  else
    {
      printf ("env HORUS_KDS_SERVER not set.\n");
      exit (2);
    }

  filename = getenv ("HORUS_FILENAME");
  if (filename)
    file_path = filename;
  else
    {
      printf ("env HORUS_FILENAME not set.\n");
      exit (2);
    }

  if (! getenv ("DISABLE_CONFIGPRINT"))
    printf ("Horus BTIO: %s%s%s%s%s%s%s%s%s%s%s\n",
          (verbose ?     " verbose" : ""),
          (debug ?       " debug" : ""),
          (nowriteback ? " nowriteback" : ""),
          (aescrypt ?    " aes" : ""),
          (horus ?       " horus" : ""),
          (aggregate ?   " aggregate" : ""),
          (spinwait ?    " spinwait" : ""),
          (addr ?        " serv: " : ""),
          (addr ?          addr : ""),
          (filename ?    " file: " : ""),
          (filename ?      filename : ""));

  if (horus == 0 && aescrypt == 0)
    return;

  if (aggregate)
    request_level = 0;

  if (debug)
    horus_verbose++;

  /* Decide AES block size (only the first time) */
  if (aes_block_size == 0)
    {
      if (size > HORUS_BLOCK_SIZE)
        {
          if (size % HORUS_BLOCK_SIZE)
            aes_block_size = size % HORUS_BLOCK_SIZE;
          else
            aes_block_size = HORUS_BLOCK_SIZE;
        }
      else
        aes_block_size = size;

      if (verbose)
        printf ("AES block size: %lu\n", aes_block_size);

      if (aes_block_size % AES_KEYSIZE_128 != 0)
        printf ("aes_block_size not aligned with %d\n", AES_KEYSIZE_128);
      if (offset % aes_block_size != 0)
        printf ("offset not aligned with %lu\n", aes_block_size);
      if (size % aes_block_size != 0)
        printf ("size not aligned with %lu\n", aes_block_size);
    }

  /* Horus file config (only the first time) */
  if (horus && leaf_level < 0)
    {
      int fd;

      if (verbose)
        printf ("Horus for %s\n", file_path);

      /* Get Horus config */
      fd = open (file_path, O_RDONLY);
      ret = horus_get_file_config (fd, &horus_config);
      assert (ret >= 0 && horus_is_valid_config (&horus_config));
      close (fd);
      leaf_level = horus_get_leaf_level (&horus_config);

      /* Setup connection with KDS */
      pthread_mutex_lock(&fd_mutex);
      horus_sockfd = socket (PF_INET, SOCK_DGRAM, 0);
      pthread_mutex_unlock(&fd_mutex);
      if (spinwait)
        fcntl (horus_sockfd, F_SETFL, O_NONBLOCK);
      assert (horus_sockfd > 0);
      memset (&horus_kds_addr, 0, sizeof (horus_kds_addr));
      horus_kds_addr.sin_family = AF_INET;
      inet_pton (AF_INET, kds_serv_addr, &horus_kds_addr.sin_addr);
      horus_kds_addr.sin_port = htons (HORUS_KDS_SERVER_PORT);
    }

  /* AES */
  if (aescrypt && cipher == NULL)
    cipher = aes_xts_init ();
  memset (aeskey, 0, sizeof (aeskey));
  memset (iv, 0, sizeof (iv));

  sblock = offset / HORUS_BLOCK_SIZE;
  eblock = (offset + size) / HORUS_BLOCK_SIZE + 1;

  x = leaf_level;
  for (block_id = sblock; block_id < eblock; block_id++)
    {
      y = block_id;

      if (horus)
        {
          /* If the horus key does not match, request */
          if (horus_key_x < 0 ||
              horus_key_y != horus_key_y_of (horus_key_x, x, y,
                                             horus_config.kht_block_size))
            {
              if (request_level < 0)
                request_level = leaf_level;
              horus_key_x = request_level;
              horus_key_y = horus_key_y_of (request_level, x, y,
                                            horus_config.kht_block_size);
              horus_key_len = sizeof (horus_key);
              if (spinwait)
                horus_key_request_spin (horus_key, &horus_key_len,
                                        file_path, horus_key_x, horus_key_y,
                                        horus_sockfd, &horus_kds_addr);
              else
                horus_key_request (horus_key, &horus_key_len,
                                   file_path, horus_key_x, horus_key_y,
                                   horus_sockfd, &horus_kds_addr);

              if (verbose)
                printf ("request K_%d,%d = %s\n", horus_key_x, horus_key_y,
                        print_key (horus_key, horus_key_len));
            }

          /* Calculate the leaf key */
          if (horus_key_x != x)
            {
              block_key_len = sizeof (block_key);
              horus_block_key (block_key, &block_key_len, x, y,
                               horus_key, horus_key_len,
                               horus_key_x, horus_key_y,
                               horus_config.kht_block_size);
              if (verbose)
                printf ("calculated K_%lu,%lu = %s\n", x, y,
                        print_key (block_key, block_key_len));
            }
          else
            {
              assert (horus_key_y == y);
              memcpy (block_key, horus_key, HORUS_KEY_LEN);
              block_key_len = horus_key_len;
            }
        }

      if (aescrypt)
        {
          /* Set AES key */
          memset (aeskey, 0, AES_KEYSIZE_128 * 2);
          if (horus)
            memcpy (aeskey, block_key, block_key_len);
          ret = aes_xts_setkey (cipher, aeskey, AES_KEYSIZE_128 * 2);
          assert (! ret);
        }

      /* Calculate AES block */
      prev_horus_align = ((offset + ioffset) / HORUS_BLOCK_SIZE) *
                         HORUS_BLOCK_SIZE;
      next_horus_align = prev_horus_align + HORUS_BLOCK_SIZE;
      aes_sblock = (offset + ioffset) / aes_block_size;
      aes_eblock = MIN (offset + size, next_horus_align) / aes_block_size;
      if (verbose)
        printf ("aes_block: start: %lu end: %lu (pos %#llx)\n",
                aes_sblock, aes_eblock, offset + ioffset);
      if (debug && aes_sblock == aes_eblock)
        {
          printf ("prev_horus_align = %llu\n", prev_horus_align);
          printf ("next_horus_align = %llu\n", next_horus_align);
          printf ("offset: %llu, ioffset: %llu, aes_block_size: %lu",
                  offset, ioffset, aes_block_size);
          printf ("MIN(offset+size,next_horus_align): %llu",
                  MIN (offset+size, next_horus_align));
        }
      //assert (aes_sblock < aes_eblock);

      for (aes_block_id = aes_sblock; aes_block_id < aes_eblock;
           aes_block_id++)
        {
          if (verbose)
            printf ("offset: %llu aes[%lu]: ioffset: %llu buf: %s\n",
                    offset, aes_block_id, ioffset,
                    print_key (buf + ioffset, 16));

          /* Set AES IV */
          memset (iv, 0, sizeof (iv));
          *(unsigned long long *)iv = aes_block_id;

          /* AES cryptography */
          if (op == OP_DECRYPT)
            {
              if (aescrypt && debug)
                printf ("offset: %llu aes[%lu]: ioffset: %llu op: decrypt\n",
                        offset, aes_block_id, ioffset);
              if (aescrypt)
                aes_xts_decrypt (cipher, crypt_buf, buf + ioffset,
                                 aes_block_size, iv);
              else
                memcpy (crypt_buf, buf + ioffset, aes_block_size);
            }
          else
            {
              if (aescrypt && debug)
                printf ("offset: %llu aes[%lu]: ioffset: %llu op: encrypt\n",
                        offset, aes_block_id, ioffset);
              if (aescrypt)
                aes_xts_encrypt (cipher, crypt_buf, buf + ioffset,
                                 aes_block_size, iv);
              else
                memcpy (crypt_buf, buf + ioffset, aes_block_size);
            }

          if (debug)
            printf ("offset: %llu aes[%lu]: ioffset: %llu crypt: %s\n",
                    offset, aes_block_id, ioffset,
                    print_key (crypt_buf, 16));

          if (! nowriteback)
            {
              /* write it back */
              memcpy (buf + ioffset, crypt_buf, aes_block_size);
            }

          if (debug)
            printf ("offset: %llu aes[%lu]: ioffset: %llu writeback: %s\n",
                    offset, aes_block_id, ioffset,
                    print_key (buf + ioffset, 16));

          ioffset += aes_block_size;
        }
    }
}