Revive patch for reading encrypted DVDs
Uwe Bonnes
bon at elektron.ikp.physik.tu-darmstadt.de
Sat Jun 5 09:08:39 CDT 2004
Hallo,
appended patch lets DvdShrink see encrypted disk. I sent it out for
discussion last december before, but then the direct device eccess was
missing. It still contains excessive debugging. Please comment, especially
on how to code in a clean multiplatform way, perhaps even with charing the
definitions with libdvdcss.
Bye
--
Uwe Bonnes bon at elektron.ikp.physik.tu-darmstadt.de
Institut fuer Kernphysik Schlossgartenstrasse 9 64289 Darmstadt
--------- Tel. 06151 162516 -------- Fax. 06151 164321 ----------
Index: wine/dlls/ntdll/cdrom.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/cdrom.c,v
retrieving revision 1.45
diff -u -r1.45 cdrom.c
--- wine/dlls/ntdll/cdrom.c 29 Apr 2004 20:04:48 -0000 1.45
+++ wine/dlls/ntdll/cdrom.c 5 Jun 2004 13:59:26 -0000
@@ -98,6 +98,153 @@
#define CD_FRAMES 75 /* frames per second */
#endif
+/* definitions taken from libdvdcss */
+
+#define IOCTL_DVD_BASE FILE_DEVICE_DVD
+
+#define IOCTL_DVD_START_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DVD_READ_KEY CTL_CODE(IOCTL_DVD_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DVD_SEND_KEY CTL_CODE(IOCTL_DVD_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DVD_END_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x0403, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DVD_SET_READ_AHEAD CTL_CODE(IOCTL_DVD_BASE, 0x0404, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DVD_GET_REGION CTL_CODE(IOCTL_DVD_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DVD_SEND_KEY2 CTL_CODE(IOCTL_DVD_BASE, 0x0406, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_DVD_READ_STRUCTURE CTL_CODE(IOCTL_DVD_BASE, 0x0450, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+typedef enum {
+ DvdChallengeKey = 0x01,
+ DvdBusKey1,
+ DvdBusKey2,
+ DvdTitleKey,
+ DvdAsf,
+ DvdSetRpcKey = 0x6,
+ DvdGetRpcKey = 0x8,
+ DvdDiskKey = 0x80,
+ DvdInvalidateAGID = 0x3f
+} DVD_KEY_TYPE;
+
+typedef ULONG DVD_SESSION_ID, *PDVD_SESSION_ID;
+
+typedef struct _DVD_COPY_PROTECT_KEY {
+ ULONG KeyLength;
+ DVD_SESSION_ID SessionId;
+ DVD_KEY_TYPE KeyType;
+ ULONG KeyFlags;
+ union {
+ struct {
+ ULONG FileHandle;
+ ULONG Reserved; // used for NT alignment
+ };
+ LARGE_INTEGER TitleOffset;
+ } Parameters;
+ UCHAR KeyData[0];
+} DVD_COPY_PROTECT_KEY, *PDVD_COPY_PROTECT_KEY;
+
+typedef struct _DVD_RPC_KEY {
+ UCHAR UserResetsAvailable:3;
+ UCHAR ManufacturerResetsAvailable:3;
+ UCHAR TypeCode:2;
+ UCHAR RegionMask;
+ UCHAR RpcScheme;
+ UCHAR Reserved2[1];
+} DVD_RPC_KEY, * PDVD_RPC_KEY;
+
+typedef struct _DVD_ASF {
+ UCHAR Reserved0[3];
+ UCHAR SuccessFlag:1;
+ UCHAR Reserved1:7;
+} DVD_ASF, * PDVD_ASF;
+
+typedef struct _DVD_REGION
+{
+ unsigned char copy_system;
+ unsigned char region_data; /* current media region (not playable when set) */
+ unsigned char system_region; /* current drive region (playable when set) */
+ unsigned char reset_count; /* number of resets available */
+} DVD_REGION, * PDVD_REGION;
+
+typedef struct _DVD_READ_STRUCTURE {
+ /* Contains an offset to the logical block address of the descriptor to be retrieved. */
+ LARGE_INTEGER block_byte_offset;
+
+ /* 0:Physical descriptor, 1:Copyright descriptor, 2:Disk key descriptor
+ 3:BCA descriptor, 4:Manufacturer descriptor, 5:Max descriptor
+ */
+ long format;
+
+ /* Session ID, that is obtained by IOCTL_DVD_START_SESSION */
+ long session;
+
+ /* From 0 to 4 */
+ unsigned char layer_no;
+}DVD_READ_STRUCTURE, * PDVD_READ_STRUCTURE;
+
+typedef struct _DVD_LAYER_DESCRIPTOR
+{
+ unsigned short length;
+
+ unsigned char book_version : 4;
+
+ /* 0:DVD-ROM, 1:DVD-RAM, 2:DVD-R, 3:DVD-RW, 9:DVD-RW */
+ unsigned char book_type : 4;
+
+ unsigned char minimum_rate : 4;
+
+ /* The physical size of the media. 0:120 mm, 1:80 mm. */
+ unsigned char disk_size : 4;
+
+ /* 1:Read-only layer, 2:Recordable layer, 4:Rewritable layer */
+ unsigned char layer_type : 4;
+
+ /* 0:parallel track path, 1:opposite track path */
+ unsigned char track_path : 1;
+
+ /* 0:one layers, 1:two layers, and so on */
+ unsigned char num_of_layers : 2;
+
+ unsigned char reserved1 : 1;
+
+ /* 0:0.74 µm/track, 1:0.80 µm/track, 2:0.615 µm/track */
+ unsigned char track_density : 4;
+
+ /* 0:0.267 µm/bit, 1:0.293 µm/bit, 2:0.409 to 0.435 µm/bit, 4:0.280 to 0.291 µm/bit, 8:0.353 µm/bit */
+ unsigned char linear_density : 4;
+
+ /* Must be either 0x30000:DVD-ROM or DVD-R/-RW or 0x31000:DVD-RAM or DVD+RW */
+ unsigned long starting_data_sector;
+
+ unsigned long end_data_sector;
+ unsigned long end_layer_zero_sector;
+ unsigned char reserved5 : 7;
+
+ /* 0 indicates no BCA data */
+ unsigned char BCA_flag : 1;
+
+ unsigned char reserved6;
+}DVD_LAYER_DESCRIPTOR, * PDVD_LAYER_DESCRIPTOR;
+
+typedef struct _DVD_COPYRIGHT_DESCRIPTOR
+{
+ unsigned char protection;
+ unsigned char region;
+ unsigned short reserved;
+}DVD_COPYRIGHT_DESCRIPTOR, * PDVD_COPYRIGHT_DESCRIPTOR;
+
+typedef struct _DVD_MANUFACTURER_DESCRIPTOR
+{
+ unsigned char manufacturing[2048];
+}DVD_MANUFACTURER_DESCRIPTOR, * PDVD_MANUFACTURER_DESCRIPTOR;
+
+#define DVD_CHALLENGE_KEY_LENGTH (12 + sizeof(DVD_COPY_PROTECT_KEY))
+
+#define DVD_DISK_KEY_LENGTH (2048 + sizeof(DVD_COPY_PROTECT_KEY))
+
+#define DVD_KEY_SIZE 5
+#define DVD_CHALLENGE_SIZE 10
+#define DVD_DISCKEY_SIZE 2048
+#define DVD_SECTOR_PROTECTED 0x00000020
+
static const struct iocodexs
{
DWORD code;
@@ -124,7 +271,15 @@
{IOCTL_CDROM_LOAD_MEDIA, "IOCTL_CDROM_LOAD_MEDIA"},
{IOCTL_CDROM_RESERVE, "IOCTL_CDROM_RESERVE"},
{IOCTL_CDROM_RELEASE, "IOCTL_CDROM_RELEASE"},
-{IOCTL_CDROM_FIND_NEW_DEVICES, "IOCTL_CDROM_FIND_NEW_DEVICES"}
+{IOCTL_CDROM_FIND_NEW_DEVICES, "IOCTL_CDROM_FIND_NEW_DEVICES"},
+{IOCTL_DVD_READ_KEY,"IOCTL_DVD_READ_KEY"},
+{IOCTL_DVD_SEND_KEY,"IOCTL_DVD_SEND_KEY"},
+{IOCTL_DVD_END_SESSION,"IOCTL_DVD_END_SESSION"},
+{IOCTL_DVD_SET_READ_AHEAD,"IOCTL_DVD_SET_READ_AHEAD"},
+{IOCTL_DVD_GET_REGION,"IOCTL_DVD_GET_REGION"},
+{IOCTL_DVD_SEND_KEY2,"IOCTL_DVD_SEND_KEY2"},
+{IOCTL_SCSI_PASS_THROUGH,"IOCTL_SCSI_PASS_THROUGH"},
+{IOCTL_SCSI_PASS_THROUGH_DIRECT,"IOCTL_SCSI_PASS_THROUGH_DIRECT"}
};
static const char *iocodex(DWORD code)
{
@@ -1539,6 +1694,225 @@
}
/******************************************************************
+ * DVD_StartSession
+ *
+ *
+ */
+static NTSTATUS DVD_StartSession(int fd, PDVD_SESSION_ID sid_in, PDVD_SESSION_ID sid_out)
+{
+#if defined(linux)
+ NTSTATUS ret = STATUS_NOT_SUPPORTED;
+ dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.type = DVD_LU_SEND_AGID;
+ if (sid_in) auth_info.lsa.agid = *(int*)sid_in; /* ?*/
+
+ TRACE("BON: fd 0x%08x\n",fd);
+ ret =CDROM_GetStatusCode(ioctl(fd, DVD_AUTH, &auth_info));
+ *sid_out = auth_info.lsa.agid;
+ return ret;
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+ return STATUS_NOT_SUPPORTED;
+#else
+ return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ * DVD_EndSession
+ *
+ *
+ */
+static NTSTATUS DVD_EndSession(int fd, PDVD_SESSION_ID sid)
+{
+#if defined(linux)
+ dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.type = DVD_INVALIDATE_AGID;
+ auth_info.lsa.agid = *(int*)sid;
+
+ TRACE("BON:\n");
+ return CDROM_GetStatusCode(ioctl(fd, DVD_AUTH, &auth_info));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+ return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, (rmv->PreventMediaRemoval) ? CDIOCPREVENT : CDIOCALLOW, NULL));
+#else
+ return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ * DVD_SendKey
+ *
+ *
+ */
+static NTSTATUS DVD_SendKey(int fd, PDVD_COPY_PROTECT_KEY key)
+{
+#if defined(linux)
+ NTSTATUS ret = STATUS_NOT_SUPPORTED;
+ dvd_authinfo auth_info;
+
+ if (fd == -1)
+ {
+ FIXME("BON: No fd\n");
+ return ret;
+ }
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ switch (key->KeyType)
+ {
+ case DvdChallengeKey:
+ auth_info.type = DVD_HOST_SEND_CHALLENGE;
+ auth_info.hsc.agid = (int)key->SessionId;
+ TRACE("BON:DvdChallengeKey ioc 0x%x\n", DVD_AUTH );
+ memcpy( auth_info.hsc.chal, key->KeyData, DVD_CHALLENGE_SIZE );
+ ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
+ break;
+ case DvdBusKey2:
+ auth_info.type = DVD_HOST_SEND_KEY2;
+ auth_info.hsk.agid = (int)key->SessionId;
+
+ memcpy( auth_info.hsk.key, key->KeyData, DVD_KEY_SIZE );
+
+ TRACE("BON:DvdBusKey2\n");
+ ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
+ break;
+
+ default:
+ FIXME("Unknown Keytype 0x%x\n",key->KeyType);
+ }
+ return ret;
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+ TRACE("BON: bsd\n");
+ return STATUS_NOT_SUPPORTED;
+#else
+ TRACE("BON: outside\n");
+ return STATUS_NOT_SUPPORTED;
+#endif
+ TRACE("BON: not reached\n");
+}
+
+/******************************************************************
+ * DVD_ReadKey
+ *
+ *
+ */
+static NTSTATUS DVD_ReadKey(int fd, PDVD_COPY_PROTECT_KEY key)
+{
+#if defined(linux)
+ NTSTATUS ret = STATUS_NOT_SUPPORTED;
+ dvd_struct dvd;
+ dvd_authinfo auth_info;
+
+ if (fd == -1)
+ {
+ FIXME("BON: No fd\n");
+ return ret;
+ }
+ memset( &dvd, 0, sizeof( dvd_struct ) );
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ switch (key->KeyType)
+ {
+ case DvdDiskKey:
+
+ dvd.type = DVD_STRUCT_DISCKEY;
+ dvd.disckey.agid = (int)key->SessionId;
+ memset( dvd.disckey.value, 0, DVD_DISCKEY_SIZE );
+
+ TRACE("BON: DvdDiskKey\n");
+ ret = CDROM_GetStatusCode(ioctl( fd, DVD_READ_STRUCT, &dvd ));
+ if (ret == STATUS_SUCCESS)
+ memcpy(key->KeyData,dvd.disckey.value,DVD_DISCKEY_SIZE);
+ break;
+ case DvdTitleKey:
+ auth_info.type = DVD_LU_SEND_TITLE_KEY;
+ auth_info.lstk.agid = (int)key->SessionId;
+ auth_info.lstk.lba = (int)(key->Parameters.TitleOffset.QuadPart>>11);
+ TRACE("BON: DvdTitleKey session %d Quadpart 0x%08lx offset 0x%08x\n",
+ (int)key->SessionId, (long)key->Parameters.TitleOffset.QuadPart,
+ auth_info.lstk.lba);
+ ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
+ if (ret == STATUS_SUCCESS)
+ memcpy(key->KeyData, auth_info.lstk.title_key, DVD_KEY_SIZE );
+ break;
+ case DvdChallengeKey:
+
+ auth_info.type = DVD_LU_SEND_CHALLENGE;
+ auth_info.lsc.agid = (int)key->SessionId;
+
+ TRACE("BON: DvdChallengeKey\n");
+ ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
+ if (ret == STATUS_SUCCESS)
+ memcpy( key->KeyData, auth_info.lsc.chal, DVD_CHALLENGE_SIZE );
+ break;
+ case DvdAsf:
+ auth_info.type = DVD_LU_SEND_ASF;
+ TRACE("BON: DvdAsf\n");
+ auth_info.lsasf.asf=((PDVD_ASF)key->KeyData)->SuccessFlag;
+ ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
+ ((PDVD_ASF)key->KeyData)->SuccessFlag = auth_info.lsasf.asf;
+ break;
+ case DvdBusKey1:
+ auth_info.type = DVD_LU_SEND_KEY1;
+ auth_info.lsk.agid = (int)key->SessionId;
+
+ TRACE("BON: DvdBusKey1\n");
+ ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
+
+ if (ret == STATUS_SUCCESS)
+ memcpy( key->KeyData, auth_info.lsk.key, DVD_KEY_SIZE );
+ break;
+ case DvdGetRpcKey:
+ auth_info.type = DVD_LU_SEND_RPC_STATE;
+
+ TRACE("BON: DvdGetRpcKey\n");
+ ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
+
+ if (ret == STATUS_SUCCESS)
+ {
+ ((PDVD_RPC_KEY)key->KeyData)->TypeCode = auth_info.lrpcs.type;
+ ((PDVD_RPC_KEY)key->KeyData)->RegionMask = auth_info.lrpcs.region_mask;
+ ((PDVD_RPC_KEY)key->KeyData)->RpcScheme = auth_info.lrpcs.rpc_scheme;
+ }
+ break;
+ default:
+ FIXME("Unknown keytype 0x%x\n",key->KeyType);
+ }
+ return ret;
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+ TRACE("BON: bsd\n");
+ return STATUS_NOT_SUPPORTED;
+#else
+ TRACE("BON: outside\n");
+ return STATUS_NOT_SUPPORTED;
+#endif
+ TRACE("BON: not reached\n");
+}
+
+/******************************************************************
+ * DVD_GetRegion
+ *
+ *
+ */
+static NTSTATUS DVD_GetRegion(int dev, PDVD_REGION region)
+{
+ FIXME("\n");
+ return STATUS_SUCCESS;
+
+}
+
+/******************************************************************
+ * DVD_GetRegion
+ *
+ *
+ */
+static NTSTATUS DVD_ReadStructure(int dev, PDVD_READ_STRUCTURE structure, PDVD_LAYER_DESCRIPTOR layer)
+{
+ FIXME("\n");
+ return STATUS_SUCCESS;
+
+}
+/******************************************************************
* CDROM_DeviceIoControl
*
*
@@ -1747,6 +2121,65 @@
else if (nOutBufferSize < sizeof(IO_SCSI_CAPABILITIES)) status = STATUS_BUFFER_TOO_SMALL;
else status = CDROM_ScsiGetCaps((PIO_SCSI_CAPABILITIES)lpOutBuffer);
break;
+ case IOCTL_DVD_START_SESSION:
+ sz = sizeof(DVD_SESSION_ID);
+ if (lpOutBuffer == NULL) status = STATUS_INVALID_PARAMETER;
+ else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
+ else
+ {
+ TRACE("BON: before in 0x%08lx out 0x%08lx\n",(lpInBuffer)?*(PDVD_SESSION_ID)lpInBuffer:0,
+ *(PDVD_SESSION_ID)lpOutBuffer);
+ status = DVD_StartSession(fd, (PDVD_SESSION_ID)lpInBuffer, (PDVD_SESSION_ID)lpOutBuffer);
+ TRACE("BON: before in 0x%08lx out 0x%08lx\n",(lpInBuffer)?*(PDVD_SESSION_ID)lpInBuffer:0,
+ *(PDVD_SESSION_ID)lpOutBuffer);
+ }
+ break;
+ case IOCTL_DVD_END_SESSION:
+ sz = sizeof(DVD_SESSION_ID);
+ if ((lpInBuffer == NULL) || (nInBufferSize < sz))status = STATUS_INVALID_PARAMETER;
+ else status = DVD_EndSession(fd, (PDVD_SESSION_ID)lpInBuffer);
+ break;
+ case IOCTL_DVD_SEND_KEY:
+ sz = 0;
+ if (!lpInBuffer ||
+ (((PDVD_COPY_PROTECT_KEY)lpInBuffer)->KeyLength != nInBufferSize))
+ status = STATUS_INVALID_PARAMETER;
+ else
+ {
+ TRACE("BON doing DVD_SendKey\n");
+ status = DVD_SendKey(fd, (PDVD_COPY_PROTECT_KEY)lpInBuffer);
+ }
+ break;
+
+ case IOCTL_DVD_READ_KEY:
+ if (!lpInBuffer ||
+ (((PDVD_COPY_PROTECT_KEY)lpInBuffer)->KeyLength != nInBufferSize))
+ status = STATUS_INVALID_PARAMETER;
+ else if (lpInBuffer !=lpOutBuffer) status = STATUS_BUFFER_TOO_SMALL;
+ else
+ {
+ TRACE("BON doing DVD_READ_KEY\n");
+ sz = ((PDVD_COPY_PROTECT_KEY)lpInBuffer)->KeyLength;
+ status = DVD_ReadKey(fd, (PDVD_COPY_PROTECT_KEY)lpInBuffer);
+ }
+ break;
+
+ case IOCTL_DVD_GET_REGION:
+ sz = sizeof(DVD_REGION);
+ if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
+ else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
+ TRACE("BON doing DVD_Get_REGION\n");
+ status = DVD_GetRegion(fd, (PDVD_REGION)lpOutBuffer);
+ break;
+
+ case IOCTL_DVD_READ_STRUCTURE:
+ sz = sizeof(DVD_LAYER_DESCRIPTOR);
+ if (lpInBuffer == NULL || nInBufferSize != sizeof(DVD_READ_STRUCTURE)) status = STATUS_INVALID_PARAMETER;
+ else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
+ TRACE("BON doing DVD_READ_STRUCTURE\n");
+ status = DVD_ReadStructure(fd, (PDVD_READ_STRUCTURE)lpInBuffer, (PDVD_LAYER_DESCRIPTOR)lpOutBuffer);
+ break;
+
default:
FIXME("Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n",
dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
More information about the wine-patches
mailing list