- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# DeCSSInputPin.cpp

    00001 /*
    00002  *      Copyright (C) 2003-2005 Gabest
    00003  *      http://www.gabest.org
    00004  *
    00005  *  This Program is free software; you can redistribute it and/or modify
    00006  *  it under the terms of the GNU General Public License as published by
    00007  *  the Free Software Foundation; either version 2, or (at your option)
    00008  *  any later version.
    00009  *
    00010  *  This Program is distributed in the hope that it will be useful,
    00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    00013  *  GNU General Public License for more details.
    00014  *
    00015  *  You should have received a copy of the GNU General Public License
    00016  *  along with GNU Make; see the file COPYING.  If not, write to
    00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
    00018  *  http://www.gnu.org/copyleft/gpl.html
    00019  *
    00020  */
    00021
    00022 #include "stdafx.h"
    00023 #include <atlbase.h>
    00024 #include <streams.h>
    00025 #include <dvdmedia.h>
    00026 #include <ks.h>
    00027 #include <ksmedia.h>
    00028 #include "DeCSSInputPin.h"
    00029 #include "..\DSUtil\DSUtil.h"
    00030 #include "CSSauth.h"
    00031 #include "CSSscramble.h"
    00032
    00033 #include <initguid.h>
    00034 #include "..\..\include\moreuuids.h"
    00035
    00036 //
    00037 // CDeCSSInputPin
    00038 //
    00039
    00040 CDeCSSInputPin::CDeCSSInputPin(TCHAR* pObjectName, CTransformFilter* pFilter, HRESULT* phr, LPWSTR pName)
    00041         : CTransformInputPin(pObjectName, pFilter, phr, pName)
    00042 {
    00043         m_varient = -1;
    00044         memset(m_Challenge, 0, sizeof(m_Challenge));
    00045         memset(m_KeyCheck, 0, sizeof(m_KeyCheck));
    00046         memset(m_DiscKey, 0, sizeof(m_DiscKey));
    00047         memset(m_TitleKey, 0, sizeof(m_TitleKey));
    00048 }
    00049
    00050 STDMETHODIMP CDeCSSInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
    00051 {
    00052     CheckPointer(ppv, E_POINTER);
    00053
    00054         return
    00055                 QI(IKsPropertySet)
    00056                  __super::NonDelegatingQueryInterface(riid, ppv);
    00057 }
    00058
    00059 // IMemInputPin
    00060
    00061 STDMETHODIMP CDeCSSInputPin::Receive(IMediaSample* pSample)
    00062 {
    00063         long len = pSample->GetActualDataLength();
    00064
    00065         BYTE* p = NULL;
    00066         if(SUCCEEDED(pSample->GetPointer(&p)) && len > 0)
    00067         {
    00068                 BYTE* base = p;
    00069
    00070                 if(m_mt.majortype == MEDIATYPE_DVD_ENCRYPTED_PACK && len == 2048 && (p[0x14]&0x30))
    00071                 {
    00072                         CSSdescramble(p, m_TitleKey);
    00073                         p[0x14] &= ~0x30;
    00074
    00075                         if(CComQIPtr<IMediaSample2> pMS2 = pSample)
    00076                         {
    00077                                 AM_SAMPLE2_PROPERTIES props;
    00078                                 memset(&props, 0, sizeof(props));
    00079                                 if(SUCCEEDED(pMS2->GetProperties(sizeof(props), (BYTE*)&props))
    00080                                 && (props.dwTypeSpecificFlags & AM_UseNewCSSKey))
    00081                                 {
    00082                                         props.dwTypeSpecificFlags &= ~AM_UseNewCSSKey;
    00083                                         pMS2->SetProperties(sizeof(props), (BYTE*)&props);
    00084                                 }
    00085                         }
    00086                 }
    00087         }
    00088
    00089         HRESULT hr = Transform(pSample);
    00090
    00091         return hr == S_OK ? __super::Receive(pSample) :
    00092                 hr == S_FALSE ? S_OK : hr;
    00093 }
    00094
    00095 void CDeCSSInputPin::StripPacket(BYTE*& p, long& len)
    00096 {
    00097         GUID majortype = m_mt.majortype;
    00098
    00099         if(majortype == MEDIATYPE_MPEG2_PACK || majortype == MEDIATYPE_DVD_ENCRYPTED_PACK)
    00100         if(len > 0 && *(DWORD*)p == 0xba010000) // MEDIATYPE_*_PACK
    00101         {
    00102                 len -= 14; p += 14;
    00103                 if(int stuffing = (p[-1]&7)) {len -= stuffing; p += stuffing;}
    00104                 majortype = MEDIATYPE_MPEG2_PES;
    00105         }
    00106
    00107         if(majortype == MEDIATYPE_MPEG2_PES)
    00108         if(len > 0 && *(DWORD*)p == 0xbb010000)
    00109         {
    00110                 len -= 4; p += 4;
    00111                 int hdrlen = ((p[0]<<8)|p[1]) + 2;
    00112                 len -= hdrlen; p += hdrlen;
    00113         }
    00114
    00115         if(majortype == MEDIATYPE_MPEG2_PES)
    00116         if(len > 0
    00117         && ((*(DWORD*)p&0xf0ffffff) == 0xe0010000
    00118         || (*(DWORD*)p&0xe0ffffff) == 0xc0010000
    00119         || (*(DWORD*)p&0xbdffffff) == 0xbd010000)) // PES
    00120         {
    00121                 bool ps1 = (*(DWORD*)p&0xbdffffff) == 0xbd010000;
    00122
    00123                 len -= 4; p += 4;
    00124                 int expected = ((p[0]<<8)|p[1]);
    00125                 len -= 2; p += 2;
    00126                 BYTE* p0 = p;
    00127
    00128                 for(int i = 0; i < 16 && *p == 0xff; i++, len--, p++);
    00129
    00130                 if((*p&0xc0) == 0x80) // mpeg2
    00131                 {
    00132                         len -= 2; p += 2;
    00133                         len -= *p+1; p += *p+1;
    00134                 }
    00135                 else // mpeg1
    00136                 {
    00137                         if((*p&0xc0) == 0x40)
    00138                         {
    00139                                 len -= 2; p += 2;
    00140                         }
    00141
    00142                         if((*p&0x30) == 0x30 || (*p&0x30) == 0x20)
    00143                         {
    00144                                 bool pts = !!(*p&0x20), dts = !!(*p&0x10);
    00145                                 if(pts) len -= 5; p += 5;
    00146                                 if(dts) {ASSERT((*p&0xf0) == 0x10); len -= 5; p += 5;}
    00147                         }
    00148                         else
    00149                         {
    00150                                 len--; p++;
    00151                         }
    00152                 }
    00153
    00154                 if(ps1)
    00155                 {
    00156                         len--; p++;
    00157                         if(m_mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) {len -= 6; p += 6;}
    00158                         else if(m_mt.subtype == MEDIASUBTYPE_DOLBY_AC3 || m_mt.subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3
    00159                                 || m_mt.subtype == MEDIASUBTYPE_DTS || m_mt.subtype == MEDIASUBTYPE_WAVE_DTS) {len -= 3; p += 3;}
    00160                 }
    00161
    00162                 if(expected > 0)
    00163                 {
    00164                         expected -= (p - p0);
    00165                         len = min(expected, len);
    00166                 }
    00167         }
    00168
    00169         if(len < 0) {ASSERT(0); len = 0;}
    00170 }
    00171
    00172 // IKsPropertySet
    00173
    00174 STDMETHODIMP CDeCSSInputPin::Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength)
    00175 {
    00176         if(PropSet != AM_KSPROPSETID_CopyProt)
    00177                 return E_NOTIMPL;
    00178
    00179         switch(Id)
    00180         {
    00181         case AM_PROPERTY_COPY_MACROVISION:
    00182                 break;
    00183         case AM_PROPERTY_DVDCOPY_CHLG_KEY: // 3. auth: receive drive nonce word, also store and encrypt the buskey made up of the two nonce words
    00184                 {
    00185                         AM_DVDCOPY_CHLGKEY* pChlgKey = (AM_DVDCOPY_CHLGKEY*)pPropertyData;
    00186                         for(int i = 0; i < 10; i++)
    00187                                 m_Challenge[i] = pChlgKey->ChlgKey[9-i];
    00188
    00189                         CSSkey2(m_varient, m_Challenge, &m_Key[5]);
    00190
    00191                         CSSbuskey(m_varient, m_Key, m_KeyCheck);
    00192                 }
    00193                 break;
    00194         case AM_PROPERTY_DVDCOPY_DISC_KEY: // 5. receive the disckey
    00195                 {
    00196                         AM_DVDCOPY_DISCKEY* pDiscKey = (AM_DVDCOPY_DISCKEY*)pPropertyData; // pDiscKey->DiscKey holds the disckey encrypted with itself and the 408 disckeys encrypted with the playerkeys
    00197
    00198                         bool fSuccess = false;
    00199
    00200                         for(int j = 0; j < g_nPlayerKeys; j++)
    00201                         {
    00202                                 for(int k = 1; k < 409; k++)
    00203                                 {
    00204                                         BYTE DiscKey[6];
    00205                                         for(int i = 0; i < 5; i++)
    00206                                                 DiscKey[i] = pDiscKey->DiscKey[k*5+i] ^ m_KeyCheck[4-i];
    00207                                         DiscKey[5] = 0;
    00208
    00209                                         CSSdisckey(DiscKey, g_PlayerKeys[j]);
    00210
    00211                                         BYTE Hash[6];
    00212                                         for(int i = 0; i < 5; i++)
    00213                                                 Hash[i] = pDiscKey->DiscKey[i] ^ m_KeyCheck[4-i];
    00214                                         Hash[5] = 0;
    00215
    00216                                         CSSdisckey(Hash, DiscKey);
    00217
    00218                                         if(!memcmp(Hash, DiscKey, 6))
    00219                                         {
    00220                                                 memcpy(m_DiscKey, DiscKey, 6);
    00221                                                 j = g_nPlayerKeys;
    00222                                                 fSuccess = true;
    00223                                                 break;
    00224                                         }
    00225                                 }
    00226                         }
    00227
    00228                         if(!fSuccess)
    00229                                 return E_FAIL;
    00230                 }
    00231                 break;
    00232         case AM_PROPERTY_DVDCOPY_DVD_KEY1: // 2. auth: receive our drive-encrypted nonce word and decrypt it for verification
    00233                 {
    00234                         AM_DVDCOPY_BUSKEY* pKey1 = (AM_DVDCOPY_BUSKEY*)pPropertyData;
    00235                         for(int i = 0; i < 5; i++)
    00236                                 m_Key[i] =  pKey1->BusKey[4-i];
    00237
    00238                         m_varient = -1;
    00239
    00240                         for(int i = 31; i >= 0; i--)
    00241                         {
    00242                                 CSSkey1(i, m_Challenge, m_KeyCheck);
    00243
    00244                                 if(memcmp(m_KeyCheck, &m_Key[0], 5) == 0)
    00245                                         m_varient = i;
    00246                         }
    00247                 }
    00248                 break;
    00249         case AM_PROPERTY_DVDCOPY_REGION:
    00250                 break;
    00251         case AM_PROPERTY_DVDCOPY_SET_COPY_STATE:
    00252                 break;
    00253         case AM_PROPERTY_DVDCOPY_TITLE_KEY: // 6. receive the title key and decrypt it with the disc key
    00254                 {
    00255                         AM_DVDCOPY_TITLEKEY* pTitleKey = (AM_DVDCOPY_TITLEKEY*)pPropertyData;
    00256                         for(int i = 0; i < 5; i++)
    00257                                 m_TitleKey[i] = pTitleKey->TitleKey[i] ^ m_KeyCheck[4-i];
    00258                         m_TitleKey[5] = 0;
    00259                         CSStitlekey(m_TitleKey, m_DiscKey);
    00260                 }
    00261                 break;
    00262         default:
    00263                 return E_PROP_ID_UNSUPPORTED;
    00264         }
    00265
    00266         return S_OK;
    00267 }
    00268
    00269 STDMETHODIMP CDeCSSInputPin::Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned)
    00270 {
    00271         if(PropSet != AM_KSPROPSETID_CopyProt)
    00272                 return E_NOTIMPL;
    00273
    00274         switch(Id)
    00275         {
    00276         case AM_PROPERTY_DVDCOPY_CHLG_KEY: // 1. auth: send our nonce word
    00277                 {
    00278                         AM_DVDCOPY_CHLGKEY* pChlgKey = (AM_DVDCOPY_CHLGKEY*)pPropertyData;
    00279                         for(int i = 0; i < 10; i++)
    00280                                 pChlgKey->ChlgKey[i] = 9 - (m_Challenge[i] = i);
    00281                         *pBytesReturned = sizeof(AM_DVDCOPY_CHLGKEY);
    00282                 }
    00283                 break;
    00284         case AM_PROPERTY_DVDCOPY_DEC_KEY2: // 4. auth: send back the encrypted drive nonce word to finish the authentication
    00285                 {
    00286                         AM_DVDCOPY_BUSKEY* pKey2 = (AM_DVDCOPY_BUSKEY*)pPropertyData;
    00287                         for(int i = 0; i < 5; i++)
    00288                                 pKey2->BusKey[4-i] = m_Key[5+i];
    00289                         *pBytesReturned = sizeof(AM_DVDCOPY_BUSKEY);
    00290                 }
    00291                 break;
    00292         case AM_PROPERTY_DVDCOPY_REGION:
    00293                 {
    00294                         DVD_REGION* pRegion = (DVD_REGION*)pPropertyData;
    00295                         pRegion->RegionData = 0;
    00296                         pRegion->SystemRegion = 0;
    00297                         *pBytesReturned = sizeof(DVD_REGION);
    00298                 }
    00299                 break;
    00300         case AM_PROPERTY_DVDCOPY_SET_COPY_STATE:
    00301                 {
    00302                         AM_DVDCOPY_SET_COPY_STATE* pState = (AM_DVDCOPY_SET_COPY_STATE*)pPropertyData;
    00303                         pState->DVDCopyState = AM_DVDCOPYSTATE_AUTHENTICATION_REQUIRED;
    00304                         *pBytesReturned = sizeof(AM_DVDCOPY_SET_COPY_STATE);
    00305                 }
    00306                 break;
    00307         default:
    00308                 return E_PROP_ID_UNSUPPORTED;
    00309         }
    00310
    00311         return S_OK;
    00312 }
    00313
    00314 STDMETHODIMP CDeCSSInputPin::QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport)
    00315 {
    00316         if(PropSet != AM_KSPROPSETID_CopyProt)
    00317                 return E_NOTIMPL;
    00318
    00319         switch(Id)
    00320         {
    00321         case AM_PROPERTY_COPY_MACROVISION:
    00322                 *pTypeSupport = KSPROPERTY_SUPPORT_SET;
    00323                 break;
    00324         case AM_PROPERTY_DVDCOPY_CHLG_KEY:
    00325                 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
    00326                 break;
    00327         case AM_PROPERTY_DVDCOPY_DEC_KEY2:
    00328                 *pTypeSupport = KSPROPERTY_SUPPORT_GET;
    00329                 break;
    00330         case AM_PROPERTY_DVDCOPY_DISC_KEY:
    00331                 *pTypeSupport = KSPROPERTY_SUPPORT_SET;
    00332                 break;
    00333         case AM_PROPERTY_DVDCOPY_DVD_KEY1:
    00334                 *pTypeSupport = KSPROPERTY_SUPPORT_SET;
    00335                 break;
    00336         case AM_PROPERTY_DVDCOPY_REGION:
    00337                 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
    00338                 break;
    00339         case AM_PROPERTY_DVDCOPY_SET_COPY_STATE:
    00340                 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
    00341                 break;
    00342         case AM_PROPERTY_DVDCOPY_TITLE_KEY:
    00343                 *pTypeSupport = KSPROPERTY_SUPPORT_SET;
    00344                 break;
    00345         default:
    00346                 return E_PROP_ID_UNSUPPORTED;
    00347         }
    00348
    00349         return S_OK;
    00350 }