1 // BcasCard.cpp: CBcasCard クラスのインプリメンテーション
3 //////////////////////////////////////////////////////////////////////
10 static char THIS_FILE[]=__FILE__;
15 //#pragma comment(lib, "WinScard.lib")
21 CBcasCard::CBcasCard()
23 , m_bIsEstablish(false)
24 , m_dwLastError(BCEC_NOERROR)
27 memset(&m_BcasCardInfo, 0, sizeof(m_BcasCardInfo));
28 memset(&m_EcmStatus, 0, sizeof(m_EcmStatus));
31 if(::SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &m_ScardContext) != SCARD_S_SUCCESS){
32 m_dwLastError = BCEC_NOTESTABLISHED;
35 m_bIsEstablish = true;
42 CBcasCard::~CBcasCard()
47 if(m_bIsEstablish)::SCardReleaseContext(m_ScardContext);
50 const DWORD CBcasCard::GetCardReaderNum(void) const
53 return m_CardReaderArray.size();
56 LPCTSTR CBcasCard::GetCardReaderName(const DWORD dwIndex) const
59 return (dwIndex < GetCardReaderNum())? m_CardReaderArray[dwIndex].c_str() : NULL;
62 const bool CBcasCard::OpenCard(LPCTSTR lpszReader)
66 m_dwLastError = BCEC_NOTESTABLISHED;
75 // 指定されたカードリーダに対してオープンを試みる
76 DWORD dwActiveProtocol = SCARD_PROTOCOL_UNDEFINED;
78 if(::SCardConnect(m_ScardContext, lpszReader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, &m_hBcasCard, &dwActiveProtocol) != SCARD_S_SUCCESS){
79 m_dwLastError = BCEC_CARDOPENERROR;
83 if(dwActiveProtocol != SCARD_PROTOCOL_T1){
85 m_dwLastError = BCEC_CARDOPENERROR;
90 // 全てのカードリーダに対してオープンを試みる
93 while(GetCardReaderName(dwIndex)){
94 if(OpenCard(GetCardReaderName(dwIndex++)))return true;
101 if(!InitialSetting())return false;
103 m_dwLastError = BCEC_NOERROR;
108 void CBcasCard::CloseCard(void)
112 ::SCardDisconnect(m_hBcasCard, SCARD_LEAVE_CARD);
117 const DWORD CBcasCard::GetLastError(void) const
120 return m_dwLastError;
123 const bool CBcasCard::EnumCardReader(void)
126 DWORD dwBuffSize = 0UL;
128 switch(::SCardListReaders(m_ScardContext, NULL, NULL, &dwBuffSize)){
129 case SCARD_E_NO_READERS_AVAILABLE :
131 m_dwLastError = BCEC_NOCARDREADERS;
134 case SCARD_S_SUCCESS :
140 m_dwLastError = BCEC_INTERNALERROR;
145 // auto_ptr<TCHAR> cannot be used for array
146 // auto_ptr<TCHAR> szReaders(new TCHAR[dwBuffSize]);
147 std::string szReaders;
148 szReaders.resize(dwBuffSize);
150 switch(::SCardListReaders(m_ScardContext, NULL, (char*)szReaders.data(), &dwBuffSize)){
151 case SCARD_E_NO_READERS_AVAILABLE :
153 m_dwLastError = BCEC_NOCARDREADERS;
156 case SCARD_S_SUCCESS : {
158 LPCTSTR lpszCurReader = szReaders.data();
159 m_CardReaderArray.clear();
161 while(*lpszCurReader){
162 m_CardReaderArray.push_back(lpszCurReader);
163 lpszCurReader += m_CardReaderArray.back().length() + 1UL;
171 m_dwLastError = BCEC_INTERNALERROR;
175 m_dwLastError = BCEC_NOERROR;
180 const bool CBcasCard::TransmitCommand(const BYTE *pSendData, const DWORD dwSendSize, BYTE *pRecvData, const DWORD dwMaxRecv, DWORD *pdwRecvSize)
182 DWORD dwRecvSize = dwMaxRecv;
185 DWORD dwReturn = ::SCardTransmit(m_hBcasCard, SCARD_PCI_T1, pSendData, dwSendSize, NULL, pRecvData, &dwRecvSize);
188 if(pdwRecvSize)*pdwRecvSize = dwRecvSize;
190 return (dwReturn == SCARD_S_SUCCESS)? true : false;
193 const bool CBcasCard::InitialSetting(void)
195 static const BYTE InitSettingCmd[] = {0x90U, 0x30U, 0x00U, 0x00U, 0x00U};
197 // 「Initial Setting Conditions Command」を処理する
199 m_dwLastError = BCEC_CARDNOTOPEN;
204 DWORD dwRecvSize = 0UL;
206 memset(RecvData, 0, sizeof(RecvData));
209 if(!TransmitCommand(InitSettingCmd, sizeof(InitSettingCmd), RecvData, sizeof(RecvData), &dwRecvSize)){
210 m_dwLastError = BCEC_TRANSMITERROR;
214 if(dwRecvSize < 57UL){
215 m_dwLastError = BCEC_TRANSMITERROR;
220 memcpy(m_BcasCardInfo.BcasCardID, &RecvData[8], 6UL); // +8 Card ID
221 memcpy(m_BcasCardInfo.SystemKey, &RecvData[16], 32UL); // +16 Descrambling system key
222 memcpy(m_BcasCardInfo.InitialCbc, &RecvData[48], 8UL); // +48 Descrambler CBC initial value
225 memset(&m_EcmStatus, 0, sizeof(m_EcmStatus));
230 const BYTE * CBcasCard::GetBcasCardID(void)
234 m_dwLastError = BCEC_CARDNOTOPEN;
238 m_dwLastError = BCEC_NOERROR;
240 return m_BcasCardInfo.BcasCardID;
243 const BYTE * CBcasCard::GetInitialCbc(void)
245 // Descrambler CBC Initial Value を返す
247 m_dwLastError = BCEC_CARDNOTOPEN;
251 m_dwLastError = BCEC_NOERROR;
253 return m_BcasCardInfo.InitialCbc;
256 const BYTE * CBcasCard::GetSystemKey(void)
258 // Descrambling System Key を返す
260 m_dwLastError = BCEC_CARDNOTOPEN;
264 m_dwLastError = BCEC_NOERROR;
266 return m_BcasCardInfo.SystemKey;
269 const BYTE * CBcasCard::GetKsFromEcm(const BYTE *pEcmData, const DWORD dwEcmSize)
271 static const BYTE EcmReceiveCmd[] = {0x90U, 0x34U, 0x00U, 0x00U};
273 // 「ECM Receive Command」を処理する
275 m_dwLastError = BCEC_CARDNOTOPEN;
280 if(!pEcmData || (dwEcmSize < 30UL) || (dwEcmSize > 256UL)){
281 m_dwLastError = BCEC_BADARGUMENT;
286 if(!StoreEcmData(pEcmData, dwEcmSize)){
287 // ECMが同一の場合はキャッシュ済みKsを返す
288 m_dwLastError = BCEC_NOERROR;
289 return m_EcmStatus.KsData;
293 DWORD dwRecvSize = 0UL;
296 memset(RecvData, 0, sizeof(RecvData));
299 memcpy(SendData, EcmReceiveCmd, sizeof(EcmReceiveCmd)); // CLA, INS, P1, P2
300 SendData[sizeof(EcmReceiveCmd)] = (BYTE)dwEcmSize; // COMMAND DATA LENGTH
301 memcpy(&SendData[sizeof(EcmReceiveCmd) + 1], pEcmData, dwEcmSize); // ECM
302 SendData[sizeof(EcmReceiveCmd) + dwEcmSize + 1] = 0x00U; // RESPONSE DATA LENGTH
305 if(!TransmitCommand(SendData, sizeof(EcmReceiveCmd) + dwEcmSize + 2UL, RecvData, sizeof(RecvData), &dwRecvSize)){
306 memset(&m_EcmStatus, 0, sizeof(m_EcmStatus));
307 m_dwLastError = BCEC_TRANSMITERROR;
312 if(dwRecvSize != 25UL){
313 memset(&m_EcmStatus, 0, sizeof(m_EcmStatus));
314 m_dwLastError = BCEC_TRANSMITERROR;
319 memcpy(m_EcmStatus.KsData, &RecvData[6], sizeof(m_EcmStatus.KsData));
322 switch(((WORD)RecvData[4] << 8) | (WORD)RecvData[5]){
323 // Purchased: Viewing
324 case 0x0200U : // Payment-deferred PPV
325 case 0x0400U : // Prepaid PPV
326 case 0x0800U : // Tier
327 m_dwLastError = BCEC_NOERROR;
328 return m_EcmStatus.KsData;
332 m_dwLastError = BCEC_ECMREFUSED;
337 const bool CBcasCard::StoreEcmData(const BYTE *pEcmData, const DWORD dwEcmSize)
339 bool bUpdate = false;
342 if(m_EcmStatus.dwLastEcmSize != dwEcmSize){
347 // サイズが同じ場合はデータをチェックする
348 for(DWORD dwPos = 0UL ; dwPos < dwEcmSize ; dwPos++){
349 if(pEcmData[dwPos] != m_EcmStatus.LastEcmData[dwPos]){
359 m_EcmStatus.dwLastEcmSize = dwEcmSize;
360 memcpy(m_EcmStatus.LastEcmData, pEcmData, dwEcmSize);