void FillBlock(const block* prev_block, const block* ref_block, block* next_block, const uint64_t* Sbox) { block blockR; CopyBlock(&blockR,ref_block); XORBlock(&blockR,prev_block); block block_tmp; CopyBlock(&block_tmp, &blockR); uint64_t x = 0; if (Sbox != NULL) { x = blockR.v[0] ^ blockR.v[ARGON2_WORDS_IN_BLOCK - 1]; for (int i = 0; i < 6 * 16; ++i) { uint32_t x1 = x >> 32; uint32_t x2 = x & 0xFFFFFFFF; uint64_t y = Sbox[x1 & ARGON2_SBOX_MASK]; uint64_t z = Sbox[(x2 & ARGON2_SBOX_MASK) + ARGON2_SBOX_SIZE / 2]; x = (uint64_t) x1 * (uint64_t) x2; x += y; x ^= z; } }
// ========================================================================= // Decryption function // Note: PlaintextLength must be set to the size of the PlaintextData buffer on // entry; on exit, this will be set to the size of the buffer used. NTSTATUS ImpCypherDecryptSectorData( IN GUID* CypherGUID, IN LARGE_INTEGER SectorID, // Indexed from zero IN int SectorSize, // In bytes IN int KeyLength, // In bits IN FREEOTFEBYTE* Key, IN char* KeyASCII, // ASCII representation of "Key" IN int IVLength, // In bits IN FREEOTFEBYTE* IV, IN int CyphertextLength, // In bytes IN FREEOTFEBYTE* CyphertextData, OUT FREEOTFEBYTE* PlaintextData ) { NTSTATUS status = STATUS_SUCCESS; // Null IV in case we're not given an IV char zeroIV[FREEOTFE_MAX_CYPHER_BLOCKSIZE]; int i; INTEGER_128 blockID128; int errnum; TWOFISH(CONTEXT) context; DEBUGOUTCYPHERIMPL(DEBUGLEV_ENTER, (TEXT("ImpCypherDecryptData\n"))); if ( (IsEqualGUID(&CIPHER_GUID_TWOFISH_256_XTS, CypherGUID)) || (IsEqualGUID(&CIPHER_GUID_TWOFISH_192_XTS, CypherGUID)) || (IsEqualGUID(&CIPHER_GUID_TWOFISH_128_XTS, CypherGUID)) ) { // Generate index in correct format // XTS uses: // *) The sector index (i.e. the number of N-bit sectors) // *) The first sector is sector 0 // *) Littleendian format LARGE_INTEGER__To__INTEGER_128_LittleEndian( SectorID, blockID128 ); if ((errnum = xts_decrypt( &context, &(TWOFISH(set_key)), &(TWOFISH(encrypt)), &(TWOFISH(decrypt)), ((KeyLength/2)), Key, ((KeyLength/2)), &(Key[(KeyLength/2)/8]), CyphertextData, CyphertextLength, PlaintextData, blockID128 )) != CRYPT_OK) { DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to decrypt block (errnum: %d)\n"), errnum)); status = STATUS_UNSUCCESSFUL; } } else if ( (IsEqualGUID(&CIPHER_GUID_TWOFISH_256_CBC, CypherGUID)) || (IsEqualGUID(&CIPHER_GUID_TWOFISH_192_CBC, CypherGUID)) || (IsEqualGUID(&CIPHER_GUID_TWOFISH_128_CBC, CypherGUID)) ) { // Handle situation where a NULL/zero length IV is passed in if ( (IVLength == 0) || (IV == NULL) ) { FREEOTFE_MEMZERO(&zeroIV, sizeof(zeroIV)); IV = (char*)&zeroIV; } // Process data using CBC mode // // CBC Mode DECRYPT: // *) Setup key // *) For each block... // *) Decrypt cyphertext with key // *) XOR output plaintext with IV // *) IV = Cyphertext data // Note: "dec" specified; we're DECRYPTING TWOFISH(set_key)(&context, Key, KeyLength, dec); for (i=0; i < CyphertextLength; i += (TWOFISH_BLOCK_SIZE / 8)) { TWOFISH(decrypt)(&context, CyphertextData+i, PlaintextData+i); XORBlock(PlaintextData+i, IV, PlaintextData+i, (TWOFISH_BLOCK_SIZE / 8)); IV = CyphertextData+i; } } else { DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unsupported cipher GUID passed in.\n"))); status = STATUS_INVALID_PARAMETER; } SecZeroMemory(&context, sizeof(context)); DEBUGOUTCYPHERIMPL(DEBUGLEV_EXIT, (TEXT("ImpCypherDecryptData\n"))); return status; }
// ========================================================================= // Decryption function // Note: PlaintextLength must be set to the size of the PlaintextData buffer on // entry; on exit, this will be set to the size of the buffer used. NTSTATUS ImpCypherDecryptSectorData( IN GUID* CypherGUID, IN LARGE_INTEGER SectorID, // Indexed from zero IN int SectorSize, // In bytes IN int KeyLength, // In bits IN FREEOTFEBYTE* Key, IN char* KeyASCII, // ASCII representation of "Key" IN int IVLength, // In bits IN FREEOTFEBYTE* IV, IN int CyphertextLength, // In bytes IN FREEOTFEBYTE* CyphertextData, OUT FREEOTFEBYTE* PlaintextData ) { NTSTATUS status = STATUS_SUCCESS; // Null IV in case we're not given an IV char zeroIV[FREEOTFE_MAX_CYPHER_BLOCKSIZE]; int i; CONTEXT context; DEBUGOUTCYPHERIMPL(DEBUGLEV_ENTER, (TEXT("ImpCypherDecryptData\n"))); if ( (IsEqualGUID(&CIPHER_GUID_CAST6_256_CBC, CypherGUID)) || (IsEqualGUID(&CIPHER_GUID_CAST6_224_CBC, CypherGUID)) || (IsEqualGUID(&CIPHER_GUID_CAST6_192_CBC, CypherGUID)) || (IsEqualGUID(&CIPHER_GUID_CAST6_160_CBC, CypherGUID)) || (IsEqualGUID(&CIPHER_GUID_CAST6_128_CBC, CypherGUID)) ) { // Handle situation where a NULL/zero length IV is passed in if ( (IVLength == 0) || (IV == NULL) ) { FREEOTFE_MEMZERO(&zeroIV, sizeof(zeroIV)); IV = (char*)&zeroIV; } // Process data using CBC mode // // CBC Mode DECRYPT: // *) Setup key // *) For each block... // *) Decrypt cyphertext with key // *) XOR output plaintext with IV // *) IV = Cyphertext data // Note: "dec" specified; we're DECRYPTING set_key(&context, (u4byte *)Key, KeyLength); for (i=0; i < CyphertextLength; i += (CAST6_BLOCK_SIZE / 8)) { decrypt(&context, (u4byte *)(CyphertextData+i), (u4byte *)(PlaintextData+i)); XORBlock(PlaintextData+i, IV, PlaintextData+i, (CAST6_BLOCK_SIZE / 8)); IV = CyphertextData+i; } } else { DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unsupported cipher GUID passed in.\n"))); status = STATUS_INVALID_PARAMETER; } SecZeroMemory(&context, sizeof(context)); DEBUGOUTCYPHERIMPL(DEBUGLEV_EXIT, (TEXT("ImpCypherDecryptData\n"))); return status; }