Example #1
0
static void
test_crypto_s2k_errors(void *arg)
{
  uint8_t buf[S2K_MAXLEN], buf2[S2K_MAXLEN];
  size_t sz;

  (void)arg;

  /* Bogus specifiers: simple */
  tt_int_op(S2K_BAD_LEN, OP_EQ,
            secret_to_key_derivekey(buf, sizeof(buf),
                                    (const uint8_t*)"", 0, "ABC", 3));
  tt_int_op(S2K_BAD_ALGORITHM, OP_EQ,
            secret_to_key_derivekey(buf, sizeof(buf),
                                    (const uint8_t*)"\x10", 1, "ABC", 3));
  tt_int_op(S2K_BAD_LEN, OP_EQ,
            secret_to_key_derivekey(buf, sizeof(buf),
                                    (const uint8_t*)"\x01\x02", 2, "ABC", 3));

  tt_int_op(S2K_BAD_LEN, OP_EQ,
            secret_to_key_check((const uint8_t*)"", 0, "ABC", 3));
  tt_int_op(S2K_BAD_ALGORITHM, OP_EQ,
            secret_to_key_check((const uint8_t*)"\x10", 1, "ABC", 3));
  tt_int_op(S2K_BAD_LEN, OP_EQ,
            secret_to_key_check((const uint8_t*)"\x01\x02", 2, "ABC", 3));

  /* too long gets "BAD_LEN" too */
  memset(buf, 0, sizeof(buf));
  buf[0] = 2;
  tt_int_op(S2K_BAD_LEN, OP_EQ,
            secret_to_key_derivekey(buf2, sizeof(buf2),
                                    buf, sizeof(buf), "ABC", 3));

  /* Truncated output */
#ifdef HAVE_LIBSCRYPT_H
  tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 50, &sz,
                                                 "ABC", 3, 0));
  tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 50, &sz,
                                                 "ABC", 3, S2K_FLAG_LOW_MEM));
#endif
  tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 37, &sz,
                                              "ABC", 3, S2K_FLAG_USE_PBKDF2));
  tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 29, &sz,
                                              "ABC", 3, S2K_FLAG_NO_SCRYPT));

#ifdef HAVE_LIBSCRYPT_H
  tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_make_specifier(buf, 18, 0));
  tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_make_specifier(buf, 18,
                                                 S2K_FLAG_LOW_MEM));
#endif
  tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_make_specifier(buf, 17,
                                                 S2K_FLAG_USE_PBKDF2));
  tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_make_specifier(buf, 9,
                                                 S2K_FLAG_NO_SCRYPT));

  /* Now try using type-specific bogus specifiers. */

  /* It's a bad pbkdf2 buffer if it has an iteration count that would overflow
   * int32_t. */
  memset(buf, 0, sizeof(buf));
  buf[0] = 1; /* pbkdf2 */
  buf[17] = 100; /* 1<<100 is much bigger than INT32_MAX */
  tt_int_op(S2K_BAD_PARAMS, OP_EQ,
            secret_to_key_derivekey(buf2, sizeof(buf2),
                                    buf, 18, "ABC", 3));

#ifdef HAVE_LIBSCRYPT_H
  /* It's a bad scrypt buffer if N would overflow uint64 */
  memset(buf, 0, sizeof(buf));
  buf[0] = 2; /* scrypt */
  buf[17] = 100; /* 1<<100 is much bigger than UINT64_MAX */
  tt_int_op(S2K_BAD_PARAMS, OP_EQ,
            secret_to_key_derivekey(buf2, sizeof(buf2),
                                    buf, 19, "ABC", 3));
#endif

 done:
  ;
}
Example #2
0
/**
 * Make an authenticated passphrase-encrypted blob to encode the
 * <b>input_len</b> bytes in <b>input</b> using the passphrase
 * <b>secret</b> of <b>secret_len</b> bytes.  Allocate a new chunk of memory
 * to hold the encrypted data, and store a pointer to that memory in
 * *<b>out</b>, and its size in <b>outlen_out</b>.  Use <b>s2k_flags</b> as an
 * argument to the passphrase-hashing function.
 */
int
crypto_pwbox(uint8_t **out, size_t *outlen_out,
             const uint8_t *input, size_t input_len,
             const char *secret, size_t secret_len,
             unsigned s2k_flags)
{
  uint8_t *result = NULL, *encrypted_portion;
  size_t encrypted_len = 128 * CEIL_DIV(input_len+4, 128);
  ssize_t result_len;
  int spec_len;
  uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN];
  pwbox_encoded_t *enc = NULL;
  ssize_t enc_len;

  crypto_cipher_t *cipher;
  int rv;

  enc = pwbox_encoded_new();

  pwbox_encoded_setlen_skey_header(enc, S2K_MAXLEN);

  spec_len = secret_to_key_make_specifier(
                                      pwbox_encoded_getarray_skey_header(enc),
                                      S2K_MAXLEN,
                                      s2k_flags);
  if (BUG(spec_len < 0 || spec_len > S2K_MAXLEN))
    goto err;
  pwbox_encoded_setlen_skey_header(enc, spec_len);
  enc->header_len = spec_len;

  crypto_rand((char*)enc->iv, sizeof(enc->iv));

  pwbox_encoded_setlen_data(enc, encrypted_len);
  encrypted_portion = pwbox_encoded_getarray_data(enc);

  set_uint32(encrypted_portion, htonl((uint32_t)input_len));
  memcpy(encrypted_portion+4, input, input_len);

  /* Now that all the data is in position, derive some keys, encrypt, and
   * digest */
  const int s2k_rv = secret_to_key_derivekey(keys, sizeof(keys),
                              pwbox_encoded_getarray_skey_header(enc),
                              spec_len,
                              secret, secret_len);
  if (BUG(s2k_rv < 0))
    goto err;

  cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv);
  crypto_cipher_crypt_inplace(cipher, (char*)encrypted_portion, encrypted_len);
  crypto_cipher_free(cipher);

  result_len = pwbox_encoded_encoded_len(enc);
  if (BUG(result_len < 0))
    goto err;
  result = tor_malloc(result_len);
  enc_len = pwbox_encoded_encode(result, result_len, enc);
  if (BUG(enc_len < 0))
    goto err;
  tor_assert(enc_len == result_len);

  crypto_hmac_sha256((char*) result + result_len - 32,
                     (const char*)keys + CIPHER_KEY_LEN,
                     DIGEST256_LEN,
                     (const char*)result,
                     result_len - 32);

  *out = result;
  *outlen_out = result_len;
  rv = 0;
  goto out;

 err:
  /* LCOV_EXCL_START

     This error case is often unreachable if we're correctly coded, unless
     somebody adds a new error case somewhere, or unless you're building
     without scrypto support.

       - make_specifier can't fail, unless S2K_MAX_LEN is too short.
       - secret_to_key_derivekey can't really fail unless we're missing
         scrypt, or the underlying function fails, or we pass it a bogus
         algorithm or parameters.
       - pwbox_encoded_encoded_len can't fail unless we're using trunnel
         incorrectly.
       - pwbox_encoded_encode can't fail unless we're using trunnel wrong,
         or it's buggy.
   */
  tor_free(result);
  rv = -1;
  /* LCOV_EXCL_STOP */
 out:
  pwbox_encoded_free(enc);
  memwipe(keys, 0, sizeof(keys));
  return rv;
}