// ========================================================================= // Cypher driver init function // driverInfo - The structure to be initialized NTSTATUS ImpCypherDriverExtDetailsInit_v3( IN OUT CYPHER_DRIVER_INFO_v3* driverInfo ) { NTSTATUS status = STATUS_SUCCESS; int idx = -1; DEBUGOUTCYPHERIMPL(DEBUGLEV_ENTER, (TEXT("ImpCypherDriverExtDetailsInit_v3\n"))); // -- POPULATE DRIVER IDENTIFICATION -- FREEOTFE_MEMZERO(driverInfo->DriverTitle, sizeof(driverInfo->DriverTitle)); FREEOTFE_MEMCPY( driverInfo->DriverTitle, DRIVER_TITLE, strlen(DRIVER_TITLE) ); driverInfo->DriverGUID = DRIVER_GUID; driverInfo->DriverVersionID = DRIVER_CYPHER_VERSION; // -- POPULATE CYPHERS SUPPORTED -- driverInfo->CypherCount = CYPHERS_SUPPORTED; driverInfo->CypherDetails = FREEOTFE_MEMCALLOC( sizeof(CYPHER_v3), driverInfo->CypherCount ); // -- CAST5 -- idx++; FREEOTFE_MEMZERO(driverInfo->CypherDetails[idx].Title, MAX_CYPHER_TITLE); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_CAST5, strlen(DRIVER_CIPHER_TITLE_CAST5) ); driverInfo->CypherDetails[idx].Mode = CYPHER_MODE_CBC; driverInfo->CypherDetails[idx].KeySizeUnderlying = 128; driverInfo->CypherDetails[idx].BlockSize = (cast5_desc.block_length * 8); driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_CAST5; driverInfo->CypherDetails[idx].KeySizeRequired = driverInfo->CypherDetails[idx].KeySizeUnderlying; DEBUGOUTCYPHERIMPL(DEBUGLEV_EXIT, (TEXT("ImpCypherDriverExtDetailsInit_v3\n"))); return status; }
// ========================================================================= // Hash driver init function // driverInfo - The structure to be initialized NTSTATUS ImpHashDriverExtDetailsInit( IN OUT HASH_DRIVER_INFO* driverInfo ) { NTSTATUS status = STATUS_SUCCESS; int idx = -1; DEBUGOUTHASHIMPL(DEBUGLEV_ENTER, (TEXT("ImpHashDriverExtDetailsInit\n"))); // -- POPULATE DRIVER IDENTIFICATION -- FREEOTFE_MEMZERO(driverInfo->DriverTitle, sizeof(driverInfo->DriverTitle)); FREEOTFE_MEMCPY( driverInfo->DriverTitle, DRIVER_TITLE, strlen(DRIVER_TITLE) ); driverInfo->DriverGUID = DRIVER_GUID; driverInfo->DriverVersionID = DRIVER_HASH_VERSION; // -- POPULATE HASHES SUPPORTED -- driverInfo->HashCount = HASHES_SUPPORTED; driverInfo->HashDetails = FREEOTFE_MEMCALLOC( sizeof(HASH), driverInfo->HashCount ); // -- Null -- idx++; FREEOTFE_MEMZERO(driverInfo->HashDetails[idx].Title, MAX_HASH_TITLE); FREEOTFE_MEMCPY( driverInfo->HashDetails[idx].Title, DRIVER_HASH_TITLE_NULL, strlen(DRIVER_HASH_TITLE_NULL) ); driverInfo->HashDetails[idx].Length = -1; driverInfo->HashDetails[idx].BlockSize = -1; driverInfo->HashDetails[idx].VersionID = DRIVER_HASH_IMPL_VERSION; driverInfo->HashDetails[idx].HashGUID = HASH_GUID_NULL; DEBUGOUTHASHIMPL(DEBUGLEV_EXIT, (TEXT("ImpHashDriverExtDetailsInit\n"))); return status; }
// ========================================================================= // Copy contents of CYPHER_DRIVER_INFO_v3 struct to CYPHER_DRIVER_INFO_v1 // struct // ! WARNING ! void CopyCYPHER_DRIVER_INFO_v1ToCYPHER_DRIVER_INFO_v3( IN CYPHER_DRIVER_INFO_v1* Source, OUT CYPHER_DRIVER_INFO_v3* Dest ) { unsigned int i; Dest->DriverGUID = Source->DriverGUID; FREEOTFE_MEMZERO(Dest->DriverTitle, sizeof(Dest->DriverTitle)); FREEOTFE_MEMCPY( Dest->DriverTitle, Source->DriverTitle, strlen(Source->DriverTitle) ); Dest->DriverVersionID = Source->DriverVersionID; Dest->CypherCount = Source->CypherCount; Dest->CypherDetails = FREEOTFE_MEMCALLOC( Source->CypherCount, sizeof(Dest->CypherDetails[0]) ); for (i = 0; i < Source->CypherCount; i++) { CopyCYPHER_v1ToCYPHER_v3( &(Source->CypherDetails[i]), &(Dest->CypherDetails[i]) ); } }
// ========================================================================= // Hash function // driverInfo - The structure to be cleared down NTSTATUS ImpHashHashData( IN GUID* HashGUID, IN unsigned int DataLength, // In bits IN FREEOTFEBYTE* Data, IN OUT unsigned int* HashLength, // In bits OUT FREEOTFEBYTE* Hash ) { NTSTATUS status = STATUS_SUCCESS; WCHAR* tmpGUIDStr; DEBUGOUTHASHIMPL(DEBUGLEV_ENTER, (TEXT("ImpHashHashData\n"))); if (IsEqualGUID(&HASH_GUID_NULL, HashGUID)) { if (*HashLength < DataLength) { DEBUGOUTHASHIMPL(DEBUGLEV_ERROR, (TEXT("output hash length buffer too small (got: %d; need: %d)\n"), *HashLength, DataLength )); status = STATUS_BUFFER_TOO_SMALL; } else { FREEOTFE_MEMZERO( Hash, ((*HashLength) / 8) // Convert bits to bytes ); FREEOTFE_MEMCPY( Hash, Data, (DataLength / 8) // Convert bits to bytes ); *HashLength = DataLength; } } else { DEBUGOUTHASHIMPL(DEBUGLEV_ERROR, (TEXT("Driver doesn't recognise GUID\n"))); GUIDToWCHAR(HashGUID, &tmpGUIDStr); DEBUGOUTHASHIMPL(DEBUGLEV_INFO, (TEXT("Hash passed in: %ls\n"), tmpGUIDStr)); SecZeroAndFreeWCHARMemory(tmpGUIDStr); status = STATUS_INVALID_PARAMETER; } DEBUGOUTHASHIMPL(DEBUGLEV_EXIT, (TEXT("ImpHashHashData\n"))); return status; }
// ========================================================================= // Copy contents of CYPHER_v3 struct to CYPHER_v1 struct void CopyCYPHER_v3ToCYPHER_v1( IN CYPHER_v3* Source, OUT CYPHER_v1* Dest ) { FREEOTFE_MEMZERO(Dest->Title, sizeof(Dest->Title)); FREEOTFE_MEMCPY( Dest->Title, Source->Title, strlen(Source->Title) ); Dest->BlockSize = Source->BlockSize; Dest->VersionID = Source->VersionID; Dest->CypherGUID = Source->CypherGUID; Dest->KeySizeUnderlying = Source->KeySizeRequired; Dest->Mode = Source->Mode; }
// ========================================================================= // Copy contents of CYPHER_v1 struct to CYPHER_v3 struct void CopyCYPHER_v1ToCYPHER_v3( IN CYPHER_v1* Source, OUT CYPHER_v3* Dest ) { FREEOTFE_MEMZERO(Dest->Title, sizeof(Dest->Title)); FREEOTFE_MEMCPY( Dest->Title, Source->Title, strlen(Source->Title) ); Dest->BlockSize = Source->BlockSize; Dest->VersionID = Source->VersionID; Dest->CypherGUID = Source->CypherGUID; Dest->KeySizeUnderlying = Source->KeySizeUnderlying; Dest->Mode = Source->Mode; // Values which don't exist in the earlier struct... Dest->KeySizeRequired = Dest->KeySizeUnderlying; }
// ========================================================================= // Cypher driver init function // driverInfo - The structure to be initialized NTSTATUS ImpCypherDriverExtDetailsInit_v3( IN OUT CYPHER_DRIVER_INFO_v3* driverInfo ) { NTSTATUS status = STATUS_SUCCESS; int idx = -1; DEBUGOUTCYPHERIMPL(DEBUGLEV_ENTER, (TEXT("ImpCypherDriverExtDetailsInit_v3\n"))); // -- POPULATE DRIVER IDENTIFICATION -- FREEOTFE_MEMZERO(driverInfo->DriverTitle, sizeof(driverInfo->DriverTitle)); FREEOTFE_MEMCPY( driverInfo->DriverTitle, DRIVER_TITLE, strlen(DRIVER_TITLE) ); driverInfo->DriverGUID = DRIVER_GUID; driverInfo->DriverVersionID = DRIVER_CYPHER_VERSION; // -- POPULATE CYPHERS SUPPORTED -- driverInfo->CypherCount = CYPHERS_SUPPORTED; driverInfo->CypherDetails = FREEOTFE_MEMCALLOC( sizeof(CYPHER_v3), driverInfo->CypherCount ); // -- Twofish-256 XTS -- idx++; FREEOTFE_MEMZERO(driverInfo->CypherDetails[idx].Title, MAX_CYPHER_TITLE); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_TWOFISH_256_XTS, strlen(DRIVER_CIPHER_TITLE_TWOFISH_256_XTS) ); driverInfo->CypherDetails[idx].Mode = CYPHER_MODE_XTS; driverInfo->CypherDetails[idx].KeySizeUnderlying = 256; driverInfo->CypherDetails[idx].BlockSize = TWOFISH_BLOCK_SIZE; driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_TWOFISH_256_XTS; driverInfo->CypherDetails[idx].KeySizeRequired = (2 * driverInfo->CypherDetails[idx].KeySizeUnderlying); // -- Twofish-192 XTS -- idx++; FREEOTFE_MEMZERO(driverInfo->CypherDetails[idx].Title, MAX_CYPHER_TITLE); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_TWOFISH_192_XTS, strlen(DRIVER_CIPHER_TITLE_TWOFISH_192_XTS) ); driverInfo->CypherDetails[idx].Mode = CYPHER_MODE_XTS; driverInfo->CypherDetails[idx].KeySizeUnderlying = 192; driverInfo->CypherDetails[idx].BlockSize = TWOFISH_BLOCK_SIZE; driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_TWOFISH_192_XTS; driverInfo->CypherDetails[idx].KeySizeRequired = (2 * driverInfo->CypherDetails[idx].KeySizeUnderlying); // -- Twofish-128 XTS -- idx++; FREEOTFE_MEMZERO(driverInfo->CypherDetails[idx].Title, MAX_CYPHER_TITLE); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_TWOFISH_128_XTS, strlen(DRIVER_CIPHER_TITLE_TWOFISH_128_XTS) ); driverInfo->CypherDetails[idx].Mode = CYPHER_MODE_XTS; driverInfo->CypherDetails[idx].KeySizeUnderlying = 128; driverInfo->CypherDetails[idx].BlockSize = TWOFISH_BLOCK_SIZE; driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_TWOFISH_128_XTS; driverInfo->CypherDetails[idx].KeySizeRequired = (2 * driverInfo->CypherDetails[idx].KeySizeUnderlying); // -- Twofish-256 CBC -- idx++; FREEOTFE_MEMZERO(driverInfo->CypherDetails[idx].Title, MAX_CYPHER_TITLE); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_TWOFISH_256_CBC, strlen(DRIVER_CIPHER_TITLE_TWOFISH_256_CBC) ); driverInfo->CypherDetails[idx].Mode = CYPHER_MODE_CBC; driverInfo->CypherDetails[idx].KeySizeUnderlying = 256; driverInfo->CypherDetails[idx].BlockSize = TWOFISH_BLOCK_SIZE; driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_TWOFISH_256_CBC; driverInfo->CypherDetails[idx].KeySizeRequired = driverInfo->CypherDetails[idx].KeySizeUnderlying; // -- Twofish-192 CBC -- idx++; FREEOTFE_MEMZERO(driverInfo->CypherDetails[idx].Title, MAX_CYPHER_TITLE); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_TWOFISH_192_CBC, strlen(DRIVER_CIPHER_TITLE_TWOFISH_192_CBC) ); driverInfo->CypherDetails[idx].Mode = CYPHER_MODE_CBC; driverInfo->CypherDetails[idx].KeySizeUnderlying = 192; driverInfo->CypherDetails[idx].BlockSize = TWOFISH_BLOCK_SIZE; driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_TWOFISH_192_CBC; driverInfo->CypherDetails[idx].KeySizeRequired = driverInfo->CypherDetails[idx].KeySizeUnderlying; // -- Twofish-128 CBC -- idx++; FREEOTFE_MEMZERO(driverInfo->CypherDetails[idx].Title, MAX_CYPHER_TITLE); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_TWOFISH_128_CBC, strlen(DRIVER_CIPHER_TITLE_TWOFISH_128_CBC) ); driverInfo->CypherDetails[idx].Mode = CYPHER_MODE_CBC; driverInfo->CypherDetails[idx].KeySizeUnderlying = 128; driverInfo->CypherDetails[idx].BlockSize = TWOFISH_BLOCK_SIZE; driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_TWOFISH_128_CBC; driverInfo->CypherDetails[idx].KeySizeRequired = driverInfo->CypherDetails[idx].KeySizeUnderlying; DEBUGOUTCYPHERIMPL(DEBUGLEV_EXIT, (TEXT("ImpCypherDriverExtDetailsInit_v3\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; 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; }
// ========================================================================= // Generate block IV NTSTATUS GenerateBlockIV( IN DEVICE_CONTEXT* devContext, IN LARGE_INTEGER fileOffset, // The offset within the *volume file* where // the data was obtained from IN unsigned int blockIVLength, // The size of the required IV (and length of // "sectorIV"), in bits OUT unsigned char* blockIV ) { NTSTATUS status; LARGE_INTEGER blockID; unsigned int useBytes; unsigned int i; unsigned int j; DEBUGOUTMAINDRV(DEBUGLEV_VERBOSE_ENTER, (TEXT("GenerateBlockIV\n"))); status = STATUS_SUCCESS; DEBUGOUTMAINDRV(DEBUGLEV_VERBOSE_INFO, (TEXT("Block IV length is: %d\n"), blockIVLength)); // Belt 'n braces - we should never be called if there isn't a fixed blocksize... if (blockIVLength <= 0) { DEBUGOUTMAINDRV(DEBUGLEV_ERROR, (TEXT("IV length requested is <= 0\n"))); status = STATUS_INVALID_PARAMETER; } else { // Generate the IV... // Clear down the IV so we have a NULL IV/baseline IV to work from... FREEOTFE_MEMZERO( blockIV, (blockIVLength / 8) ); blockID = GetBlockID(devContext, fileOffset); DEBUGOUTMAINDRV(DEBUGLEV_VERBOSE_INFO, (TEXT("Block IV generation method: %d\n"), devContext->SectorIVGenMethod)); switch (devContext->SectorIVGenMethod) { case SCTRIVGEN_NONE: { // Do nothing - sector IV already zero'd break; } case SCTRIVGEN_32BIT_SECTOR_ID: { status = GenerateBlockIV_SectorID( blockID, 32, blockIVLength, blockIV ); break; } case SCTRIVGEN_64BIT_SECTOR_ID: { status = GenerateBlockIV_SectorID( blockID, 64, blockIVLength, blockIV ); break; } case SCTRIVGEN_HASH_32BIT_SECTOR_ID: { status = GenerateBlockIV_HashedSectorID( devContext, blockID, 32, blockIVLength, blockIV ); break; } case SCTRIVGEN_HASH_64BIT_SECTOR_ID: { status = GenerateBlockIV_HashedSectorID( devContext, blockID, 64, blockIVLength, blockIV ); break; } case SCTRIVGEN_ESSIV: { status = GenerateBlockIV_ESSIV( devContext, blockID, 64, blockIVLength, blockIV ); break; } default: { DEBUGOUTMAINDRV(DEBUGLEV_ERROR, (TEXT("Unknown block IV generation method: %d\n"), devContext->SectorIVGenMethod)); status = STATUS_INVALID_PARAMETER;; } } // If we have a per-volume IV, XOR it with IV... if (NT_SUCCESS(status)) { DEBUGOUTMAINDRV(DEBUGLEV_VERBOSE_INFO, (TEXT("Block ID: %lld bits\n"), blockID.QuadPart)); for(j = 0; j < (blockIVLength / 8); j++) { DEBUGOUTMAINDRV(DEBUGLEV_VERBOSE_INFO, (TEXT("----- Block IV [%.2d]: %.2x\n"), j, blockIV[j])); } useBytes = (min(blockIVLength, devContext->VolumeIVLength) / 8); DEBUGOUTMAINDRV(DEBUGLEV_VERBOSE_INFO, (TEXT("XORing block IV with %d bits of volume IV...\n"), (useBytes * 8))); for(i = 0; i < useBytes; i++) { blockIV[i] ^= devContext->VolumeIV[i]; } if (useBytes > 0) { for(j = 0; j < (blockIVLength / 8); j++) { DEBUGOUTMAINDRV(DEBUGLEV_VERBOSE_INFO, (TEXT("----- Actual block IV [%.2d]: %.2x\n"), j, blockIV[j])); } } } else { DEBUGOUTMAINDRV(DEBUGLEV_INFO, (TEXT("IV generation failed (status: %d)\n"), status)); } } // ELSE PART - if (blockIVLength <= 0) DEBUGOUTMAINDRV(DEBUGLEV_VERBOSE_EXIT, (TEXT("GenerateBlockIV\n"))); return status; }
// ========================================================================= // Generate block IV: ESS_IV // From Linux's dm_crypt kernel source (drivers/md/dm-crypt.c): // * ess_iv: "encrypted sector|salt initial vector", the sector number is // * encrypted with the bulk cipher using a salt as key. The salt // * should be derived from the bulk cipher's key via hashing. // i.e.: // Let salt = malloc(IV length) bits of memory (This is done when first mounting) // Set salt to be hash(key) (This is done when first mounting) // Encrypt the n-bit block ID using the above salt as the key // - Note: Linux's dm-crypt volumes use 64 bit block IDs // Use the result as the IV NTSTATUS GenerateBlockIV_ESSIV( IN DEVICE_CONTEXT* devContext, IN LARGE_INTEGER blockID, IN unsigned int blockIDBits, // The number of bits in blockID to be used // Set to either 32 or 64 bits IN unsigned int blockIVLength, // The size of the required IV (and length of // "blockIV"), in bits OUT unsigned char* blockIV // Pointer to where the IV should be written // Note: Caller must pre-initialise to 0x00s ) { NTSTATUS status; unsigned char cypherInput[FREEOTFE_MAX_CYPHER_BLOCKSIZE / 8]; // Divide by 8 to get bytes from bits unsigned char cypherOutput[FREEOTFE_MAX_CYPHER_BLOCKSIZE / 8]; // Divide by 8 to get bytes from bits unsigned int encryptLengthBytes; unsigned int useBitsFromHash; DEBUGOUTMAINDRV(DEBUGLEV_VERBOSE_ENTER, (TEXT("GenerateBlockIV_ESSIV\n"))); status = STATUS_SUCCESS; // Generate the IV... DEBUGOUTMAINDRV(DEBUGLEV_VERBOSE_INFO, (TEXT("%d bit block IDs being used\n"), blockIDBits)); DEBUGOUTMAINDRV(DEBUGLEV_VERBOSE_INFO, (TEXT("Block ID is: %lld\n"), blockID.QuadPart)); FREEOTFE_MEMZERO(&cypherInput, sizeof(cypherInput)); if (blockIDBits == 32) { // Cast the IV (unsigned cast) as a ptr to a ULONG, then dereference to set *(ULONG*)cypherInput = blockID.LowPart; } else if (blockIDBits == 64) { // Cast the IV (unsigned cast) as a ptr to a ULONG, then dereference to set *(ULONG*)cypherInput = blockID.LowPart; // Cast the IV (unsigned cast) as a ptr to a ULONG, then dereference to set // The IV is offset by sizeof(ULONG), since the IV is in unsigned chars, // before it is cast *(ULONG*)(cypherInput+sizeof(ULONG)) = blockID.HighPart; } else { DEBUGOUTMAINDRV(DEBUGLEV_ERROR, (TEXT("blockIDBits must be set to either 32 or 64 (set to: %d)\n"), blockIDBits)); status = STATUS_INTERNAL_ERROR; } encryptLengthBytes = (devContext->IVCypher.Details.BlockSize / 8); // Allow for IV cyphers with a variable length blocksize if (devContext->IVCypher.Details.BlockSize < 0) { encryptLengthBytes = (blockIDBits / 8); } if (NT_SUCCESS(status)) { // Note: We use a NULL IV for this encryption if (devContext->IVCypher.FnEncryptSector != NULL) { status = devContext->IVCypher.FnEncryptSector( &devContext->IVCypher.CypherGUID, blockID, devContext->EncryptionBlockSize, devContext->ESSIVKeyLength, (char*)devContext->ESSIVKey, (char*)devContext->ESSIVKeyASCII, 0, NULL, encryptLengthBytes, (char*)&cypherInput, (char*)&cypherOutput ); } else if (devContext->IVCypher.FnEncrypt != NULL) { status = devContext->IVCypher.FnEncrypt( &devContext->IVCypher.CypherGUID, devContext->ESSIVKeyLength, (char*)devContext->ESSIVKey, (char*)devContext->ESSIVKeyASCII, 0, NULL, encryptLengthBytes, (char*)&cypherInput, (char*)&cypherOutput ); } else { DEBUGOUTMAINDRV(DEBUGLEV_ERROR, (TEXT("No encryption function?!\n"))); status = STATUS_INVALID_PARAMETER; } if (!(NT_SUCCESS(status))) { DEBUGOUTMAINDRV(DEBUGLEV_ERROR, (TEXT("ESSIV encrypt failed\n"))); } } if (!(NT_SUCCESS(status))) { DEBUGOUTMAINDRV(DEBUGLEV_ERROR, (TEXT("Failed to ESSIV to form IV.\n"))); } else { // The number of useful bits we can take from the hash useBitsFromHash = (min(blockIVLength, (encryptLengthBytes * 8))); DEBUGOUTMAINDRV(DEBUGLEV_VERBOSE_INFO, (TEXT("Number of useful bits from cypher: %d\n"), useBitsFromHash)); // If the block IV is larger than the number of bits the hash returns, ensure that // the remainder of the block IV is blanked if (useBitsFromHash < blockIVLength) { FREEOTFE_MEMZERO(blockIV, (blockIVLength / 8)); } // Copy the first 'n' bits of the hash to be the block IV FREEOTFE_MEMCPY( blockIV, &cypherOutput, (useBitsFromHash / 8) // Divide by 8 to get bytes from bits ); } DEBUGOUTMAINDRV(DEBUGLEV_VERBOSE_EXIT, (TEXT("GenerateblockIV_ESSIV\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; // libtomcrypt can't handle NULL IVs in CBC mode - it ASSERTs that IV != NULL char ltcNullIV[FREEOTFE_MAX_CYPHER_BLOCKSIZE]; int cipher; symmetric_CBC *cbc; int errnum; DEBUGOUTCYPHERIMPL(DEBUGLEV_ENTER, (TEXT("ImpCypherDecryptData\n"))); if (!( (IsEqualGUID(&CIPHER_GUID_CAST5, CypherGUID)) )) { DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unsupported cipher GUID passed in.\n"))); status = STATUS_INVALID_PARAMETER; } // libtomcrypt can't handle NULL IVs in CBC mode - it ASSERTs that IV != NULL if ( (IVLength == 0) || (IV == NULL) ) { FREEOTFE_MEMZERO(<cNullIV, sizeof(ltcNullIV)); IV = (char*)<cNullIV; } cbc = FREEOTFE_MEMALLOC(sizeof(symmetric_CBC)); FREEOTFE_MEMZERO(cbc, sizeof(symmetric_CBC)); if NT_SUCCESS(status) { status = InitLTCCypher(&cipher); } if NT_SUCCESS(status) { // Start a CBC session if ((errnum = cbc_start( cipher, IV, Key, (KeyLength/8), 0, cbc )) != CRYPT_OK) { status = STATUS_UNSUCCESSFUL; DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to start CBC session (errnum: %d)\n"), errnum)); } else { if ((errnum = cbc_decrypt( CyphertextData, PlaintextData, CyphertextLength, cbc )) != CRYPT_OK) { DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to encrypt/decrypt block (errnum: %d)\n"), errnum)); status = STATUS_UNSUCCESSFUL; } cbc_done(cbc); } } SecZeroMemory(cbc, sizeof(symmetric_CBC)); FREEOTFE_FREE(cbc); DEBUGOUTCYPHERIMPL(DEBUGLEV_EXIT, (TEXT("ImpCypherDecryptData\n"))); return status; }
// ========================================================================= // Cypher driver init function // driverInfo - The structure to be initialized NTSTATUS ImpCypherDriverExtDetailsInit_v3( IN OUT CYPHER_DRIVER_INFO_v3* driverInfo ) { NTSTATUS status = STATUS_SUCCESS; int idx = -1; int blockSizeBits; DEBUGOUTCYPHERIMPL(DEBUGLEV_ENTER, (TEXT("ImpCypherDriverExtDetailsInit_v3\n"))); blockSizeBits = (twofish_desc.block_length * 8); // -- POPULATE DRIVER IDENTIFICATION -- FREEOTFE_MEMZERO(driverInfo->DriverTitle, sizeof(driverInfo->DriverTitle)); FREEOTFE_MEMCPY( driverInfo->DriverTitle, DRIVER_TITLE, strlen(DRIVER_TITLE) ); driverInfo->DriverGUID = DRIVER_GUID; driverInfo->DriverVersionID = DRIVER_CYPHER_VERSION; // -- POPULATE cyphers SUPPORTED -- driverInfo->CypherCount = CYPHERS_SUPPORTED; driverInfo->CypherDetails = FREEOTFE_MEMCALLOC( sizeof(CYPHER_v3), driverInfo->CypherCount ); // -- Twofish-256 CBC -- idx++; FREEOTFE_MEMZERO( driverInfo->CypherDetails[idx].Title, sizeof(driverInfo->CypherDetails[idx].Title) ); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_TWOFISH_256_CBC, strlen(DRIVER_CIPHER_TITLE_TWOFISH_256_CBC) ); driverInfo->CypherDetails[idx].BlockSize = blockSizeBits; driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_TWOFISH_256_CBC; DetermineCypherDetails( &driverInfo->CypherDetails[idx].CypherGUID, &driverInfo->CypherDetails[idx].KeySizeUnderlying, &driverInfo->CypherDetails[idx].Mode ); driverInfo->CypherDetails[idx].KeySizeRequired = driverInfo->CypherDetails[idx].KeySizeUnderlying; // -- Twofish-256 XTS -- idx++; FREEOTFE_MEMZERO( driverInfo->CypherDetails[idx].Title, sizeof(driverInfo->CypherDetails[idx].Title) ); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_TWOFISH_256_XTS, strlen(DRIVER_CIPHER_TITLE_TWOFISH_256_XTS) ); driverInfo->CypherDetails[idx].BlockSize = blockSizeBits; driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_TWOFISH_256_XTS; DetermineCypherDetails( &driverInfo->CypherDetails[idx].CypherGUID, &driverInfo->CypherDetails[idx].KeySizeUnderlying, &driverInfo->CypherDetails[idx].Mode ); driverInfo->CypherDetails[idx].KeySizeRequired = (2 * driverInfo->CypherDetails[idx].KeySizeUnderlying); // -- Twofish-256 LRW -- idx++; FREEOTFE_MEMZERO( driverInfo->CypherDetails[idx].Title, sizeof(driverInfo->CypherDetails[idx].Title) ); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_TWOFISH_256_LRW, strlen(DRIVER_CIPHER_TITLE_TWOFISH_256_LRW) ); driverInfo->CypherDetails[idx].BlockSize = blockSizeBits; driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_TWOFISH_256_LRW; DetermineCypherDetails( &driverInfo->CypherDetails[idx].CypherGUID, &driverInfo->CypherDetails[idx].KeySizeUnderlying, &driverInfo->CypherDetails[idx].Mode ); driverInfo->CypherDetails[idx].KeySizeRequired = driverInfo->CypherDetails[idx].KeySizeUnderlying + driverInfo->CypherDetails[idx].BlockSize; // -- Twofish-192 CBC -- idx++; FREEOTFE_MEMZERO( driverInfo->CypherDetails[idx].Title, sizeof(driverInfo->CypherDetails[idx].Title) ); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_TWOFISH_192_CBC, strlen(DRIVER_CIPHER_TITLE_TWOFISH_192_CBC) ); driverInfo->CypherDetails[idx].BlockSize = blockSizeBits; driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_TWOFISH_192_CBC; DetermineCypherDetails( &driverInfo->CypherDetails[idx].CypherGUID, &driverInfo->CypherDetails[idx].KeySizeUnderlying, &driverInfo->CypherDetails[idx].Mode ); driverInfo->CypherDetails[idx].KeySizeRequired = driverInfo->CypherDetails[idx].KeySizeUnderlying; // -- Twofish-192 XTS -- idx++; FREEOTFE_MEMZERO( driverInfo->CypherDetails[idx].Title, sizeof(driverInfo->CypherDetails[idx].Title) ); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_TWOFISH_192_XTS, strlen(DRIVER_CIPHER_TITLE_TWOFISH_192_XTS) ); driverInfo->CypherDetails[idx].BlockSize = blockSizeBits; driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_TWOFISH_192_XTS; DetermineCypherDetails( &driverInfo->CypherDetails[idx].CypherGUID, &driverInfo->CypherDetails[idx].KeySizeUnderlying, &driverInfo->CypherDetails[idx].Mode ); driverInfo->CypherDetails[idx].KeySizeRequired = (2 * driverInfo->CypherDetails[idx].KeySizeUnderlying); // -- Twofish-192 LRW -- idx++; FREEOTFE_MEMZERO( driverInfo->CypherDetails[idx].Title, sizeof(driverInfo->CypherDetails[idx].Title) ); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_TWOFISH_192_LRW, strlen(DRIVER_CIPHER_TITLE_TWOFISH_192_LRW) ); driverInfo->CypherDetails[idx].BlockSize = blockSizeBits; driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_TWOFISH_192_LRW; DetermineCypherDetails( &driverInfo->CypherDetails[idx].CypherGUID, &driverInfo->CypherDetails[idx].KeySizeUnderlying, &driverInfo->CypherDetails[idx].Mode ); driverInfo->CypherDetails[idx].KeySizeRequired = driverInfo->CypherDetails[idx].KeySizeUnderlying + driverInfo->CypherDetails[idx].BlockSize; // -- Twofish-128 CBC -- idx++; FREEOTFE_MEMZERO( driverInfo->CypherDetails[idx].Title, sizeof(driverInfo->CypherDetails[idx].Title) ); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_TWOFISH_128_CBC, strlen(DRIVER_CIPHER_TITLE_TWOFISH_128_CBC) ); driverInfo->CypherDetails[idx].BlockSize = blockSizeBits; driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_TWOFISH_128_CBC; DetermineCypherDetails( &driverInfo->CypherDetails[idx].CypherGUID, &driverInfo->CypherDetails[idx].KeySizeUnderlying, &driverInfo->CypherDetails[idx].Mode ); driverInfo->CypherDetails[idx].KeySizeRequired = driverInfo->CypherDetails[idx].KeySizeUnderlying; // -- Twofish-128 XTS -- idx++; FREEOTFE_MEMZERO( driverInfo->CypherDetails[idx].Title, sizeof(driverInfo->CypherDetails[idx].Title) ); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_TWOFISH_128_XTS, strlen(DRIVER_CIPHER_TITLE_TWOFISH_128_XTS) ); driverInfo->CypherDetails[idx].BlockSize = blockSizeBits; driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_TWOFISH_128_XTS; DetermineCypherDetails( &driverInfo->CypherDetails[idx].CypherGUID, &driverInfo->CypherDetails[idx].KeySizeUnderlying, &driverInfo->CypherDetails[idx].Mode ); driverInfo->CypherDetails[idx].KeySizeRequired = (2 * driverInfo->CypherDetails[idx].KeySizeUnderlying); // -- Twofish-128 LRW -- idx++; FREEOTFE_MEMZERO( driverInfo->CypherDetails[idx].Title, sizeof(driverInfo->CypherDetails[idx].Title) ); FREEOTFE_MEMCPY( driverInfo->CypherDetails[idx].Title, DRIVER_CIPHER_TITLE_TWOFISH_128_LRW, strlen(DRIVER_CIPHER_TITLE_TWOFISH_128_LRW) ); driverInfo->CypherDetails[idx].BlockSize = blockSizeBits; driverInfo->CypherDetails[idx].VersionID = DRIVER_CYPHER_IMPL_VERSION; driverInfo->CypherDetails[idx].CypherGUID = CIPHER_GUID_TWOFISH_128_LRW; DetermineCypherDetails( &driverInfo->CypherDetails[idx].CypherGUID, &driverInfo->CypherDetails[idx].KeySizeUnderlying, &driverInfo->CypherDetails[idx].Mode ); driverInfo->CypherDetails[idx].KeySizeRequired = driverInfo->CypherDetails[idx].KeySizeUnderlying + driverInfo->CypherDetails[idx].BlockSize; DEBUGOUTCYPHERIMPL(DEBUGLEV_EXIT, (TEXT("ImpCypherDriverExtDetailsInit_v3\n"))); return status; }
// ========================================================================= // Encrypt/Decrypt 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 ImpCypherCryptData( IN GUID* CypherGUID, IN LARGE_INTEGER SectorID, 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 BOOLEAN encryptNotDecrypt, // TRUE = encrypt; FALSE = decrypt IN int InLength, // In bytes IN FREEOTFEBYTE* InData, OUT FREEOTFEBYTE* OutData ) { NTSTATUS status = STATUS_SUCCESS; // libtomcrypt can't handle NULL IVs in CBC mode - it ASSERTs that IV != NULL char ltcNullIV[FREEOTFE_MAX_CYPHER_BLOCKSIZE]; int cipher; symmetric_CBC *cbc; symmetric_LRW *lrw; symmetric_xts *xts; int errnum; CYPHER_MODE mode; int keySizeUnderlying; LARGE_INTEGER blockID64; INTEGER_128 blockID128; DEBUGOUTCYPHERIMPL(DEBUGLEV_ENTER, (TEXT("ImpCypherDecryptData\n"))); status = DetermineCypherDetails( CypherGUID, &keySizeUnderlying, &mode ); // libtomcrypt can't handle NULL IVs in CBC mode - it ASSERTs that IV != NULL if ( (IVLength == 0) || (IV == NULL) ) { FREEOTFE_MEMZERO(<cNullIV, sizeof(ltcNullIV)); IV = (char*)<cNullIV; } // Sanity check on key supplied if NT_SUCCESS(status) { switch (mode) { case CYPHER_MODE_CBC: { if (KeyLength != keySizeUnderlying) { status = STATUS_INVALID_PARAMETER; } break; } case CYPHER_MODE_XTS: { if (KeyLength != (2 * keySizeUnderlying)) { status = STATUS_INVALID_PARAMETER; } break; } case CYPHER_MODE_LRW: { if (KeyLength != (keySizeUnderlying + (twofish_desc.block_length * 8))) { status = STATUS_INVALID_PARAMETER; } break; } } } if NT_SUCCESS(status) { status = InitLTCCypher(&cipher); } if NT_SUCCESS(status) { switch (mode) { case CYPHER_MODE_CBC: { cbc = FREEOTFE_MEMALLOC(sizeof(symmetric_CBC)); FREEOTFE_MEMZERO(cbc, sizeof(symmetric_CBC)); // Start a CBC session if ((errnum = cbc_start( cipher, IV, Key, (keySizeUnderlying/8), 0, cbc )) != CRYPT_OK) { status = STATUS_UNSUCCESSFUL; DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to start CBC session (errnum: %d)\n"), errnum)); } else { if (encryptNotDecrypt) { if ((errnum = cbc_encrypt( InData, OutData, InLength, cbc )) != CRYPT_OK) { DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to encrypt block (errnum: %d)\n"), errnum)); status = STATUS_UNSUCCESSFUL; } } else { if ((errnum = cbc_decrypt( InData, OutData, InLength, cbc )) != CRYPT_OK) { DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to decrypt block (errnum: %d)\n"), errnum)); status = STATUS_UNSUCCESSFUL; } } cbc_done(cbc); } SecZeroMemory(cbc, sizeof(symmetric_CBC)); FREEOTFE_FREE(cbc); break; } case CYPHER_MODE_LRW: { lrw = FREEOTFE_MEMALLOC(sizeof(symmetric_LRW)); FREEOTFE_MEMZERO(lrw, sizeof(symmetric_LRW)); // Generate index in correct format // LRW uses: // *) The block index (i.e. the number of 128 bit blocks) // *) The first block has block index 1 - not 0! // *) Bigendian format // Note: LTC increments this itself as it processes each block SectorIDToBlockIdx_64Bit(SectorID, SectorSize, &blockID64); LARGE_INTEGER__To__INTEGER_128_BigEndian( blockID64, blockID128 ); IV = blockID128; // Start a LRW session if ((errnum = lrw_start( cipher, IV, Key, (keySizeUnderlying/8), // 128 bits tweak key begins after the // cypher key (Key + (keySizeUnderlying/8)), 0, lrw )) != CRYPT_OK) { status = STATUS_UNSUCCESSFUL; DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to start LRW session (errnum: %d)\n"), errnum)); } else { if (encryptNotDecrypt) { if ((errnum = lrw_encrypt( InData, OutData, InLength, lrw )) != CRYPT_OK) { DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to encrypt block (errnum: %d)\n"), errnum)); status = STATUS_UNSUCCESSFUL; } } else { if ((errnum = lrw_decrypt( InData, OutData, InLength, lrw )) != CRYPT_OK) { DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to decrypt block (errnum: %d)\n"), errnum)); status = STATUS_UNSUCCESSFUL; } } lrw_done(lrw); } SecZeroMemory(lrw, sizeof(symmetric_LRW)); FREEOTFE_FREE(lrw); break; } case CYPHER_MODE_XTS: { xts = FREEOTFE_MEMALLOC(sizeof(symmetric_xts)); FREEOTFE_MEMZERO(xts, sizeof(symmetric_xts)); // 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 ); // Start an XTS session if ((errnum = xts_start( cipher, Key, &(Key[keySizeUnderlying/8]), (keySizeUnderlying/8), 0, xts )) != CRYPT_OK) { status = STATUS_UNSUCCESSFUL; DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to start XTS session (errnum: %d)\n"), errnum)); } else { if (encryptNotDecrypt) { if ((errnum = xts_encrypt( InData, InLength, OutData, blockID128, xts )) != CRYPT_OK) { DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to encrypt block (errnum: %d)\n"), errnum)); status = STATUS_UNSUCCESSFUL; } } else { if ((errnum = xts_decrypt( InData, InLength, OutData, blockID128, xts )) != CRYPT_OK) { DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unable to decrypt block (errnum: %d)\n"), errnum)); status = STATUS_UNSUCCESSFUL; } } xts_done(xts); } SecZeroMemory(xts, sizeof(symmetric_xts)); FREEOTFE_FREE(xts); break; } } } DEBUGOUTCYPHERIMPL(DEBUGLEV_EXIT, (TEXT("ImpCypherDecryptData\n"))); return status; }
// ========================================================================= // Hash driver init function // driverInfo - The structure to be initialized NTSTATUS ImpHashDriverExtDetailsInit( IN OUT HASH_DRIVER_INFO* driverInfo ) { NTSTATUS status = STATUS_SUCCESS; int idx = -1; DEBUGOUTHASHIMPL(DEBUGLEV_ENTER, (TEXT("ImpHashDriverExtDetailsInit\n"))); // -- POPULATE DRIVER IDENTIFICATION -- FREEOTFE_MEMZERO(driverInfo->DriverTitle, sizeof(driverInfo->DriverTitle)); FREEOTFE_MEMCPY( driverInfo->DriverTitle, DRIVER_TITLE, strlen(DRIVER_TITLE) ); driverInfo->DriverGUID = DRIVER_GUID; driverInfo->DriverVersionID = DRIVER_HASH_VERSION; // -- POPULATE HASHES SUPPORTED -- driverInfo->HashCount = HASHES_SUPPORTED; driverInfo->HashDetails = FREEOTFE_MEMCALLOC( sizeof(HASH), driverInfo->HashCount ); // -- SHA-512 -- idx++; FREEOTFE_MEMZERO(driverInfo->HashDetails[idx].Title, MAX_HASH_TITLE); FREEOTFE_MEMCPY( driverInfo->HashDetails[idx].Title, DRIVER_HASH_TITLE_SHA512, strlen(DRIVER_HASH_TITLE_SHA512) ); driverInfo->HashDetails[idx].Length = (sha512_desc.hashsize * 8); driverInfo->HashDetails[idx].BlockSize = (sha512_desc.blocksize * 8); driverInfo->HashDetails[idx].VersionID = DRIVER_HASH_IMPL_VERSION; driverInfo->HashDetails[idx].HashGUID = HASH_GUID_SHA512; // -- SHA-384 -- idx++; FREEOTFE_MEMZERO(driverInfo->HashDetails[idx].Title, MAX_HASH_TITLE); FREEOTFE_MEMCPY( driverInfo->HashDetails[idx].Title, DRIVER_HASH_TITLE_SHA384, strlen(DRIVER_HASH_TITLE_SHA384) ); driverInfo->HashDetails[idx].Length = (sha384_desc.hashsize * 8); driverInfo->HashDetails[idx].BlockSize = (sha384_desc.blocksize * 8); driverInfo->HashDetails[idx].VersionID = DRIVER_HASH_IMPL_VERSION; driverInfo->HashDetails[idx].HashGUID = HASH_GUID_SHA384; // -- SHA-256 -- idx++; FREEOTFE_MEMZERO(driverInfo->HashDetails[idx].Title, MAX_HASH_TITLE); FREEOTFE_MEMCPY( driverInfo->HashDetails[idx].Title, DRIVER_HASH_TITLE_SHA256, strlen(DRIVER_HASH_TITLE_SHA256) ); driverInfo->HashDetails[idx].Length = (sha256_desc.hashsize * 8); driverInfo->HashDetails[idx].BlockSize = (sha256_desc.blocksize * 8); driverInfo->HashDetails[idx].VersionID = DRIVER_HASH_IMPL_VERSION; driverInfo->HashDetails[idx].HashGUID = HASH_GUID_SHA256; // -- SHA-224 -- idx++; FREEOTFE_MEMZERO(driverInfo->HashDetails[idx].Title, MAX_HASH_TITLE); FREEOTFE_MEMCPY( driverInfo->HashDetails[idx].Title, DRIVER_HASH_TITLE_SHA224, strlen(DRIVER_HASH_TITLE_SHA224) ); driverInfo->HashDetails[idx].Length = (sha224_desc.hashsize * 8); driverInfo->HashDetails[idx].BlockSize = (sha224_desc.blocksize * 8); driverInfo->HashDetails[idx].VersionID = DRIVER_HASH_IMPL_VERSION; driverInfo->HashDetails[idx].HashGUID = HASH_GUID_SHA224; // -- SHA-1 -- idx++; FREEOTFE_MEMZERO(driverInfo->HashDetails[idx].Title, MAX_HASH_TITLE); FREEOTFE_MEMCPY( driverInfo->HashDetails[idx].Title, DRIVER_HASH_TITLE_SHA1, strlen(DRIVER_HASH_TITLE_SHA1) ); driverInfo->HashDetails[idx].Length = (sha1_desc.hashsize * 8); driverInfo->HashDetails[idx].BlockSize = (sha1_desc.blocksize * 8); driverInfo->HashDetails[idx].VersionID = DRIVER_HASH_IMPL_VERSION; driverInfo->HashDetails[idx].HashGUID = HASH_GUID_SHA1; DEBUGOUTHASHIMPL(DEBUGLEV_EXIT, (TEXT("ImpHashDriverExtDetailsInit\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; }