OSDN Git Service

fix memory leak, thanks to Valgrind
[rec10/rec10-git.git] / b25-remote / BCasCard.cpp
1 // BcasCard.cpp: CBcasCard クラスのインプリメンテーション
2 //
3 //////////////////////////////////////////////////////////////////////
4
5 #include "W2L.h"
6 #include "BCasCard.h"
7
8 #ifdef _DEBUG
9 #undef THIS_FILE
10 static char THIS_FILE[]=__FILE__;
11 #define new DEBUG_NEW
12 #endif
13
14
15 //#pragma comment(lib, "WinScard.lib")
16
17
18 using std::auto_ptr;
19
20
21 CBcasCard::CBcasCard()
22         : m_hBcasCard(NULL)
23         , m_bIsEstablish(false)
24         , m_dwLastError(BCEC_NOERROR)
25 {
26         // 内部状態初期化
27         memset(&m_BcasCardInfo, 0, sizeof(m_BcasCardInfo));
28         memset(&m_EcmStatus,    0, sizeof(m_EcmStatus));
29
30         // リソースマネージャコンテキスト確立
31         if(::SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &m_ScardContext) != SCARD_S_SUCCESS){
32                 m_dwLastError = BCEC_NOTESTABLISHED;
33                 }
34         else{
35                 m_bIsEstablish = true;
36                 
37                 // カードリーダ列挙
38                 EnumCardReader();
39                 }
40 }
41
42 CBcasCard::~CBcasCard()
43 {
44         CloseCard();
45
46         // リソースマネージャコンテキストの開放
47         if(m_bIsEstablish)::SCardReleaseContext(m_ScardContext);
48 }
49
50 const DWORD CBcasCard::GetCardReaderNum(void) const
51 {
52         // カードリーダー数を返す
53         return m_CardReaderArray.size();
54 }
55
56 LPCTSTR CBcasCard::GetCardReaderName(const DWORD dwIndex) const
57 {
58         // カードリーダー名を返す
59         return (dwIndex < GetCardReaderNum())? m_CardReaderArray[dwIndex].c_str() : NULL;
60 }
61
62 const bool CBcasCard::OpenCard(LPCTSTR lpszReader)
63 {
64         // リソースマネージャコンテキストの確立
65         if(!m_bIsEstablish){
66                 m_dwLastError = BCEC_NOTESTABLISHED;
67                 return false;
68                 }
69         
70         // 一旦クローズする
71         CloseCard();
72
73
74         if(lpszReader){
75                 // 指定されたカードリーダに対してオープンを試みる
76                 DWORD dwActiveProtocol = SCARD_PROTOCOL_UNDEFINED;
77                 
78                 if(::SCardConnect(m_ScardContext, lpszReader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, &m_hBcasCard, &dwActiveProtocol) != SCARD_S_SUCCESS){
79                         m_dwLastError = BCEC_CARDOPENERROR;
80                         return false;
81                         }
82
83                 if(dwActiveProtocol != SCARD_PROTOCOL_T1){
84                         CloseCard();
85                         m_dwLastError = BCEC_CARDOPENERROR;
86                         return false;
87                         }
88                 }
89         else{
90                 // 全てのカードリーダに対してオープンを試みる
91                 DWORD dwIndex = 0UL;
92         
93                 while(GetCardReaderName(dwIndex)){
94                         if(OpenCard(GetCardReaderName(dwIndex++)))return true;                  
95                         }
96                 
97                 return false;
98                 }
99
100         // カード初期化
101         if(!InitialSetting())return false;
102
103         m_dwLastError = BCEC_NOERROR;
104
105         return true;
106 }
107
108 void CBcasCard::CloseCard(void)
109 {
110         // カードをクローズする
111         if(m_hBcasCard){
112                 ::SCardDisconnect(m_hBcasCard, SCARD_LEAVE_CARD);
113                 m_hBcasCard = NULL;
114                 }
115 }
116
117 const DWORD CBcasCard::GetLastError(void) const
118 {
119         // 最後に発生したエラーを返す
120         return m_dwLastError;
121 }
122
123 const bool CBcasCard::EnumCardReader(void)
124 {
125         // カードリーダを列挙する
126         DWORD dwBuffSize = 0UL;
127         
128         switch(::SCardListReaders(m_ScardContext, NULL, NULL, &dwBuffSize)){
129                 case SCARD_E_NO_READERS_AVAILABLE :
130                         // カードリーダが見つからない
131                         m_dwLastError = BCEC_NOCARDREADERS;
132                         return false;
133
134                 case SCARD_S_SUCCESS :
135                         // バッファサイズ取得成功
136                         break;
137                 
138                 default:
139                         // エラー
140                         m_dwLastError = BCEC_INTERNALERROR;             
141                         return false;
142                 }
143
144         // バッファ確保
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);
149
150         switch(::SCardListReaders(m_ScardContext, NULL, (char*)szReaders.data(), &dwBuffSize)){
151                 case SCARD_E_NO_READERS_AVAILABLE :
152                         // カードリーダが見つからない
153                         m_dwLastError = BCEC_NOCARDREADERS;
154                         return false;
155
156                 case SCARD_S_SUCCESS : {
157                         // カードリーダ名保存
158                         LPCTSTR lpszCurReader = szReaders.data();
159                         m_CardReaderArray.clear();
160                         
161                         while(*lpszCurReader){
162                                 m_CardReaderArray.push_back(lpszCurReader);
163                                 lpszCurReader += m_CardReaderArray.back().length() + 1UL;
164                                 }
165                         
166                         break;
167                         }
168                 
169                 default:
170                         // エラー
171                         m_dwLastError = BCEC_INTERNALERROR;             
172                         return false;
173                 }
174
175         m_dwLastError = BCEC_NOERROR;
176
177         return true;
178 }
179
180 const bool CBcasCard::TransmitCommand(const BYTE *pSendData, const DWORD dwSendSize, BYTE *pRecvData, const DWORD dwMaxRecv, DWORD *pdwRecvSize)
181 {
182         DWORD dwRecvSize = dwMaxRecv;
183
184         // データ送受信
185         DWORD dwReturn = ::SCardTransmit(m_hBcasCard, SCARD_PCI_T1, pSendData, dwSendSize, NULL, pRecvData, &dwRecvSize);
186         
187         // 受信サイズ格納
188         if(pdwRecvSize)*pdwRecvSize = dwRecvSize;
189
190         return (dwReturn == SCARD_S_SUCCESS)? true : false;
191 }
192
193 const bool CBcasCard::InitialSetting(void)
194 {
195         static const BYTE InitSettingCmd[] = {0x90U, 0x30U, 0x00U, 0x00U, 0x00U};
196
197         // 「Initial Setting Conditions Command」を処理する
198         if(!m_hBcasCard){
199                 m_dwLastError = BCEC_CARDNOTOPEN;
200                 return false;
201                 }
202
203         // バッファ準備
204         DWORD dwRecvSize = 0UL;
205         BYTE RecvData[1024];
206         memset(RecvData, 0, sizeof(RecvData));
207         
208         // コマンド送信
209         if(!TransmitCommand(InitSettingCmd, sizeof(InitSettingCmd), RecvData, sizeof(RecvData), &dwRecvSize)){
210                 m_dwLastError = BCEC_TRANSMITERROR;
211                 return false;
212                 }
213
214         if(dwRecvSize < 57UL){
215                 m_dwLastError = BCEC_TRANSMITERROR;
216                 return false;           
217                 }
218
219         // レスポンス解析
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
223
224         // ECMステータス初期化
225         memset(&m_EcmStatus, 0, sizeof(m_EcmStatus));
226
227         return true;
228 }
229
230 const BYTE * CBcasCard::GetBcasCardID(void)
231 {
232         // Card ID を返す
233         if(!m_hBcasCard){
234                 m_dwLastError = BCEC_CARDNOTOPEN;
235                 return NULL;
236                 }
237         
238         m_dwLastError = BCEC_NOERROR;
239         
240         return m_BcasCardInfo.BcasCardID;
241 }
242
243 const BYTE * CBcasCard::GetInitialCbc(void)
244 {
245         // Descrambler CBC Initial Value を返す
246         if(!m_hBcasCard){
247                 m_dwLastError = BCEC_CARDNOTOPEN;
248                 return NULL;
249                 }
250         
251         m_dwLastError = BCEC_NOERROR;
252         
253         return m_BcasCardInfo.InitialCbc;
254 }
255
256 const BYTE * CBcasCard::GetSystemKey(void)
257 {
258         // Descrambling System Key を返す
259         if(!m_hBcasCard){
260                 m_dwLastError = BCEC_CARDNOTOPEN;
261                 return NULL;
262                 }
263         
264         m_dwLastError = BCEC_NOERROR;
265         
266         return m_BcasCardInfo.SystemKey;
267 }
268
269 const BYTE * CBcasCard::GetKsFromEcm(const BYTE *pEcmData, const DWORD dwEcmSize)
270 {
271         static const BYTE EcmReceiveCmd[] = {0x90U, 0x34U, 0x00U, 0x00U};
272
273         // 「ECM Receive Command」を処理する
274         if(!m_hBcasCard){
275                 m_dwLastError = BCEC_CARDNOTOPEN;
276                 return NULL;
277                 }
278
279         // ECMサイズをチェック
280         if(!pEcmData || (dwEcmSize < 30UL) || (dwEcmSize > 256UL)){
281                 m_dwLastError = BCEC_BADARGUMENT;
282                 return NULL;
283                 }
284
285         // キャッシュをチェックする
286         if(!StoreEcmData(pEcmData, dwEcmSize)){
287                 // ECMが同一の場合はキャッシュ済みKsを返す
288                 m_dwLastError = BCEC_NOERROR;
289                 return m_EcmStatus.KsData;
290                 }
291
292         // バッファ準備
293         DWORD dwRecvSize = 0UL;
294         BYTE SendData[1024];
295         BYTE RecvData[1024];
296         memset(RecvData, 0, sizeof(RecvData));
297
298         // コマンド構築
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
303
304         // コマンド送信
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;
308                 return NULL;
309                 }
310
311         // サイズチェック
312         if(dwRecvSize != 25UL){
313                 memset(&m_EcmStatus, 0, sizeof(m_EcmStatus));
314                 m_dwLastError = BCEC_TRANSMITERROR;
315                 return NULL;
316                 }       
317         
318         // レスポンス解析
319         memcpy(m_EcmStatus.KsData, &RecvData[6], sizeof(m_EcmStatus.KsData));
320
321         // リターンコード解析
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;
329                 
330                 // 上記以外(視聴不可)
331                 default :
332                         m_dwLastError = BCEC_ECMREFUSED;
333                         return NULL;
334                 }
335 }
336
337 const bool CBcasCard::StoreEcmData(const BYTE *pEcmData, const DWORD dwEcmSize)
338 {
339         bool bUpdate = false;
340         
341         // ECMデータ比較
342         if(m_EcmStatus.dwLastEcmSize != dwEcmSize){
343                 // サイズが変化した
344                 bUpdate = true;
345                 }
346         else{
347                 // サイズが同じ場合はデータをチェックする
348                 for(DWORD dwPos = 0UL ; dwPos < dwEcmSize ; dwPos++){
349                         if(pEcmData[dwPos] != m_EcmStatus.LastEcmData[dwPos]){
350                                 // データが不一致
351                                 bUpdate = true;
352                                 break;
353                                 }                       
354                         }
355                 }
356
357         // ECMデータを保存する
358         if(bUpdate){
359                 m_EcmStatus.dwLastEcmSize = dwEcmSize;
360                 memcpy(m_EcmStatus.LastEcmData, pEcmData, dwEcmSize);
361                 }
362
363         return bUpdate;
364 }