// ========================================================================= // Initialize libtomcrypt cypher NTSTATUS InitLTCCypher( OUT int *cipher ) { NTSTATUS status = STATUS_CRYPTO_SYSTEM_INVALID; DEBUGOUTCYPHERIMPL(DEBUGLEV_ENTER, (TEXT("InitLTCCypher\n"))); // Initialize cipher *cipher = register_cipher(&cast5_desc); if (*cipher == -1) { DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Could not register cipher\n"))); } else { *cipher = find_cipher("cast5"); if (*cipher == -1) { DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Could not find cipher\n"))); } else { status = STATUS_SUCCESS; } } DEBUGOUTCYPHERIMPL(DEBUGLEV_EXIT, (TEXT("InitLTCCypher\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; 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; }
// ========================================================================= // Internal function to carry out actual XOR encryption NTSTATUS _xor_data( IN int KeyLength, // In bits IN FREEOTFEBYTE* Key, IN int DataLength, // In bytes IN FREEOTFEBYTE* InData, OUT FREEOTFEBYTE* OutData ) { NTSTATUS status = STATUS_SUCCESS; int i; int keyOffset; int keyLenBytes; DEBUGOUTCYPHERIMPL(DEBUGLEV_ENTER, (TEXT("_xor_data\n"))); keyLenBytes = (KeyLength / 8); // Sanity check, just in case we were passed an empty password! if (keyLenBytes != 0) { keyOffset = 0; for(i = 0; i < DataLength; i++, keyOffset++) { if (keyOffset >= keyLenBytes) { keyOffset = 0; } OutData[i] = InData[i] ^ Key[keyOffset]; } } else { // No password? Just copy the data from the input buffer to the output FREEOTFE_MEMCPY( OutData, InData, DataLength ); } DEBUGOUTCYPHERIMPL(DEBUGLEV_EXIT, (TEXT("_xor_data\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; DEBUGOUTCYPHERIMPL(DEBUGLEV_ENTER, (TEXT("ImpCypherDecryptData\n"))); DEBUGOUTCYPHERIMPL(DEBUGLEV_INFO, (TEXT("key length = %d; data length = %d\n"), KeyLength, CyphertextLength)); if (!(IsEqualGUID(&CIPHER_GUID_XOR, CypherGUID))) { status = STATUS_INVALID_PARAMETER; } else { if ( (IV == NULL) && (IVLength != 0) ) { // Sanity check failed... DEBUGOUTCYPHERIMPL(DEBUGLEV_INFO, (TEXT("Inconsistant: NULL passed as %d bit long IV\n"), IVLength)); status = STATUS_INVALID_PARAMETER; } else { _xor_data(KeyLength, Key, CyphertextLength, CyphertextData, PlaintextData); } } DEBUGOUTCYPHERIMPL(DEBUGLEV_EXIT, (TEXT("ImpCypherDecryptData\n"))); return status; }
// ========================================================================= // Cypher driver cleardown function // driverInfo - The structure to be cleared down NTSTATUS ImpCypherDriverExtDetailsCleardown_v3( IN OUT CYPHER_DRIVER_INFO_v3* driverInfo ) { NTSTATUS status = STATUS_SUCCESS; DEBUGOUTCYPHERIMPL(DEBUGLEV_ENTER, (TEXT("ImpCypherDriverExtDetailsCleardown_v3\n"))); if (driverInfo->CypherDetails != NULL) { FREEOTFE_FREE(driverInfo->CypherDetails); } driverInfo->CypherDetails = NULL; driverInfo->CypherCount = 0; DEBUGOUTCYPHERIMPL(DEBUGLEV_EXIT, (TEXT("ImpCypherDriverExtDetailsCleardown_v3\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; 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; }
// ========================================================================= // 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; }
// ========================================================================= NTSTATUS DetermineCypherDetails( IN GUID* CypherGUID, OUT int* KeySizeUnderlying, OUT CYPHER_MODE* CypherMode ) { NTSTATUS status = STATUS_SUCCESS; if (IsEqualGUID(&CIPHER_GUID_TWOFISH_256_CBC, CypherGUID)) { *CypherMode = CYPHER_MODE_CBC; *KeySizeUnderlying = 256; } else if (IsEqualGUID(&CIPHER_GUID_TWOFISH_256_XTS, CypherGUID)) { *CypherMode = CYPHER_MODE_XTS; *KeySizeUnderlying = 256; } else if (IsEqualGUID(&CIPHER_GUID_TWOFISH_256_LRW, CypherGUID)) { *CypherMode = CYPHER_MODE_LRW; *KeySizeUnderlying = 256; } else if (IsEqualGUID(&CIPHER_GUID_TWOFISH_192_CBC, CypherGUID)) { *CypherMode = CYPHER_MODE_CBC; *KeySizeUnderlying = 192; } else if (IsEqualGUID(&CIPHER_GUID_TWOFISH_192_XTS, CypherGUID)) { *CypherMode = CYPHER_MODE_XTS; *KeySizeUnderlying = 192; } else if (IsEqualGUID(&CIPHER_GUID_TWOFISH_192_LRW, CypherGUID)) { *CypherMode = CYPHER_MODE_LRW; *KeySizeUnderlying = 192; } else if (IsEqualGUID(&CIPHER_GUID_TWOFISH_128_CBC, CypherGUID)) { *CypherMode = CYPHER_MODE_CBC; *KeySizeUnderlying = 128; } else if (IsEqualGUID(&CIPHER_GUID_TWOFISH_128_XTS, CypherGUID)) { *CypherMode = CYPHER_MODE_XTS; *KeySizeUnderlying = 128; } else if (IsEqualGUID(&CIPHER_GUID_TWOFISH_128_LRW, CypherGUID)) { *CypherMode = CYPHER_MODE_LRW; *KeySizeUnderlying = 128; } else { DEBUGOUTCYPHERIMPL(DEBUGLEV_ERROR, (TEXT("Unsupported cipher GUID passed in.\n"))); status = STATUS_INVALID_PARAMETER; } 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; }