/** Test AES-CTR encryption and decryption with IV. */ static void test_crypto_aes_iv(void *arg) { char *plain, *encrypted1, *encrypted2, *decrypted1, *decrypted2; char plain_1[1], plain_15[15], plain_16[16], plain_17[17]; char key1[16], key2[16]; ssize_t encrypted_size, decrypted_size; int use_evp = !strcmp(arg,"evp"); evaluate_evp_for_aes(use_evp); plain = tor_malloc(4095); encrypted1 = tor_malloc(4095 + 1 + 16); encrypted2 = tor_malloc(4095 + 1 + 16); decrypted1 = tor_malloc(4095 + 1); decrypted2 = tor_malloc(4095 + 1); crypto_rand(plain, 4095); crypto_rand(key1, 16); crypto_rand(key2, 16); crypto_rand(plain_1, 1); crypto_rand(plain_15, 15); crypto_rand(plain_16, 16); crypto_rand(plain_17, 17); key1[0] = key2[0] + 128; /* Make sure that contents are different. */ /* Encrypt and decrypt with the same key. */ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 4095, plain, 4095); test_eq(encrypted_size, 16 + 4095); tt_assert(encrypted_size > 0); /* This is obviously true, since 4111 is * greater than 0, but its truth is not * obvious to all analysis tools. */ decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 4095, encrypted1, encrypted_size); test_eq(decrypted_size, 4095); tt_assert(decrypted_size > 0); test_memeq(plain, decrypted1, 4095); /* Encrypt a second time (with a new random initialization vector). */ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted2, 16 + 4095, plain, 4095); test_eq(encrypted_size, 16 + 4095); tt_assert(encrypted_size > 0); decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted2, 4095, encrypted2, encrypted_size); test_eq(decrypted_size, 4095); tt_assert(decrypted_size > 0); test_memeq(plain, decrypted2, 4095); test_memneq(encrypted1, encrypted2, encrypted_size); /* Decrypt with the wrong key. */ decrypted_size = crypto_cipher_decrypt_with_iv(key2, decrypted2, 4095, encrypted1, encrypted_size); test_memneq(plain, decrypted2, decrypted_size); /* Alter the initialization vector. */ encrypted1[0] += 42; decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 4095, encrypted1, encrypted_size); test_memneq(plain, decrypted2, 4095); /* Special length case: 1. */ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 1, plain_1, 1); test_eq(encrypted_size, 16 + 1); tt_assert(encrypted_size > 0); decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 1, encrypted1, encrypted_size); test_eq(decrypted_size, 1); tt_assert(decrypted_size > 0); test_memeq(plain_1, decrypted1, 1); /* Special length case: 15. */ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 15, plain_15, 15); test_eq(encrypted_size, 16 + 15); tt_assert(encrypted_size > 0); decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 15, encrypted1, encrypted_size); test_eq(decrypted_size, 15); tt_assert(decrypted_size > 0); test_memeq(plain_15, decrypted1, 15); /* Special length case: 16. */ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 16, plain_16, 16); test_eq(encrypted_size, 16 + 16); tt_assert(encrypted_size > 0); decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 16, encrypted1, encrypted_size); test_eq(decrypted_size, 16); tt_assert(decrypted_size > 0); test_memeq(plain_16, decrypted1, 16); /* Special length case: 17. */ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 17, plain_17, 17); test_eq(encrypted_size, 16 + 17); tt_assert(encrypted_size > 0); decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 17, encrypted1, encrypted_size); test_eq(decrypted_size, 17); tt_assert(decrypted_size > 0); test_memeq(plain_17, decrypted1, 17); done: /* Free memory. */ tor_free(plain); tor_free(encrypted1); tor_free(encrypted2); tor_free(decrypted1); tor_free(decrypted2); }
/** Decrypt the encrypted introduction points in <b>ipos_encrypted</b> of * length <b>ipos_encrypted_size</b> using <b>descriptor_cookie</b> and * write the result to a newly allocated string that is pointed to by * <b>ipos_decrypted</b> and its length to <b>ipos_decrypted_size</b>. * Return 0 if decryption was successful and -1 otherwise. */ int rend_decrypt_introduction_points(char **ipos_decrypted, size_t *ipos_decrypted_size, const char *descriptor_cookie, const char *ipos_encrypted, size_t ipos_encrypted_size) { tor_assert(ipos_encrypted); tor_assert(descriptor_cookie); if (ipos_encrypted_size < 2) { log_warn(LD_REND, "Size of encrypted introduction points is too " "small."); return -1; } if (ipos_encrypted[0] == (int)REND_BASIC_AUTH) { char iv[CIPHER_IV_LEN], client_id[REND_BASIC_AUTH_CLIENT_ID_LEN], session_key[CIPHER_KEY_LEN], *dec; int declen, client_blocks; size_t pos = 0, len, client_entries_len; crypto_digest_t *digest; crypto_cipher_t *cipher; client_blocks = (int) ipos_encrypted[1]; client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE * REND_BASIC_AUTH_CLIENT_ENTRY_LEN; if (ipos_encrypted_size < 2 + client_entries_len + CIPHER_IV_LEN + 1) { log_warn(LD_REND, "Size of encrypted introduction points is too " "small."); return -1; } memcpy(iv, ipos_encrypted + 2 + client_entries_len, CIPHER_IV_LEN); digest = crypto_digest_new(); crypto_digest_add_bytes(digest, descriptor_cookie, REND_DESC_COOKIE_LEN); crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN); crypto_digest_get_digest(digest, client_id, REND_BASIC_AUTH_CLIENT_ID_LEN); crypto_digest_free(digest); for (pos = 2; pos < 2 + client_entries_len; pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN) { if (tor_memeq(ipos_encrypted + pos, client_id, REND_BASIC_AUTH_CLIENT_ID_LEN)) { /* Attempt to decrypt introduction points. */ cipher = crypto_cipher_new(descriptor_cookie); if (crypto_cipher_decrypt(cipher, session_key, ipos_encrypted + pos + REND_BASIC_AUTH_CLIENT_ID_LEN, CIPHER_KEY_LEN) < 0) { log_warn(LD_REND, "Could not decrypt session key for client."); crypto_cipher_free(cipher); return -1; } crypto_cipher_free(cipher); len = ipos_encrypted_size - 2 - client_entries_len - CIPHER_IV_LEN; dec = tor_malloc_zero(len + 1); declen = crypto_cipher_decrypt_with_iv(session_key, dec, len, ipos_encrypted + 2 + client_entries_len, ipos_encrypted_size - 2 - client_entries_len); if (declen < 0) { log_warn(LD_REND, "Could not decrypt introduction point string."); tor_free(dec); return -1; } if (fast_memcmpstart(dec, declen, "introduction-point ")) { log_warn(LD_REND, "Decrypted introduction points don't " "look like we could parse them."); tor_free(dec); continue; } *ipos_decrypted = dec; *ipos_decrypted_size = declen; return 0; } } log_warn(LD_REND, "Could not decrypt introduction points. Please " "check your authorization for this service!"); return -1; } else if (ipos_encrypted[0] == (int)REND_STEALTH_AUTH) { char *dec; int declen; if (ipos_encrypted_size < CIPHER_IV_LEN + 2) { log_warn(LD_REND, "Size of encrypted introduction points is too " "small."); return -1; } dec = tor_malloc_zero(ipos_encrypted_size - CIPHER_IV_LEN - 1 + 1); declen = crypto_cipher_decrypt_with_iv(descriptor_cookie, dec, ipos_encrypted_size - CIPHER_IV_LEN - 1, ipos_encrypted + 1, ipos_encrypted_size - 1); if (declen < 0) { log_warn(LD_REND, "Decrypting introduction points failed!"); tor_free(dec); return -1; } *ipos_decrypted = dec; *ipos_decrypted_size = declen; return 0; } else { log_warn(LD_REND, "Unknown authorization type number: %d", ipos_encrypted[0]); return -1; } }