// ========================================================================= // This routine is the driver's entry point, called by the I/O system // to load the driver. The driver's entry points are initialized. // In DBG mode, this routine also examines the registry for special // debug parameters. NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING devDirName; OBJECT_ATTRIBUTES dirObjAttribs; PDEVICE_OBJECT mainDevObj; PDEVICE_EXTENSION mainDevExt; // The following debug handling was ripped from the MS DDK "floppy.c" // example #if DBG // We use this to query into the registry as to whether we // should break at driver entry. RTL_QUERY_REGISTRY_TABLE paramTable[3]; ULONG default_ShouldBreak = 0; // Default to 0; no break // ULONG default_DebugLevel = 0xFFFFFFFF; // Default to all on ULONG default_DebugLevel = 0x0000001F; // All except verbose debug ULONG debugLevel = 0; ULONG shouldBreak = 0; PWCHAR path; ULONG pathLength; // Since the registry path parameter is a "counted" UNICODE string, it // might not be zero terminated. For a very short time allocate memory // to hold the registry path zero terminated so that we can use it to // delve into the registry. // // NOTE NOTE!!!! This is not an architected way of breaking into // a driver. It happens to work for this driver because the original // DDK example code for DriverEntry happened to be written in this manner. pathLength = RegistryPath->Length + sizeof(WCHAR); if (path = FREEOTFE_MEMALLOC(pathLength)) { SecZeroMemory(¶mTable[0], sizeof(paramTable)); SecZeroMemory(path, pathLength); RtlMoveMemory( path, RegistryPath->Buffer, RegistryPath->Length ); paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; paramTable[0].Name = L"BreakOnEntry"; paramTable[0].EntryContext = &shouldBreak; paramTable[0].DefaultType = REG_DWORD; paramTable[0].DefaultData = &default_ShouldBreak; paramTable[0].DefaultLength = sizeof(ULONG); paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; paramTable[1].Name = L"DebugLevel"; paramTable[1].EntryContext = &debugLevel; paramTable[1].DefaultType = REG_DWORD; paramTable[1].DefaultData = &default_DebugLevel; paramTable[1].DefaultLength = sizeof(ULONG); if (!(NT_SUCCESS(RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, path, ¶mTable[0], NULL, NULL)))) { shouldBreak = default_ShouldBreak; debugLevel = default_DebugLevel; } FREEOTFE_FREE(path); } FreeOTFEDebugLevel = debugLevel; DEBUGOUTHASHDRV(DEBUGLEV_INFO, ("Debug level: %d\n", FreeOTFEDebugLevel)); if (shouldBreak == 1) { DbgBreakPoint(); } #endif DEBUGOUTHASHDRV(DEBUGLEV_ENTER, ("DriverEntry\n")); // Create main device dir DEBUGOUTHASHDRV(DEBUGLEV_INFO, ("Creating dir object (main)...\n")); status = CreateDeviceDir( DEVICE_FREEOTFE_ROOT, &DirFreeOTFERoot ); if (!(NT_SUCCESS(status))) { DEBUGOUTHASHDRV(DEBUGLEV_ERROR, ("Unable to CreateDeviceDir (main)\n")); return status; } // Create hash device dir DEBUGOUTHASHDRV(DEBUGLEV_INFO, ("Creating dir object (hash)...\n")); status = CreateDeviceDir( DEVICE_HASH_DIR_NAME, &DirFreeOTFEHash ); if (!(NT_SUCCESS(status))) { DEBUGOUTHASHDRV(DEBUGLEV_ERROR, ("Unable to CreateDeviceDir (hash)\n")); ZwClose(DirFreeOTFERoot); return status; } // Create main device DEBUGOUTHASHDRV(DEBUGLEV_INFO, ("Creating main device...\n")); status = CreateDevice(DriverObject, &mainDevObj); if (!(NT_SUCCESS(status))) { DEBUGOUTHASHDRV(DEBUGLEV_ERROR, ("Call to CreateDevice FAILED.\n")); return status; } // Store the device dir handle for closure on unload mainDevExt = (PDEVICE_EXTENSION)mainDevObj->DeviceExtension; // Initialize the driver object with this driver's entry points. DriverObject->MajorFunction[IRP_MJ_CREATE] = FreeOTFE_MF_DispatchCreate; DriverObject->MajorFunction[IRP_MJ_CLOSE] = FreeOTFE_MF_DispatchClose; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FreeOTFE_MF_DispatchDeviceControl; DriverObject->DriverUnload = DriverUnload; DEBUGOUTHASHDRV(DEBUGLEV_EXIT, ("DriverEntry\n")); return status; }
// ========================================================================= // IOCTL to hash data NTSTATUS IOCTL_FreeOTFEHashIOCTL_Hash( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS status; PIO_STACK_LOCATION irpSp; PDIOC_HASH_DATA_IN DIOCBufferIn; PDIOC_HASH_DATA_OUT DIOCBufferOut; FREEOTFEBYTE* tmpOutput; unsigned int tmpLengthBits; // In *bits* int userBufferSizeBytes; // In *bytes* DEBUGOUTHASHDRV(DEBUGLEV_ENTER, ("IOCTL_FreeOTFEHashIOCTL_Hash\n")); irpSp = IoGetCurrentIrpStackLocation(Irp); DIOCBufferIn = (PDIOC_HASH_DATA_IN)Irp->AssociatedIrp.SystemBuffer; DIOCBufferOut = (PDIOC_HASH_DATA_OUT)Irp->AssociatedIrp.SystemBuffer; // Check size of INPUT buffer // Minimum check... // (Done first in order to ensure that we can later access "length" parts // for actual check) if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*DIOCBufferIn)-sizeof(DIOCBufferIn->Data)) { DEBUGOUTHASHDRV(DEBUGLEV_ERROR, ("inBuffer size wrong size (expect min: %d; got: %d)\n", sizeof(*DIOCBufferIn)-sizeof(DIOCBufferIn->Data), irpSp->Parameters.DeviceIoControl.InputBufferLength )); status = STATUS_INVALID_BUFFER_SIZE; return status; } // Actual check... if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*DIOCBufferIn)+(DIOCBufferIn->DataLength/8)-sizeof(DIOCBufferIn->Data)) { DEBUGOUTHASHDRV(DEBUGLEV_ERROR, ("inBuffer size wrong size (expect actual: %d; got: %d)\n", sizeof(*DIOCBufferIn)+(DIOCBufferIn->DataLength/8)-sizeof(DIOCBufferIn->Data), irpSp->Parameters.DeviceIoControl.InputBufferLength )); status = STATUS_INVALID_BUFFER_SIZE; return status; } // Check size of OUTPUT buffer // Minimum check... // (Done first in order to ensure that we can later access "length" parts // for actual check) if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(*DIOCBufferOut)-sizeof(DIOCBufferOut->Hash)) { DEBUGOUTHASHDRV(DEBUGLEV_ERROR, ("outBuffer size wrong size (expect min: %d; got: %d)\n", sizeof(*DIOCBufferOut)-sizeof(DIOCBufferOut->Hash), irpSp->Parameters.DeviceIoControl.OutputBufferLength )); status = STATUS_INVALID_BUFFER_SIZE; return status; } // Request valid so far, process... // We have to allocate a buffer to hold the output, before it can be copied // out to the output buffer; otherwise, the input buffer gets garbled as // data is written to the output buffer // Match the user's buffer; if it's too small, the operation will kick // it out // This calculates the size of the variable part of the struct // Yes, this should be correct: The total size of the user's output buffer, // less the size of the struct - but then plus the size of // the variable parts reserved within the buffer userBufferSizeBytes = (irpSp->Parameters.DeviceIoControl.OutputBufferLength) - sizeof(*DIOCBufferOut) + sizeof(DIOCBufferOut->Hash); tmpOutput = FREEOTFE_MEMALLOC(userBufferSizeBytes); // The size of the buffer in bits; the algorithm will read this value, then // overwrite it with the actual size of the output (in bits) tmpLengthBits = (userBufferSizeBytes * 8); DEBUGOUTHASHDRV(DEBUGLEV_INFO, ("Input buffer length is: %d bits\n", DIOCBufferIn->DataLength)); DEBUGOUTHASHDRV(DEBUGLEV_INFO, ("Allocated output buffer for: %d bits\n", tmpLengthBits)); DEBUGOUTHASHDRV(DEBUGLEV_INFO, ("About to process...\n")); status = ImpHashHashData( &DIOCBufferIn->HashGUID, DIOCBufferIn->DataLength, // In bits (FREEOTFEBYTE*)&DIOCBufferIn->Data, &tmpLengthBits, // In bits (FREEOTFEBYTE*)tmpOutput ); DEBUGOUTHASHDRV(DEBUGLEV_INFO, ("Done with status: %d (want status: %d)\n", status, STATUS_SUCCESS)); if (NT_SUCCESS(status)) { DEBUGOUTHASHDRV(DEBUGLEV_INFO, ("tmp buffer was: %d bits, output was %d bits\n", (userBufferSizeBytes * 8), tmpLengthBits)); // Actual check... // Ensure output DIOC butter is large enough to store the output // Note that we can't carry out this check until we've created the // output value, in case the algorithm used produces variable length // output if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(*DIOCBufferOut)+(tmpLengthBits/8)-sizeof(DIOCBufferOut->Hash)) { DEBUGOUTHASHDRV(DEBUGLEV_ERROR, ("outBuffer size wrong size (expect actual: %d; got: %d)\n", sizeof(*DIOCBufferOut)+(tmpLengthBits/8)-sizeof(DIOCBufferOut->Hash), irpSp->Parameters.DeviceIoControl.OutputBufferLength )); status = STATUS_INVALID_BUFFER_SIZE; } else { RtlCopyMemory(&DIOCBufferOut->Hash, tmpOutput, (tmpLengthBits / 8)); DIOCBufferOut->HashLength = tmpLengthBits; Irp->IoStatus.Information = sizeof(*DIOCBufferOut)+(tmpLengthBits/8)-sizeof(DIOCBufferOut->Hash); } } else { DEBUGOUTHASHDRV(DEBUGLEV_ERROR, ("FAILED")); } SecZeroMemory(tmpOutput, userBufferSizeBytes); FREEOTFE_FREE(tmpOutput); DEBUGOUTHASHDRV(DEBUGLEV_EXIT, ("IOCTL_FreeOTFEHashIOCTL_Hash\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; unsigned int blockLength; DEBUGOUTCYPHERIMPL(DEBUGLEV_ENTER, (TEXT("ImpCypherDecryptData\n"))); cbc = FREEOTFE_MEMALLOC(sizeof(symmetric_CBC)); FREEOTFE_MEMZERO(cbc, sizeof(symmetric_CBC)); if (IsEqualGUID(&CIPHER_GUID_DES, CypherGUID)) { status = InitLTCDESCypher(&cipher); blockLength = des_desc.block_length; } else if (IsEqualGUID(&CIPHER_GUID_3DES, CypherGUID)) { status = InitLTC3DESCypher(&cipher); blockLength = des3_desc.block_length; } else { 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; } 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; }