Skip to content

Salt alignment Binary alignment.

jfoug edited this page Nov 10, 2017 · 1 revision

We have 2 fields within the format structure. 1 for salt alignment, and 1 for binary alignment. These are HARD requirements when building formats. This is due to certain machines which REQUIRE proper alignment when accessing data larger than 1 byte (some even require it for 1 byte alignment). The compiler when generating code, and generating data (stack local structure variables, or globals), will properly align the data used for the structure, so that it will NOT cause the machine to crash. The rub comes, within john, when we use our 'tiny' memory allocation functions. With those functions, we are able to allocate memory on any memory boundary. Also, things fall into this realm, when using the system allocation system (malloc), and it does not align to a large enough offset (say it maxes out at 8 byte alignment, but we need it 16 byte aligned).

So, since WE are in charge of alignment when we allocate, and we DO allocate for binary blobs and stalt blobs within john, then we MUST get this alignment correct.

So if this is the salt structure:

struct dummy_salt { int x; int y; double z; char Buf[48]; short len; unsigned int crc; };

Then the largest object in there is the double. It is NOT the char Buf[48]. The size of that object is only 1 byte. The object which requires the alignment is the double z; object. If we align the entire structure to the sizeof(double) in this case, THEN the compiler will make SURE that 'z' is at the proper location (offset wise) to be accessed. The compiler will also make sure that x, y , len and crc are all aligned properly. It is all based upon the start of the entire memory blob being offset in the proper location.

Instance #2

struct salt { unsigned char datablob[1024]; };

crypt_all() { uint64_t p = (uint64_t)cur_salt.datablob; for (i = 0; i < 10; ++i) { *p++ = operations(input); } }

This really is a busted salt. It should have been uint64_t datablob[1024/8]; or even struct salt { union { uint64_t p[1]; unsigned char datablob[1024]; }; };

In this case (same layout of the structure), the compiler would know we access this as uint64_t, so it would align properly (the first case it does not), and we can still access the salt using either 1 or 8 byte pointers.

Binary alignment.

Usually, binary alignment is at least 4 bytes (sizeof uint32_t). This is due to how the get_hash() functions operate. They 'access' the buffer using 32 bit integers. If these functions are used:

fmt_default_get_hash_0, fmt_default_get_hash_1, fmt_default_get_hash_2, fmt_default_get_hash_3, fmt_default_get_hash_4, fmt_default_get_hash_5, fmt_default_get_hash_6

Then the binary align MUST be set to at least 4 bytes. If the format is a 64 bit hash (and accesses data with 64 bit structures), then it should be 8 byte aligned.

IF the format is being built for SIMD, and accessed thusly, then it should align binary to proper SIMD alignment