البطاقة الذكية I2C. أوامر تبادل APDU عبر واجهة I2C

مقدمة


منذ بعض الوقت ، شاركت في تطوير جهاز كان من الضروري فيه تنفيذ التشفير الروسي. نظرًا لأنه كان من المفترض في المستقبل التصديق على هذا القرار ، فقد تم طرح متطلبات معينة لتنفيذ التشفير. وكأحد خيارات تبسيط تنفيذ هذه المتطلبات ، نظرنا في إمكانية دمج قارئ البطاقة الذكية في الجهاز أو تثبيت شريحة البطاقة الذكية ، حيث تم بالفعل تنفيذ العديد من السيناريوهات اللازمة للعمل مع المعلومات الأساسية.

لسوء الحظ ، فإن مثل هذا الحل لا يناسب لسبب ما ، على الرغم من أنه إذا كان من الممكن استخدام تشفير الأجهزة الروسية المعدة بالفعل ، فإن هذا من شأنه تسريع تطوير المنتج النهائي وإصدار الشهادات اللاحقة له بشكل كبير. وكانت أسباب استحالة استخدام رموز USB أو البطاقات الذكية شائعة جدًا: كان ينبغي أن يكون الجهاز مضغوطًا تمامًا (وحدة صغيرة لأجهزة M2M أو IoT) ، يتم تشغيله بشكل أساسي في وضع خالٍ من الصيانة ويعمل في نطاق درجات حرارة واسعة.

في هذه المقالة ، أود التحدث عن حل محتمل لمثل هذه الحالة باستخدام شريحة A7001 ، المتصلة بالنظام عبر واجهة I2C.



مشاكل تنفيذ التشفير في PAC


لا أريد أن أتحدث عن مشكلات شهادة التشفير. كل من يعمل مع هذا يدرك هذا على أي حال ، لكن الباقي لا يبدو بحاجة إليه. ولكن حول بعض النقاط المهمة لا يزال الأمر يستحق القول.

من الناحية النظرية ، لا ينبغي أن يكون هناك أي مشاكل خاصة مع التشفير. بعد كل شيء ، يكفي أن تأخذ إحدى مكتبات التشفير ، على سبيل المثال ، OpenSSL ، أو أي مكتبة أخرى كثيرة.

تبدأ المشاكل عندما يكون هذا الحل مطلوبًا للحصول على الشهادة. كما أن تطبيق التشفير المحض للبرنامج في البرنامج الثابت يحول الجهاز إلى جهاز حماية معلومات تشفير متكامل ، الأمر الذي يتطلب دراسة دقيقة في أحد مختبرات الاختبار. بعد كل شيء ، عند تطوير حل باستخدام التشفير ، عليك عاجلاً أم آجلاً التفكير في أشياء مثل مخطط رئيسي ، وتخزين المفاتيح ، وإنشاء أرقام عشوائية ، ومسائل أخرى خفية.

هناك طريقة أنيقة لتنفيذ خوارزميات تشفير روسية معتمدة لبعض الحلول ، مما يسمح لنا بتبسيط عملية إنشاء الأجهزة الطرفية وتقليل الوقت اللازم لتطويرها والشهادات اللاحقة. يكفي تضمين بطاقة ذكية أو شريحة بطاقة ذكية في الجهاز ، واستخدامها كنوع من "جذر الثقة" ، وبالتالي حل عدد كبير من المشكلات المؤلمة التي تتطلب بحثًا مطولًا وتأكيدًا في مختبرات الاختبار.



متحكم البطاقة الذكية مع واجهة I2C


لكتابة هذه المقالة ، استخدمت شريحة A7001 ، التي تتصل بالجهاز النهائي عبر ناقل I2C ، والذي يتوفر في أي جهاز تقريبًا. تم توفير الشريحة بواسطة Aladdin RD ، الذي لديه بالفعل برنامج ثابت مثبت يدعم التشفير الروسي.

يتم تصنيع متحكم A7001AG (متحكم مصادقة آمن) بواسطة NXP. طبقًا لورقة البيانات الموجودة على الشريحة ، فإن A7001AG عبارة عن متحكم محمي من الوصول غير المصرح به استنادًا إلى بنية 80C51 الكلاسيكية باستخدام معالج تشفير.

في وضع توفير الطاقة ، يستهلك متحكم 50 درجة مئوية. إنه يدعم جهد الإمداد في النطاق من 1.62V إلى 5.5V ويمكن تشغيله في درجات حرارة من -25 درجة مئوية إلى + 85 درجة مئوية.

للتفاعل مع الأجهزة الخارجية ، يتم استخدام واجهة الرقيق I2C بسرعة تصل إلى 100 kbit / s.

متحكم متاح في العديد من خيارات السكن. انتهى بي الأمر بتنسيق HVQFN32. هذه علبة بلاستيكية مقاس 5x5x0.85 مم مع 32 جهة اتصال وملعب 0.5 مم.

ظهور القضية:



pinout له:



نظام المضيف لتوصيل رقاقة A7001


تم اعتبار لوحة ESP32 WiFi Kit 32 من Heltec كتخطيط للنظام المضيف مع واجهة I2C. يكلف أقل من 1000 روبل ، ويحتوي على جميع واجهات السلكية واللاسلكية اللازمة ، وهناك موصل لتوصيل بطارية الليثيوم مع دائرة الشحن ، وكذلك شاشة OLED 0.96 بوصة.



نظام مثالي تقريبًا لنماذج مختلفة لأجهزة IoT و M2M ، والتي طالما أردت اللعب معها.

يمكن برمجة اللوحة في بيئة التطوير المحلية وفي Arduino IDE. هناك العديد من الأمثلة للعمل معها. للبساطة ، استقرت على معيار اردوينو IDE.

مخطط الدائرة


يظهر الرسم البياني لدائرة توصيل شريحة A7001 في الشكل. إنه يختلف قليلاً عن ورقة البيانات الموصى بها. وفقًا لوصف الشركة المصنعة ، يجب أن يكون للمطراف 22 (إشارة إعادة الضبط RST_N) إمكانات عالية ، لكن الدائرة لم تبدأ وفقًا لهذا المخطط. نتيجة "الوخز العلمي" ، تم تحقيق قابلية التشغيل عن طريق توصيل مقاوم سحب R4 بموصل الطاقة السلبي.

استكمال: كما هو مقترح في التعليقات ، يتوافق المخطط مع ورقة البيانات ، في حين أن وصف الإخراج يربكني
RST_N - إعادة تعيين الإدخال ، نشط LOW




يتم تجميع الدائرة على لوح صغير. يتم توصيل إشارات الطاقة وإشارات I2C بأربعة أسلاك متصلة ، ووحدة ESP32 نفسها متصلة بالكمبيوتر عبر USB لتلقي الطاقة إلى الدائرة بأكملها وملء البرامج الثابتة.



البطاقة الذكية بروتوكول I2C


عندما سمعت لأول مرة عن توصيل ميكروكنترولر البطاقة الذكية عبر ناقل I2C ، أوضحوا لي أن الطبقة المادية لواجهة البطاقة الذكية (GOST R ISO / IEC 7816-3-2013) تم استبدالها بـ I2C (SMBus) ، وكل شيء آخر يعمل كالمعتاد البطاقات الذكية وفقًا لمعايير GOST R ISO / IEC 7816-4-2013 باستخدام أوامر APDU.

اتضح أن هذا ليس صحيحًا تمامًا ، أو بالأحرى ليس صحيحًا على الإطلاق. يحدث التفاعل مع متحكم على مستوى عال باستخدام أوامر APDU التقليدية ، ولكن كان هناك بعض "buts" كذلك.

  1. واجهة I2C (SMBus) ru.wikipedia.org/wiki/I٪C2٪B2C عبارة عن حافلة ذات عناية بالرقيق ، تختلف اختلافًا جوهريًا عن واجهة UART التسلسلية ، وهي مصممة لتوصيل جهازين على أساس نقطة إلى نقطة وعدم استخدام العنونة . هذا يعني أن جميع البيانات المرسلة (أوامر APDU) يجب أن تكون "معبأة" في تنسيق بيانات ناقل I2C.
  2. يبدأ العمل باستخدام البطاقة الذكية بإعادة تعيينها ، عادة عن طريق إيقاف تشغيل الطاقة ، على سبيل المثال ، إزالة البطاقة فعليًا من قارئ البطاقة. بعد إعادة التعيين ، ترسل البطاقة الذكية أولاً كتلة بيانات ATR (الإجابة إلى إعادة التعيين) ، والتي تحتوي على معلومات التكوين الضرورية لتكوين التفاعل مع البطاقة الذكية.
    وليست الرقاقة الموجودة على ناقل I2C استثناءً ، لكن في الحالة التي يجب أن يكون فيها متحكم دقيق ملحومًا بلوحة الدوائر المطبوعة ، قد لا يكون لديه دائرة إمداد الطاقة من الدائرة الكهربائية الدقيقة أو التحكم في برنامج إخراج الإخراج المعاد ضبطه. لذلك ، يتم تنفيذ إعادة تعيين الشريحة ، بما في ذلك ، على مستوى أوامر بروتوكول I2C.

تتم معالجة هذه المشكلات وغيرها من خلال بروتوكول البطاقة الذكية I2C ، والذي يمكن العثور على وصف له على موقع NXP على www.nxp.com/docs/ar/supporting-information/AN12207.pdf .

جزء البرمجيات


البحث في المكتبة مع تطبيق بروتوكول Smart Card I2C Protocol لم يعط أي نتائج. لذلك ، كان لا بد لي من فهم المواصفات وجعل تنفيذ المهام الأساسية لما كان في متناول اليد.

رسم مصادر لاردوينو IDE
#include <Wire.h> #include <vector> // I2C address on chip A7001 #define ADDR_A7001 static_cast<uint16_t>(0x48) using namespace std; typedef std::vector<uint8_t> vect; //-------------------------------------------------------------------------- // Output dump data by serial port void vect_dump(const char * prefix, const vect & v, const size_t start = 0, const size_t count = 0) { if(prefix) { Serial.print(prefix); } if(v.size() < start) { Serial.println("Empty"); return; } for(size_t i=0; i < (v.size()-start) && (count == 0 || i < count); i++) { uint8_t b = v[start + i]; // Format output HEX data if(i) Serial.print(" "); if(b < 0x0F) Serial.print("0"); Serial.print(b, HEX); } Serial.println(""); } //-------------------------------------------------------------------------- // Send array bytes by I2C to address A7001 and read response result_size bytes vect sci2c_exchange(const vect data, const uint8_t result_size) { Wire.beginTransmission(ADDR_A7001); Wire.write(data.data(), data.size()); Wire.endTransmission(false); Wire.requestFrom(ADDR_A7001, result_size, true); //delay(1); vect result(result_size, 0); if(result_size >= 2) { result[0] = Wire.read(); // Data size CDB result[1] = Wire.read(); // PCB for(size_t i=2; i<result.size()-2 && Wire.available(); i++) { result[i+2] = Wire.read(); } } return result; } //-------------------------------------------------------------------------- // Read Status Code uint8_t sci2c_status(const char * msg = nullptr) { vect v = sci2c_exchange({0b0111}, 2); uint8_t status = v[1] >> 4; if(msg) { Serial.print(msg); // Prefix switch(status) { case 0b0000: Serial.println("OK (Ready)"); break; case 0b0001: Serial.println("OK (Busy)"); break; case 0b1000: Serial.println("ERROR (Exception raised)"); break; case 0b1001: Serial.println("ERROR (Over clocking)"); break; case 0b1010: Serial.println("ERROR (Unexpected Sequence)"); break; case 0b1011: Serial.println("ERROR (Invalid Data Length)"); break; case 0b1100: Serial.println("ERROR (Unexpected Command)"); break; case 0b1101: Serial.println("ERROR (Invalid EDC)"); break; default: Serial.print("ERROR (Other Exception "); Serial.print(status, BIN); Serial.println("b)"); break; } } return status; } static uint8_t apdu_master_sequence_counter = 0; // Sequence Counter Master, Master to Slave //-------------------------------------------------------------------------- // Send APDU void sci2c_apdu_send(const vect apdu) { vect_dump("C-APDU => ", apdu); vect data(2, 0); // 0x00 - Master to Slave Data Transmission command + reserve to length data.insert(data.end(), std::begin(apdu), std::end(apdu)); data[0] |= (apdu_master_sequence_counter << 4); if(++apdu_master_sequence_counter > 0b111) { apdu_master_sequence_counter = 0; } data[1] = data.size() - 2; sci2c_exchange(data, 2); delay(10); sci2c_status(""); } //-------------------------------------------------------------------------- // Receive APDU vect sci2c_apdu_recv(uint8_t result_size) { Wire.beginTransmission(ADDR_A7001); Wire.write(0b0010); // 0010b - Slave to Master Data Transmission command Wire.endTransmission(false); Wire.requestFrom(ADDR_A7001, result_size, true); vect result(result_size, 0); for(size_t i=0; i<result.size() && Wire.available(); i++) { result[i] = Wire.read(); } vect_dump("R-APDU <= ", result); return result; } //-------------------------------------------------------------------------- void setup(){ Wire.begin(); Serial.begin(9600); while (!Serial); Serial.println(""); Serial.println("Smart Card I2C Protocol Arduino demo on A7001"); Serial.println(""); sci2c_exchange({0b00001111}, 2); //The bits b0 to b5 set to 001111b indicate the Wakeup command. sci2c_status("Status Wakeup: "); sci2c_exchange({0b00001111}, 2); //The bits b0 to b5 set to 001111b indicate the Wakeup command. sci2c_status("Status Wakeup: "); // Soft Reset sci2c_exchange({0b00011111}, 2); //The bits b0 to b5 set to 011111b indicate the Soft Reset command. delay(5); // Wait at least tRSTG (time, ReSeT Guard) sci2c_status("Status SoftReset: "); // Read ATR vect ATR = sci2c_exchange({0b101111}, 29+2); //The bits b0 to b5 set to 101111b indicate the Read Answer to Reset command. sci2c_status("Status ATR: "); vect_dump("ATR: ", ATR, 2); // Parameter Exchange // The bits b0 to b5 set to 111111b of the PCB send by the master device indicate the Parameter Exchange command. // The bits b6 and b7 of the PCB send by the master device code the CDBIsm,max(Command Data Bytes Integer, Slave to Master, MAXimum) vect CDB = sci2c_exchange({0b11111111}, 2); sci2c_status("Status CDB: "); vect_dump("CDB: ", CDB, 1); // Further examples of the exchange of APDU // Exchanges APDU from exmaple chapter sci2c_apdu_send({0x00, 0xA4, 0x04, 0x04, 0x04, 0x54, 0x65, 0x73, 0x74, 0x00}); sci2c_status("Status Test send: "); sci2c_apdu_recv(3+1); // R-APDU size + 1 byte PBC sci2c_status("Status Test recv: "); // Read Card Production Life Cycle sci2c_apdu_send({0x80, 0xCA, 0x9F, 0x7F, 0x00}); sci2c_status("Status card LC send: "); sci2c_apdu_recv(0x30+1); // R-APDU size + 1 byte PBC sci2c_status("Status card LC recv: "); // Read Card Info sci2c_apdu_send({0x80, 0xCA, 0x00, 0x66, 0x00}); sci2c_status("Status card info send: "); sci2c_apdu_recv(0x51+1); // R-APDU size + 1 byte PBC sci2c_status("Status card info recv: "); // Read Key Info sci2c_apdu_send({0x80, 0xCA, 0x00, 0xE0, 0x00}); sci2c_status("Status key send: "); sci2c_apdu_recv(0x17+1); // R-APDU size + 1 byte PBC sci2c_status("Status key recv: "); // Again exchanges APDU from exmaple chapter sci2c_apdu_send({0x00, 0xA4, 0x04, 0x04, 0x04, 0x54, 0x65, 0x73, 0x74, 0x00}); sci2c_status("Status Test send: "); sci2c_apdu_recv(3+1); // R-APDU size + 1 byte PBC sci2c_status("Status Test recv: "); Serial.println("Done!\n"); } //-------------------------------------------------------------------------- void loop() { delay(100); } 


للعمل مع منفذ I2C ، استخدمت مكتبة الأسلاك القياسية. يجب أن أقول على الفور أن هذه المكتبة ليست مناسبة للتنفيذ الكامل لبروتوكول البطاقة الذكية I2C ، لأنه لا يسمح بالتحكم في ACK و NACK عند إرسال وقراءة وحدات البايت الفردية ، وهو أمر مطلوب لتنفيذ الاستقبال الصحيح للبيانات متغيرة الطول من البطاقة الذكية.

نعم ، والأمثلة المعتادة من Wire Wire لم تنجح في المرة الأولى ، ولكن بعد بعض الرقص باستخدام لوحة مفاتيح الدف ، عدة لترات من القهوة ، googling في Yandex و Yandex في Google ، تم العثور على حل.

 Wire.write ( ); Wire.endTransmission (false); Wire.requestFrom (ADDR_A7001, 2, true); 

بناءً على وثائق المكتبة ، لا يقوم هذا التصميم بإصدار ناقل I2C بعد استدعاء endTransmission . لكن اتضح أنه بالنسبة للوحدة النمطية المستندة إلى ESP32 التي استخدمتها ، لا يحدث نقل البيانات فعليًا أثناء استدعاء endTransmission (false) ، كما هو مكتوب في وثائق مكتبة Wire ، ولكن أثناء استدعاء requestFrom (صواب) ، بينما يتم وضع البيانات في قائمة الانتظار فقط قبل هذا لنقل.

بالنظر إلى هذه القيود ، اضطررت إلى القيام ببعض "العكازات" ، لكنني أردت حقًا إطلاق شريحة A7001 دون إعادة كتابة المكتبات القياسية. لهذا السبب ، لم يتم تنفيذ معالجة خطأ البروتوكول ، ولم يكن من الممكن أيضًا استلام بيانات ذات طول متغير (أي ، ستحتاج دائمًا إلى تحديد عدد وحدات البايت المطلوب قراءتها).

هذه القيود غير مسموح بها في نظام حقيقي ، ولكنها ليست ضرورية لإظهار استخدام أوامر APDU عند العمل على ناقل I2C. لذلك ، إذا حدث خطأ في بروتوكول التبادل عند تبادل البيانات من خلال منفذ I2C ، فإن مفتاح تبديل الطاقة هو مفتاحنا.
بمعنى آخر ، إذا كان كل شيء يعمل أثناء تكرار هذه التجارب وتوقف فجأة قبل البحث عن خطأ في التعليمات البرمجية ، فقم بإيقاف تشغيل الطاقة وتشغيلها. مع درجة عالية من الاحتمال هذا يمكن أن يحل المشكلة.

أمثلة التعليمات البرمجية للعمل مع شريحة A7001


في الأمثلة ، أستخدم العديد من وظائف المساعد:

vect_dump - إخراج بيانات التفريغ في تنسيق HEX إلى منفذ التصحيح ؛
sci2c_exchange - إرسال مجموعة من البيانات عبر I2C وقراءة العدد المحدد من بايت استجابة ؛
sci2c_status - اقرأ حالة استجابة الدائرة الدقيقة ، وإذا لزم الأمر ، اعرض حالتها في منفذ التصحيح ؛
sci2c_apdu_send - إرسال أمر APDU ؛
sci2c_apdu_recv - قراءة الاستجابة للأمر APDU.

رقاقة تهيئة


وفقًا لوصف بروتوكول البطاقة الذكية I2C ، قبل البدء في العمل مع الشريحة ، يجب تنفيذ ثلاثة أوامر بالتسلسل: إعادة التشغيل (إعادة تعيين الباردة أو اللينة) ، قراءة ATR (قراءة الإجابة على إعادة التعيين) وإعداد معلمات التبادل (معلمة تبادل الأجهزة الرئيسية). وفقط بعد ذلك الشريحة مستعدة لقبول أوامر APDU.

إعادة تعيين لينة


كل شيء بسيط هنا ، نرسل أمر إعادة التشغيل وننتظر الوقت المحدد:

 sci2c_exchange ({0b00011111}, 2); delay(5); //      (tRSTG, time, ReSeT Guard) 

قراءة إجابة لإعادة تعيين


قراءة ATR قليلا أكثر تعقيدا ، كما لا تحتاج فقط إلى إرسال أمر ، ولكن أيضًا قراءة بيانات الاستجابة. وفقًا لوصف البروتوكول ، يمكن أن يكون الحد الأقصى لحجم البيانات التي تم إرجاعها CDBATS ، MAX (بايت بيانات الأوامر ، الإجابة على إعادة التعيين ، MAXimum) 29 بايت.

 vect ATR = sci2c_exchange({0b101111}, 29+2); // 29  + 1  PCB + 1  —   vect_dump("ATR: ", ATR); 

قراءة بيانات ATR: 1E 00 00 00 B8 03 11 01 05 B9 02 01 01 BA 01 01 BB 0D 41 37 30 30 31 43 47 20 32 34 32 52 31

حيث 1E هو حجم البيانات التي تم إرجاعها (29 بايت + 1 بايت من PCB) و 00 هو PCB (بروتوكول التحكم في البايت) ، والذي يجب أن يكون مساوياً لـ 0 ، وعلى ما يبدو ، في هذا المثال لم تتم قراءة البيانات بشكل صحيح (يجب أن يكون هناك بايت واحد من PCB ، وهناك ثلاثة منهم).

فيما يلي البيانات المشفرة بتنسيق TLV:

B8h - كائن بيانات ذو مستوى منخفض ، حجم 3 بايت ( 11h 01h 05h ) ؛
B9h - كائن بيانات ربط البروتوكول ، 2 بايت في الحجم ( 01h 01h ) ؛
BAh - كائن بيانات الطبقة العليا ، 1 بايت ( 01h ) في الحجم ؛
BBh - كائن بيانات نظام التشغيل ، 13 بايت ( 41 37 30 30 31 43 47 20 32 34 32 52 31 ).

فك التشفير من قراءة التكوين للرقاقة
كائن بيانات منخفض المستوى : 11 ساعة - الإصدارات الرئيسية والثانوية للبروتوكول المدعوم.

رموز اكتشاف الأخطاء : 01 ساعة - دعم الكشف عن الأخطاء ومراقبة تكامل البيانات المرسلة باستخدام LRC (رمز التكرار الطولي).

إطار انتظار عدد صحيح (FWI) : 05h - أقصى تأخير بين أمرين. يمكن أن يتراوح مدى القيم من 10 مللي ثانية إلى 5120 مللي ثانية ، الافتراضي هو 5120 مللي ثانية. يتم حساب القيمة بواسطة المعادلة T = 10ms x 2 ^ FWI. وهو ما يعطينا في هذه الحالة تأخيرًا قدره 320 مللي ثانية (10 مللي ثانية × 2 ^ 5).

كائن بيانات ربط البروتوكول - يتكون من قيمتين ، 01h 01h ، والتي تشفر البروتوكول المدعوم والبروتوكول الافتراضي. تعني هذه القيم دعمًا لبروتوكول APDU [GOST R ISO / IEC 7816-3-2013] ، وكما تعتقد ، يتم تثبيت نفس البروتوكول افتراضيًا.

كائن بيانات الطبقة العليا - الرقم 01h يعني دعم تنسيق APDU القصير والممتد.

كائن بيانات نظام التشغيل هو معرف يصل حجمه إلى 15 بايت ، كما هو محدد في المعيار [GOST R ISO / IEC 7816-4-2013]. في حالتنا ، هذه هي السلسلة " A7001CG 242R1 ".

ماجستير تبادل الأجهزة المعلمة


آخر أمر لتهيئة إعدادات التبادل:

 vect CDB = sci2c_exchange({0b11111111}, 2); sci2c_status("Status CDB: "); vect_dump("CDB: ", CDB, 1); 

قيمة الإرجاع: CCh - (11001100b) وفقًا لورقة البيانات ، يجب أن تكون 4 و 5 بتات إنكسارًا ثابتًا للبتين 2 و 3 (رموز NNb CDBIMS سالبة البتة ، MAX) ، وفقًا للقيمة المشفرة ، تدعم الرقاقة الحد الأقصى لحجم الأمر الممكن وهو 252 بايت CDBIMS قيمة MAX (عدد صحيح لبايت بيانات الأوامر ، ماجستير إلى الرقيق ، MAXimum).

وفقًا لوصف البروتوكول ، بعد تنفيذ هذه الأوامر الثلاثة وبهذا الترتيب ، فإن الدائرة الدقيقة مستعدة لتنفيذ أوامر APDU المعتادة (على الرغم من أنها تعمل بدون ضبط معلمات التبادل ، أي أنها كانت كافية لإجراء "إعادة تعيين Soft" وقراءة ATR).

تنفيذ أوامر APDU


تتكون كل دورة من تنفيذ أوامر APDU من الخطوات التالية:

  1. إرسال APDU (ماجستير لنقل الرقيق قيادة البيانات).
  2. انتظر وقت الحماية لاستلام ومعالجة الأمر.
  3. انتظر معالجة الأمر لقراءة الحالة (أمر الحالة).
  4. قراءة بيانات الاستجابة (الأمر من الرقيق إلى ماجستير نقل البيانات).

يتم تطبيق هذا المنطق في الدالتين sci2c_apdu_send و sci2c_apdu_recv ، وهناك نقطة مهمة هنا: في تنسيق بروتوكول بروتوكول البطاقة الذكية I2C ، توجد عدادات أوامر APDU المنقولة. يجب أن تتحكم هذه العدادات في أجهزة Master و Slave وأن تكون مصممة للتحكم في تسلسل البيانات المرسلة ، بحيث في حالة حدوث خطأ في الاستقبال ، يمكن إرسال أو طلب بيانات APDU مرة أخرى.

يمكن العثور على أمثلة لتنفيذ هذه الوظائف في الكود ، وفيما يلي أوامر APDU وبيانات الاستجابة فقط.

مثال من ورقة البيانات:


C-APDU => 00 A4 04 04 04 54 65 73 74 00 - اقرأ الملف باسم "اختبار".
R-APDU <= 6A 86 - وفقًا لورقة البيانات ، يجب أن يكون الجواب 64 82 ( لم يتم العثور على الملف أو التطبيق ) ، ولكن في حالتنا يتم تحميل البرنامج الثابت على الدائرة الصغيرة ، ويختلف الجواب عن المثال الموضح في الوثائق.

دورة قراءة إنتاج بطاقة حياة


C-APDU => 80 CA 9F 7F 00
R-APDU <= 9F 7F 2A 47 90 51 67 47 91 12 10 38 00 53 56 00 40 39 93 73 50 48 12 53 63 00 00 00 00 13 2C 19 30 34 30 33 39 00 00 00 00 00 00 00 00 90 00

قراءة قراءة معلومات البطاقة



C-APDU => 80 CA 00 66 00
R-APDU <= 66 4C 73 4A 06 07 2A 86 48 86 FC 6B 01 60 0C 06 0A 2A 86 48 86 FC 6B 02 02 01 01 63 09 06 07 2A 86 48 86 FC 6B 03 64 0B 06 09 2A 86 48 86 FC 6B 04 02 55 65 0B 06 09 2B 85 10 86 48 64 02 01 03 66 0C 06 0A 2B 06 01 04 01 2A 02 6E 01 02 90 00

قراءة قراءة معلومات مفتاح


C-APDU => 80 CA 00 E0 00
R-APDU <= E0 12 C0 04 01 FF 80 10 C0 04 02 FF 80 10 C0 04 03 FF 80 10 90 00

في الختام


كانت تجربة تنفيذ تبادل فرق APDU من خلال واجهة I2C ممتعة للغاية. حتى أنني وجدت نفسي أفكر عدة مرات في أنني أستمتع بحل مختلف القضايا من مجال الدارات ، وأيضاً من اللحام العادي ، منذ آخر مرة اضطررت فيها إلى حمل مكواة لحام منذ أكثر من 5 سنوات.

آمل أن تكون هذه المقالة مفيدة وتساعد على فهم المهتمين بهذا الموضوع. اكتب إذا كانت المادة تهمك. سأحاول الإجابة على جميع الأسئلة الواردة في هذه المقالة ، وإذا كان موضوع استخدام بروتوكول البطاقة الذكية I2C ممتعًا ، فسأحاول الكشف عنه بمزيد من التفاصيل في المنشورات التالية.

المراجع


Source: https://habr.com/ru/post/ar439574/


All Articles