วิธีเข้ารหัสไบต์โดยใช้ TPM (Trusted Platform Module)


110

ฉันจะเข้ารหัสไบต์โดยใช้โมดูล TPM ของเครื่องได้อย่างไร

CryptProtectData

Windows มี API ที่เรียบง่าย (ค่อนข้าง) เพื่อเข้ารหัส blob โดยใช้CryptProtectDataAPI ซึ่งเราสามารถรวมฟังก์ชันที่ใช้งานง่าย:

public Byte[] ProtectBytes(Byte[] plaintext)
{
   //...
}

รายละเอียดProtectBytesมีความสำคัญน้อยกว่าแนวคิดที่คุณสามารถใช้ได้อย่างง่ายดาย:

  • นี่คือไบต์ที่ฉันต้องการเข้ารหัสโดยคีย์ลับที่อยู่ในไฟล์ System
  • คืนหยดที่เข้ารหัสให้ฉัน

หยดที่ส่งคืนเป็นโครงสร้างเอกสารที่ไม่มีเอกสารซึ่งมีทุกอย่างที่จำเป็นในการถอดรหัสและส่งคืนข้อมูลต้นฉบับ (อัลกอริทึมแฮชอัลกอริทึมการเข้ารหัสเกลือลายเซ็น HMAC ฯลฯ )

เพื่อความสมบูรณ์นี่คือตัวอย่างการใช้งานรหัสเทียมProtectBytesที่ใช้Crypt APIเพื่อป้องกันไบต์:

public Byte[] ProtectBytes(Byte[] plaintext)
{
   //Setup our n-byte plaintext blob
   DATA_BLOB dataIn;
   dataIn.cbData = plaintext.Length;
   dataIn.pbData = Addr(plaintext[0]);

   DATA_BLOB dataOut;

   //dataOut = EncryptedFormOf(dataIn)
   BOOL bRes = CryptProtectData(
         dataIn,
         null,     //data description (optional PWideChar)
         null,     //optional entropy (PDATA_BLOB)
         null,     //reserved
         null,     //prompt struct
         CRYPTPROTECT_UI_FORBIDDEN || CRYPTPROTECT_LOCAL_MACHINE,
         ref dataOut);
   if (!bRes) then
   {
      DWORD le = GetLastError();
      throw new Win32Error(le, "Error calling CryptProtectData");
   }

   //Copy ciphertext from dataOut blob into an actual array
   bytes[] result;
   SetLength(result, dataOut.cbData);
   CopyMemory(dataOut.pbData, Addr(result[0]), dataOut.cbData);

   //When you have finished using the DATA_BLOB structure, free its pbData member by calling the LocalFree function
   LocalFree(HANDLE(dataOut.pbData)); //LocalFree takes a handle, not a pointer. But that's what the SDK says.
}

จะทำเช่นเดียวกันกับ TPM ได้อย่างไร?

รหัสด้านบนมีประโยชน์สำหรับการเข้ารหัสข้อมูลสำหรับเครื่องภายในเท่านั้น ข้อมูลถูกเข้ารหัสโดยใช้Systemบัญชีเป็นตัวสร้างคีย์ ( รายละเอียดในขณะที่น่าสนใจไม่สำคัญ ) ผลลัพธ์สุดท้ายคือฉันสามารถเข้ารหัสข้อมูล (เช่นมาสเตอร์คีย์การเข้ารหัสฮาร์ดไดรฟ์) ที่สามารถถอดรหัสได้โดยเครื่องภายในเท่านั้น

ตอนนี้ถึงเวลาที่จะก้าวไปอีกขั้น ฉันต้องการเข้ารหัสข้อมูลบางอย่าง (เช่นคีย์หลักสำหรับการเข้ารหัสฮาร์ดไดรฟ์) ที่สามารถถอดรหัสได้โดย TPM ในเครื่องเท่านั้น กล่าวอีกนัยหนึ่งฉันต้องการแทนที่ Qualcomm Trusted Execution Environment ( TEE ) ในแผนภาพบล็อกด้านล่างสำหรับ Android ด้วย TPM ใน Windows:

ใส่คำอธิบายภาพที่นี่

หมายเหตุ : ฉันตระหนักดีว่า TPM ไม่ได้ทำการลงนามข้อมูล (หรือถ้าเป็นเช่นนั้นก็ไม่รับประกันว่าการลงนามในข้อมูลเดียวกันจะให้ผลลัพธ์ไบนารีเดียวกันทุกครั้ง) ซึ่งเป็นเหตุผลที่ฉันต้องการจะยินดีที่จะเข้ามาแทนที่"อาร์เอสลงนาม"กับ"การเข้ารหัสหยด 256 บิตพร้อมคีย์ฮาร์ดแวร์ผูกพัน"

แล้วรหัสอยู่ไหน?

ปัญหาคือว่าการเขียนโปรแกรมเป็น TPM ไม่มีเอกสารสมบูรณ์ใน MSDN ไม่มี API สำหรับดำเนินการใด ๆ แต่คุณต้องหาสำเนาของSoftware StackของTrusted Computing Group (aka TSS)ให้หาคำสั่งที่จะส่งไปยัง TPM โดยมี payloads เรียงลำดับตามลำดับและเรียกใช้ฟังก์ชันTbsip_Submit_Commandของ Windowเพื่อส่งคำสั่งโดยตรง:

TBS_RESULT Tbsip_Submit_Command(
  _In_     TBS_HCONTEXT hContext,
  _In_     TBS_COMMAND_LOCALITY Locality,
  _In_     TBS_COMMAND_PRIORITY Priority,
  _In_     const PCBYTE *pabCommand,
  _In_     UINT32 cbCommand,
  _Out_    PBYTE *pabResult,
  _Inout_  UINT32 *pcbOutput
);

Windows ไม่มี API ระดับที่สูงกว่าเพื่อดำเนินการ

มันเทียบเท่าศีลธรรมในการพยายามสร้างไฟล์ข้อความโดยการออกคำสั่ง SATA I / O ไปยังฮาร์ดไดรฟ์ของคุณ

ทำไมไม่ใช้แค่กางเกง

ของ Trusted Computing Group (TCG) ได้กำหนด API ของตัวเอง: TCB ซอฟท์แวสแต็ค (TSS) การดำเนินการของ API นี้ถูกสร้างขึ้นโดยคนบางคนและถูกเรียกว่ากางเกงขายาว ผู้ชายแล้วรังเพลิงโครงการที่เป็น Windows

ปัญหาเกี่ยวกับรหัสนั้นคือไม่สามารถพกพาเข้าสู่โลกของ Windows ได้ ตัวอย่างเช่นคุณไม่สามารถใช้งานจาก Delphi คุณไม่สามารถใช้จาก C # ได้ มันต้องการ:

  • OpenSSL
  • pThread

ฉันแค่ต้องการให้รหัสเข้ารหัสบางอย่างกับ TPM ของฉัน

ข้างต้นCryptProtectDataไม่ต้องการอะไรนอกจากสิ่งที่อยู่ในตัวฟังก์ชัน

รหัสเทียบเท่าในการเข้ารหัสข้อมูลโดยใช้ TPM คืออะไร? เป็นคนอื่นได้ตั้งข้อสังเกตคุณอาจจะต้องปรึกษาคู่มือ TPM สามและสร้าง blobs ด้วยตัวคุณเอง มันอาจเกี่ยวข้องกับTPM_sealคำสั่ง แม้ว่าฉันคิดว่าฉันไม่ต้องการปิดผนึกข้อมูล แต่ฉันคิดว่าฉันต้องการผูกมัน:

Binding - เข้ารหัสข้อมูลโดยใช้คีย์การผูก TPM ซึ่งเป็นคีย์ RSA ที่ไม่ซ้ำกันซึ่งสืบเชื้อสายมาจากคีย์จัดเก็บข้อมูล การปิดผนึก - เข้ารหัสข้อมูลในลักษณะเดียวกันกับการผูก แต่นอกจากนี้ยังระบุสถานะที่ต้องอยู่ใน TPM เพื่อให้ข้อมูลถูกถอดรหัส (เปิดผนึก)

ฉันพยายามอ่านทั้งสามเล่มที่ต้องการเพื่อค้นหารหัส 20 บรรทัดที่ฉันต้องการ:

แต่ก็ต้องไม่มีความคิดสิ่งที่ฉันอ่าน หากมีบทช่วยสอนหรือตัวอย่างใด ๆ ฉันอาจต้องถ่ายทำ แต่ฉันหลงทางไปแล้ว

ดังนั้นเราขอให้ Stackoverflow

ในทำนองเดียวกันฉันสามารถให้:

Byte[] ProtectBytes_Crypt(Byte[] plaintext)
{
   //...
   CryptProtectData(...); 
   //...
}

ใครสามารถจัดหาสิ่งที่เทียบเท่ากันได้:

Byte[] ProtectBytes_TPM(Byte[] plaintext)
{
   //...
   Tbsip_Submit_Command(...);
   Tbsip_Submit_Command(...);
   Tbsip_Submit_Command(...);
   //...snip...
   Tbsip_Submit_Command(...);
   //...
}

ที่ทำสิ่งเดียวกันยกเว้นแทนที่จะล็อคกุญแจในSystemLSA ถูกล็อคใน TPM?

จุดเริ่มต้นของการวิจัย

ฉันไม่รู้ว่าการผูกหมายถึงอะไร แต่เมื่อดู TPM Main - คำสั่งส่วนที่ 3 - ข้อมูลจำเพาะเวอร์ชัน 1.2 มีการกล่าวถึงการผูก :

10.3 TPM_UnBind

TPM_UnBind รับข้อมูลหยดที่เป็นผลลัพธ์ของคำสั่ง Tspi_Data_Bind และถอดรหัสเพื่อส่งออกไปยังผู้ใช้ ผู้โทรต้องอนุญาตให้ใช้คีย์ที่จะถอดรหัสหยดน้ำที่เข้ามา TPM_UnBind ทำงานแบบบล็อกต่อบล็อกและไม่มีความสัมพันธ์ใด ๆ ระหว่างบล็อกหนึ่งกับอีกบล็อกหนึ่ง

สิ่งที่ทำให้สับสนคือไม่มีTspi_Data_Bindคำสั่ง

ความพยายามในการวิจัย

เป็นเรื่องที่น่าสยดสยองที่ไม่มีใครใส่ใจในการบันทึก TPM หรือการทำงานของมัน ราวกับว่าพวกเขาใช้เวลาทั้งหมดในการคิดหาสิ่งที่ยอดเยี่ยมนี้มาเล่นด้วย แต่ไม่ต้องการจัดการกับขั้นตอนที่เจ็บปวดในการทำให้มันใช้งานได้กับบางสิ่งบางอย่าง

เริ่มต้นด้วยหนังสือฟรี (ตอนนี้) คู่มือปฏิบัติสำหรับ TPM 2.0: การใช้โมดูลแพลตฟอร์มที่เชื่อถือได้ในยุคใหม่ของการรักษาความปลอดภัย :

บทที่ 3 - บทช่วยสอนด่วนเกี่ยวกับ TPM 2.0

TPM สามารถเข้าถึงคีย์ส่วนตัวที่สร้างขึ้นเองได้ดังนั้นจึงสามารถเข้ารหัสคีย์ด้วยคีย์สาธารณะจากนั้นจัดเก็บ Blob ที่เป็นผลลัพธ์ไว้ในฮาร์ดดิสก์ ด้วยวิธีนี้ TPM สามารถเก็บคีย์ไว้ใช้ได้ไม่ จำกัด จำนวน แต่ไม่ต้องเสียที่จัดเก็บข้อมูลภายในอันมีค่า สามารถลบคีย์ที่จัดเก็บไว้ในฮาร์ดดิสก์ได้ แต่ก็สามารถสำรองข้อมูลได้เช่นกันซึ่งดูเหมือนว่านักออกแบบจะชอบการแลกเปลี่ยนที่ยอมรับได้

ฉันจะเข้ารหัสคีย์ด้วยคีย์สาธารณะของ TPM ได้อย่างไร

บทที่ 4 - แอปพลิเคชันที่มีอยู่ซึ่งใช้ TPM

แอปพลิเคชันที่ควรใช้ TPM แต่ไม่ควรใช้

ในช่วงไม่กี่ปีที่ผ่านมาจำนวนแอปพลิเคชันบนเว็บเพิ่มขึ้น การสำรองข้อมูลและการจัดเก็บข้อมูลทางเว็บ ขณะนี้ บริษัท จำนวนมากเสนอบริการดังกล่าว แต่เท่าที่เราทราบไม่มีลูกค้ารายใดสำหรับบริการเหล่านี้ที่อนุญาตให้ผู้ใช้ล็อกคีย์สำหรับบริการสำรองข้อมูลไปยัง TPM หากทำเสร็จแล้วจะเป็นการดีอย่างแน่นอนหากคีย์ TPM ได้รับการสำรองข้อมูลโดยการทำซ้ำบนหลายเครื่อง ดูเหมือนว่าจะเป็นโอกาสสำหรับนักพัฒนา

นักพัฒนาจะล็อคคีย์ของ TPM ได้อย่างไร?

บทที่ 9 - Heirarchies

ใช้กรณี: การจัดเก็บรหัสผ่านเข้าสู่ระบบ

ไฟล์รหัสผ่านทั่วไปจะเก็บแฮชรหัสผ่านที่เค็ม การตรวจสอบประกอบด้วยการใส่เกลือและแฮชรหัสผ่านที่ให้มาและเปรียบเทียบกับค่าที่จัดเก็บไว้ เนื่องจากการคำนวณไม่มีความลับจึงอาจมีการโจมตีไฟล์รหัสผ่านแบบออฟไลน์

กรณีการใช้งานนี้ใช้คีย์ HMAC ที่สร้างโดย TPM ไฟล์รหัสผ่านจะเก็บ HMAC ของรหัสผ่านแบบเค็ม การตรวจสอบประกอบด้วยการใส่เกลือและ HMAC การใส่รหัสผ่านที่ให้มาและเปรียบเทียบกับค่าที่จัดเก็บไว้ เนื่องจากผู้โจมตีออฟไลน์ไม่มีคีย์ HMAC ผู้โจมตีจึงไม่สามารถทำการโจมตีได้ด้วยการคำนวณ

สิ่งนี้สามารถใช้ได้ หาก TPM มีคีย์ HMAC ลับและมีเพียง TPM ของฉันเท่านั้นที่รู้คีย์ HMAC ฉันสามารถแทนที่ "Sign (หรือที่เรียกว่า TPM เข้ารหัสด้วยคีย์ส่วนตัว)" ด้วย "HMAC" แต่ในบรรทัดถัดไปเขากลับตัวเองโดยสิ้นเชิง:

TPM2_Create ระบุคีย์ HMAC

ไม่ใช่ความลับ TPM ถ้าฉันต้องระบุคีย์ HMAC ความจริงที่ว่าคีย์ HMAC ไม่ใช่ความลับก็สมเหตุสมผลเมื่อคุณรู้ว่านี่คือบทเกี่ยวกับยูทิลิตี้การเข้ารหัสที่ TPM มีให้ แทนที่จะต้องเขียน SHA2, AES, HMAC หรือ RSA ด้วยตัวเองคุณสามารถใช้สิ่งที่ TPM วางไว้รอบ ๆ ได้อีกครั้ง

บทที่ 10 - คีย์

ในฐานะอุปกรณ์รักษาความปลอดภัยความสามารถของแอปพลิเคชันในการใช้คีย์ในขณะที่รักษาความปลอดภัยในอุปกรณ์ฮาร์ดแวร์ถือเป็นจุดแข็งที่สุดของ TPM TPM สามารถสร้างและนำเข้าคีย์ที่สร้างจากภายนอกได้ รองรับทั้งคีย์แบบไม่สมมาตรและแบบสมมาตร

ยอดเยี่ยม! คุณจะทำอย่างไรมันได้หรือไม่!?

ตัวสร้างคีย์

จุดแข็งที่ยิ่งใหญ่ที่สุดของ TPM คือความสามารถในการสร้างคีย์การเข้ารหัสและปกป้องความลับภายในขอบเขตฮาร์ดแวร์ ตัวสร้างคีย์ขึ้นอยู่กับตัวสร้างตัวเลขสุ่มของ TPM และไม่อาศัยแหล่งที่มาของการสุ่มจากภายนอก ดังนั้นจึงกำจัดจุดอ่อนที่อาศัยซอฟต์แวร์ที่อ่อนแอซึ่งมีแหล่งเอนโทรปีไม่เพียงพอ

ไม่ TPM มีความสามารถในการสร้างคีย์การเข้ารหัสลับและปกป้องความลับภายในขอบเขตฮาร์ดแวร์? เป็นเช่นนั้นอย่างไร?

บทที่ 12 - การลงทะเบียนการกำหนดค่าแพลตฟอร์ม

PCR สำหรับการอนุญาต

ใช้กรณี: การปิดผนึกการเข้ารหัสฮาร์ดดิสก์ที่สำคัญสำหรับรัฐแพลตฟอร์ม

แอปพลิเคชันการเข้ารหัสแบบเต็มดิสก์มีความปลอดภัยมากกว่าหาก TPM ปกป้องคีย์การเข้ารหัสมากกว่าที่จะเก็บไว้ในดิสก์เดียวกันซึ่งป้องกันด้วยรหัสผ่านเท่านั้น ประการแรกฮาร์ดแวร์ TPM มีการป้องกันการตอก (ดูบทที่ 8 สำหรับคำอธิบายโดยละเอียดของการป้องกันการโจมตีด้วยพจนานุกรม TPM) ทำให้การโจมตีด้วยความดุร้ายในรหัสผ่านไม่สามารถทำได้ คีย์ที่ป้องกันโดยซอฟต์แวร์เท่านั้นที่มีความเสี่ยงต่อรหัสผ่านที่ไม่รัดกุม ประการที่สองคีย์ซอฟต์แวร์ที่เก็บไว้ในดิสก์นั้นขโมยได้ง่ายกว่ามาก นำดิสก์ (หรือข้อมูลสำรองของดิสก์) และคุณจะได้รับกุญแจ เมื่อ TPM ถือกุญแจแพลตฟอร์มทั้งหมดหรืออย่างน้อยก็คือดิสก์และเมนบอร์ดจะต้องถูกขโมย

การปิดผนึกอนุญาตให้คีย์ได้รับการปกป้องไม่เพียง แต่ด้วยรหัสผ่าน แต่โดยนโยบาย นโยบายทั่วไปจะล็อกคีย์ของค่า PCR (สถานะซอฟต์แวร์) ปัจจุบันในขณะปิดผนึก สิ่งนี้จะถือว่าสถานะในการบูตครั้งแรกไม่ถูกบุกรุก มัลแวร์ที่ติดตั้งไว้ล่วงหน้าใด ๆ ที่มีอยู่ในการบูตครั้งแรกจะถูกวัดลงใน PCR ดังนั้นคีย์จะถูกปิดผนึกให้อยู่ในสถานะซอฟต์แวร์ที่ถูกบุกรุก องค์กรที่มีความน่าเชื่อถือน้อยกว่าอาจมีดิสก์อิมเมจมาตรฐานและประทับตราเป็น PCR ที่เป็นตัวแทนของอิมเมจนั้น ค่า PCR เหล่านี้จะถูกคำนวณล่วงหน้าบนแพลตฟอร์มที่น่าเชื่อถือมากกว่า องค์กรที่มีความซับซ้อนยิ่งขึ้นจะใช้ TPM2_PolicyAuthorize และจัดเตรียมตั๋วหลายใบที่อนุญาตชุดค่า PCR ที่เชื่อถือได้ ดูบทที่ 14 สำหรับคำอธิบายโดยละเอียดเกี่ยวกับการอนุญาตนโยบายและการประยุกต์ใช้เพื่อแก้ปัญหา PCRbrittleness

แม้ว่ารหัสผ่านจะสามารถป้องกันคีย์ได้ แต่ก็ยังได้รับความปลอดภัยแม้ว่าจะไม่มีรหัสผ่านคีย์ TPM ก็ตาม ผู้โจมตีสามารถบูตแพลตฟอร์มได้โดยไม่ต้องให้รหัสผ่าน TPMkey แต่ไม่สามารถเข้าสู่ระบบได้หากไม่มีชื่อผู้ใช้และรหัสผ่านของระบบปฏิบัติการ ความปลอดภัยของระบบปฏิบัติการปกป้องข้อมูล ผู้โจมตีสามารถบูตระบบปฏิบัติการทางเลือกได้เช่นจากดีวีดีสดหรือแท่ง USB แทนที่จะใช้จากฮาร์ดไดรฟ์เพื่อหลีกเลี่ยงความปลอดภัยในการเข้าสู่ระบบระบบปฏิบัติการ อย่างไรก็ตามการกำหนดค่าการบูตและซอฟต์แวร์ที่แตกต่างกันนี้จะเปลี่ยนค่า PCR เนื่องจาก PCR ใหม่เหล่านี้ไม่ตรงกับค่าที่ปิดผนึก TPM จะไม่คลายคีย์การถอดรหัสและไม่สามารถถอดรหัสฮาร์ดไดรฟ์ได้

ยอดเยี่ยม! นี่คือกรณีการใช้งานที่ฉันต้องการ นอกจากนี้ยังเป็นกรณีการใช้งานที่ Microsoft ใช้ TPM สำหรับ. ฉันต้องทำอย่างไร!?

ฉันจึงอ่านหนังสือทั้งเล่มและไม่มีประโยชน์อะไรเลย ซึ่งค่อนข้างน่าประทับใจเพราะมัน 375 หน้า คุณสงสัยว่าหนังสือเล่มนี้มีอะไรบ้าง - และเมื่อมองย้อนกลับไปฉันไม่รู้

ดังนั้นเราจึงเลิกใช้คำแนะนำขั้นสุดท้ายในการเขียนโปรแกรม TPM และหันไปหาเอกสารจาก Microsoft แทน:

จากไมโครซอฟท์ TPM แพลตฟอร์มเข้ารหัสลับของผู้ให้บริการเครื่องมือ มันกล่าวถึงสิ่งที่ฉันต้องการทำ:

คีย์การรับรองหรือ EK

EK ได้รับการออกแบบมาเพื่อให้ตัวระบุการเข้ารหัสที่เชื่อถือได้สำหรับแพลตฟอร์ม องค์กรอาจเก็บรักษาฐานข้อมูลของคีย์การรับรองที่เป็นของ TPM ของพีซีทั้งหมดในองค์กรของตนหรือผู้ควบคุมแฟบริกของศูนย์ข้อมูลอาจมีฐานข้อมูลของ TPM ในเบลดทั้งหมด ใน Windows คุณสามารถใช้ผู้ให้บริการ NCrypt ที่อธิบายไว้ในส่วน“ Platform Crypto Provider ใน Windows 8” เพื่ออ่านส่วนสาธารณะของ EK

ที่ไหนสักแห่งใน TPM เป็นคีย์ส่วนตัว RSA กุญแจนั้นถูกล็อคไว้ที่นั่น - โลกภายนอกจะไม่เห็น ฉันต้องการให้ TPM เซ็นชื่อด้วยคีย์ส่วนตัว (เช่นเข้ารหัสด้วยคีย์ส่วนตัว)

ดังนั้นฉันต้องการการดำเนินการขั้นพื้นฐานที่สุดที่อาจมีอยู่:

ใส่คำอธิบายภาพที่นี่

เข้ารหัสบางอย่างด้วยคีย์ส่วนตัวของคุณ ฉันยังไม่ได้ขอสิ่งที่ซับซ้อนกว่านี้:

  • "ปิดผนึก"ตามสถานะ PCR
  • สร้างคีย์และจัดเก็บไว้ใน memroy ที่ระเหยหรือไม่ลบเลือน
  • สร้างคีย์สมมาตรและพยายามโหลดลงใน TPM

ฉันกำลังขอการดำเนินการขั้นพื้นฐานที่สุดที่ TPM สามารถทำได้ เหตุใดจึงไม่ได้รับข้อมูลเกี่ยวกับวิธีการทำ

ฉันสามารถรับข้อมูลแบบสุ่มได้

ฉันคิดว่าฉันเป็นคนกะล่อนเมื่อฉันบอกว่าการลงนาม RSA เป็นสิ่งพื้นฐานที่สุดที่ TPM สามารถทำได้ ที่สุดสิ่งที่เป็นพื้นฐาน TPM สามารถขอให้ทำคือให้ฉันไบต์สุ่ม ที่ผมได้คิดวิธีการทำ:

public Byte[] GetRandomBytesTPM(int desiredBytes)
{
   //The maximum random number size is limited to 4,096 bytes per call
   Byte[] result = new Byte[desiredBytes];

   BCRYPT_ALG_HANDLE hAlgorithm;

   BCryptOpenAlgorithmProvider(
         out hAlgorithm,
         BCRYPT_RNG_ALGORITHM, //AlgorithmID: "RNG"
         MS_PLATFORM_CRYPTO_PROVIDER, //Implementation: "Microsoft Platform Crypto Provider" i.e. the TPM
         0 //Flags
   );
   try
   {                
      BCryptGenRandom(hAlgorithm, @result[0], desiredBytes, 0);
   }
   finally
   {
      BCryptCloseAlgorithmProvider(hAlgorithm);
   }

   return result;
}

สิ่งแฟนซี

ฉันตระหนักดีว่าปริมาณผู้ใช้ TPM นั้นต่ำมาก นั่นคือเหตุผลที่ไม่มีใครใน Stackoverflow มีคำตอบ ดังนั้นฉันไม่สามารถโลภมากเกินไปในการหาวิธีแก้ปัญหาทั่วไปของฉัน แต่สิ่งที่อยากทำจริงๆคือ"ปิดผนึก"ข้อมูลบางส่วน:

ใส่คำอธิบายภาพที่นี่

  • นำเสนอข้อมูลบางอย่างของ TPM (เช่นข้อมูลสำคัญ 32 ไบต์)
  • ให้ TPM เข้ารหัสข้อมูลโดยส่งคืนโครงสร้างหยดทึบบางส่วน
  • ในภายหลังขอให้ TPM ถอดรหัสหยด
  • การถอดรหัสจะใช้ได้ก็ต่อเมื่อการลงทะเบียน PCR ของ TPM เหมือนกับการลงทะเบียนระหว่างการเข้ารหัส

กล่าวอีกนัยหนึ่ง:

Byte[] ProtectBytes_TPM(Byte[] plaintext, Boolean sealToPcr)
{
   //...
}

Byte[] UnprotectBytes_TPM(Byte[] protectedBlob)
{
   //...
}

Cryptography Next Gen (Cng หรือที่เรียกว่า BCrypt) รองรับ TPM

Cryptography API ดั้งเดิมใน Windows รู้จักกันในชื่อ Crypto API

ตั้งแต่ Windows Vista เป็นต้นมา Crypto API ได้ถูกแทนที่ด้วยCryptography API: Next Generation (รู้จักกันในชื่อBestCryptย่อว่าBCryptเพื่อไม่ให้สับสนกับอัลกอริทึมการแฮชรหัสผ่าน )

Windows มาพร้อมกับผู้ให้บริการ BCrypt สองราย :

แพลตฟอร์ม Cryptoผู้ให้บริการไม่ได้รับการบันทึกไว้ใน MSDN แต่มีเอกสารจากเว็บไซต์ที่ 2012 Microsoft การวิจัย:

TPM Platform Crypto-Provider Toolkit

ผู้ให้บริการ Crypto Platform Crypto และ Toolkit ของ TPM มีโค้ดตัวอย่างยูทิลิตี้และเอกสารประกอบสำหรับการใช้ฟังก์ชันที่เกี่ยวข้องกับ TPM ในระบบย่อย Windows 8 ที่อธิบายไว้รวมถึงผู้ให้บริการการเข้ารหัสลับแพลตฟอร์ม Crypto-Next-Gen (CNG) ที่สนับสนุน TPM และวิธีการที่ผู้ให้บริการรับรอง สามารถใช้คุณสมบัติใหม่ของ Windows รองรับทั้งระบบที่ใช้ TPM1.2 และ TPM2.0

ดูเหมือนว่าความตั้งใจของ Microsoft คือการแสดงฟังก์ชันการเข้ารหัสลับ TPM กับMicrosoft Platform Crypto ProviderของCryptography NG API

การเข้ารหัสคีย์สาธารณะโดยใช้ Microsoft BCrypt

ระบุว่า:

แนวทางต่อไปอาจเป็นการหาวิธีการลงนามดิจิทัลโดยใช้Microsoft Cryptography Next Gen APIAPI

ขั้นตอนต่อไปของฉันคือการสร้างรหัสเพื่อทำการเข้ารหัสใน BCrypt ด้วยคีย์สาธารณะ RSA โดยใช้ผู้ให้บริการมาตรฐาน ( MS_PRIMITIVE_PROVIDER) เช่น:

  • modulus: 0xDC 67 FA F4 9E F2 72 1D 45 2C B4 80 79 06 A0 94 27 50 8209 DD 67 CE 57 B8 6C 4A 4F 40 9F D2 D1 69 FB 995D 85 0C 07 A1 F9 47 1B 56 16 6E F6 7F B9 CF 2A 58 36 37 99 29 AA 4F A8 12 E8 4F C7 82 2B 9D 72 2A 9C DE 6F C2 EE 12 6D CF F0 F2 B8 C4 DD 7C 5C 1A C8 17 51 A9 AC DF 08 22 04 9D 2B D7 F9 4B 09 DE 9A EB 5C 51 1A D8 F8 F9 56 9E F8 FB 37 9B 3F D3 74 65 24 0D FF 34 75 57 A4 F5 BF 55
  • publicExponent: 65537

เมื่อรหัสนั้นทำงานฉันอาจสามารถเปลี่ยนไปใช้ผู้ให้บริการ TPM (MS_PLATFORM_CRYPTO_PROVIDER ) ได้

2/22/2016: และด้วยการที่ Apple ถูกบังคับให้ช่วยถอดรหัสข้อมูลผู้ใช้จึงมีความสนใจในการทำให้ TPM ทำงานที่ง่ายที่สุดที่คิดค้นขึ้นมาเพื่อเข้ารหัสบางสิ่ง

มันเทียบเท่ากับทุกคนที่เป็นเจ้าของรถ แต่ไม่มีใครรู้ว่าจะเริ่มต้นอย่างไร มันสามารถทำสิ่งที่มีประโยชน์และเจ๋ง ๆ ได้ถ้าเพียงเราผ่านขั้นตอนที่ 1ไปได้

การอ่านโบนัส


สำหรับการผูก (การเข้ารหัส) ไม่มีฟังก์ชันที่ชัดเจนและไม่จำเป็นต้องใช้ คุณเพียงแค่สร้างคีย์การผูกใน TPM และใช้ส่วนสาธารณะเพื่อเข้ารหัสคีย์การเข้ารหัสแบบสมมาตรด้วยฟังก์ชันการเข้ารหัส rsa ของระบบ ("RSA / ECB / OAEPWithSHA1AndMGF1Padding") และบันทึกไว้ในโครงสร้างที่ถูกต้อง ("TcTssConstants.TSS_ENCDATA_BIND") สำหรับการยกเลิกการผูก (ถอดรหัส) sek คุณเพียงแค่ใช้ฟังก์ชันคลายการผูก TPM และใช้ sek ในฟังก์ชันการเข้ารหัสแบบสมมาตรที่คุณต้องการ ฉันมีฐานรหัสที่ค่อนข้างเก่าสำหรับสิ่งที่ฉันทำเมื่อนานมาแล้วอาจช่วยได้: goo.gl/jV1Ouw
evildead

จากวิกิพีเดีย Binding - เข้ารหัสข้อมูลโดยใช้คีย์การผูก TPM ซึ่งเป็นคีย์ RSA ที่ไม่ซ้ำกันซึ่งสืบเชื้อสายมาจากคีย์จัดเก็บข้อมูล en.wikipedia.org/wiki/Trusted_Platform_Moduleดูเหมือนคำสั่งคู่นี้ (TSpi_Data_Bind / TPM_UnBind) น่าจะเพียงพอสำหรับความต้องการของคุณ ...
Alex Mazzariol

1
ฉันไม่คิดว่าคุณต้องใช้ TPM โดยตรง ได้รับการสนับสนุนผ่าน CNG / NCryptXXX API มาตรฐานและ "Microsoft Platform Crypto Provider" (สำหรับแพลตฟอร์ม Windows OS ล่าสุดและหากฮาร์ดแวร์ใช้ได้และเปิดใช้งานแน่นอน) บางทีคุณอาจลองดู "TPM Platform Crypto-Provider Toolkit ที่นี่: research.microsoft.com/en-us/downloads/…ตรวจสอบสิ่งนี้ด้วย: tiw2013.cse.psu.edu/slides/…
Simon Mourier

CryptProtectData ไม่จำเป็นต้องใช้ TPM ในทางกลับกันหากคุณได้รับ CNG หรือ CSP ที่ถูกต้องสำหรับ TPM คุณสามารถใช้มันในฟังก์ชัน crypto
Michael Chourdakis

1
@ b3nj1 ไม่ฉันไม่ได้; ไม่มีใครสามารถตอบคำถามได้
Ian Boyd

คำตอบ:


7

รองพื้น

ทั้งหมดที่ตามมาคือเกี่ยวกับ TPM 1.2 โปรดทราบว่า Microsoft ต้องการ TPM 2.0 สำหรับ Windows ทุกรุ่นในอนาคต รุ่น 2.0 มีความแตกต่างโดยพื้นฐานกับ 1.2

ไม่มีโซลูชันแบบบรรทัดเดียวเนื่องจากหลักการออกแบบ TPM คิดว่า TPM เป็นไมโครคอนโทรลเลอร์ที่มีทรัพยากร จำกัด เป้าหมายหลักในการออกแบบคือราคาถูกในขณะที่ยังคงปลอดภัย ดังนั้น TPM จึงถูกฉีกขาดจากตรรกะทั้งหมดซึ่งไม่จำเป็นสำหรับการดำเนินการที่ปลอดภัย ดังนั้น TPM จะใช้งานได้ก็ต่อเมื่อคุณมีซอฟต์แวร์ที่มีไขมันมากหรือน้อยอย่างน้อยที่สุดโดยออกคำสั่งจำนวนมากตามลำดับที่ถูกต้อง และลำดับของคำสั่งเหล่านั้นอาจซับซ้อนมาก นั่นเป็นเหตุผลที่ TCG ระบุ TSS ด้วย API ที่กำหนดไว้อย่างดี หากคุณต้องการไปทาง Java ก็มีแม้แต่Java APIระดับสูงAPI ฉันไม่ทราบโครงการที่คล้ายกันสำหรับ C # / .net

การพัฒนา

ในกรณีของคุณฉันขอแนะนำให้คุณดูซอฟต์แวร์ TPM ของ IBM

ในแพ็คเกจคุณจะพบส่วนประกอบที่มีประโยชน์ 3 อย่าง:

  • ซอฟต์แวร์จำลอง TPM
  • tpm lib ที่มีน้ำหนักเบา
  • ยูทิลิตี้บรรทัดคำสั่งพื้นฐานบางอย่าง

คุณไม่จำเป็นต้องใช้ซอฟต์แวร์จำลอง TPM คุณยังสามารถเชื่อมต่อกับ HW TPM ของเครื่องได้ อย่างไรก็ตามคุณสามารถสกัดกั้นคำสั่งที่ออกและดูการตอบสนองดังนั้นการเรียนรู้วิธีประกอบและวิธีที่สอดคล้องกับข้อกำหนดของคำสั่ง

ระดับสูง

ข้อกำหนดเบื้องต้น:

  1. เปิดใช้งาน TPM แล้ว
  2. โหลดไดรเวอร์ TPM แล้ว
  3. คุณเป็นเจ้าของ TPM

ในการปิดผนึกหยดคุณต้องทำสิ่งต่อไปนี้:

  1. สร้างคีย์
  2. เก็บกุญแจหยดไว้ที่ไหนสักแห่ง
  3. ตรวจสอบให้แน่ใจว่าคีย์ถูกโหลดใน TPM
  4. ปิดผนึกหยด

ในการเปิดผนึกคุณต้อง:

  1. รับคีย์หยด
  2. โหลดคีย์ไปที่ TPM
  3. เปิดผนึกหยดที่ปิดสนิท

คุณสามารถจัดเก็บ key-blob ในโครงสร้างข้อมูลของคุณที่คุณใช้จัดเก็บไบต์ที่มีการป้องกัน

คำสั่ง TPM ส่วนใหญ่ที่คุณต้องการคือคำสั่งที่ได้รับอนุญาต ดังนั้นคุณต้องสร้างเซสชันการอนุญาตในกรณีที่จำเป็น AFAIR เหล่านี้ส่วนใหญ่เป็นเซสชัน OSAP

คำสั่ง TPM

ขณะนี้ฉันไม่สามารถเรียกใช้เวอร์ชันดีบักได้ดังนั้นฉันจึงไม่สามารถให้ลำดับที่แน่นอนแก่คุณได้ ดังนั้นให้พิจารณารายการคำสั่งที่ไม่เรียงลำดับที่คุณจะต้องใช้:

  • TPM_OSAP
  • TPM_CreateWrapKey
  • TPM_LoadKey2
  • TPM_Seal

หากคุณต้องการอ่านค่า PCR ปัจจุบันด้วย:

  • TPM_PCRRead

ไมโครซอฟท์ของพวกเขา.NET c # ห้องสมุดการจัดการสำหรับการใช้ของ TPM นอกจากนี้ยังมีโปรแกรมจำลอง TPMซึ่งไลบรารีที่มีการจัดการสามารถเชื่อมต่อเป็นทางเลือกในการดีบักได้หากไม่มี TPM จริง นอกจากนี้ยังมีTPM Platform Provider Toolkitซึ่งมีเอกสารประกอบและโค้ดตัวอย่างสำหรับการใช้ TPM ตอนนี้มีเพียงใครบางคนเท่านั้นที่สามารถหาวิธีใช้ TPM เพื่อเข้ารหัสไบต์ได้
Ian Boyd

สองลิงค์แรกของคุณคือ TPM 2.0 เท่านั้น หากคุณต้องการใช้สิ่งเหล่านี้ฉันเกรงว่าจะไม่มีความช่วยเหลือ
Scolytus

4

คีย์ที่เชื่อถือได้และเข้ารหัส

Trusted and Encrypted Keys เป็นคีย์ใหม่สองประเภทที่เพิ่มเข้าไปในบริการคีย์ริงของเคอร์เนลที่มีอยู่ ทั้งสองประเภทใหม่นี้เป็นคีย์สมมาตรที่มีความยาวผันแปรได้และในทั้งสองกรณีคีย์ทั้งหมดจะถูกสร้างขึ้นในเคอร์เนลและพื้นที่ผู้ใช้จะเห็นจัดเก็บและโหลดเฉพาะ blobs ที่เข้ารหัสเท่านั้น Trusted Keys ต้องการความพร้อมใช้งานของชิป Trusted Platform Module (TPM) เพื่อความปลอดภัยที่มากขึ้นในขณะที่ Encrypted Keys สามารถใช้กับระบบใดก็ได้ blobs ระดับผู้ใช้ทั้งหมดจะแสดงและโหลดใน hex ascii เพื่อความสะดวกและได้รับการตรวจสอบความสมบูรณ์

คีย์ที่เชื่อถือได้ใช้ TPM เพื่อสร้างและปิดผนึกคีย์ คีย์ถูกปิดผนึกภายใต้คีย์ RSA 2048 บิตใน TPM และปิดผนึกเป็นทางเลือกตามค่า PCR (การวัดความสมบูรณ์) ที่ระบุและปิดผนึกโดย TPM เท่านั้นหาก PCR และการตรวจสอบความสมบูรณ์ของหยดตรงกัน คีย์ที่เชื่อถือได้ที่โหลดสามารถอัปเดตด้วยค่า PCR ใหม่ (ในอนาคต) ดังนั้นคีย์จึงถูกย้ายไปยังค่า pcr ใหม่ได้อย่างง่ายดายเช่นเมื่อมีการอัปเดตเคอร์เนลและ initramfs คีย์เดียวกันสามารถมี blobs ที่บันทึกไว้มากมายภายใต้ค่า PCR ที่แตกต่างกันดังนั้นจึงรองรับการบู๊ตหลายครั้ง

โดยค่าเริ่มต้นคีย์ที่เชื่อถือได้จะถูกปิดผนึกภายใต้ SRK ซึ่งมีค่าการอนุญาตเริ่มต้น (20 ศูนย์) นี้สามารถตั้งค่าในเวลา takeownership tpm_takeownership -u -zกับยูทิลิตี้กางเกงที่:

Usage:
    keyctl add trusted name "new keylen [options]" ring
    keyctl add trusted name "load hex_blob [pcrlock=pcrnum]" ring
    keyctl update key "update [options]"
    keyctl print keyid

    options:
    keyhandle= ascii hex value of sealing key default 0x40000000 (SRK)
    keyauth=   ascii hex auth for sealing key default 0x00...i
        (40 ascii zeros)
    blobauth=  ascii hex auth for sealed data default 0x00...
        (40 ascii zeros)
    blobauth=  ascii hex auth for sealed data default 0x00...
        (40 ascii zeros)
    pcrinfo=   ascii hex of PCR_INFO or PCR_INFO_LONG (no default)
    pcrlock=   pcr number to be extended to "lock" blob
    migratable= 0|1 indicating permission to reseal to new PCR values,
                default 1 (resealing allowed)

keyctl printส่งคืนสำเนา ascii hex ของคีย์ที่ปิดผนึกซึ่งอยู่ในรูปแบบ TPM_STORED_DATA มาตรฐาน ความยาวคีย์สำหรับคีย์ใหม่มีหน่วยเป็นไบต์เสมอ Trusted Keys สามารถมีขนาด 32 - 128 ไบต์ (256 - 1024 บิต) ขีด จำกัด บนคือให้พอดีกับความยาวคลื่น SRK (RSA) 2048 บิตพร้อมโครงสร้าง / ช่องว่างที่จำเป็นทั้งหมด

คีย์ที่เข้ารหัสไม่ได้ขึ้นอยู่กับ TPM และเร็วกว่าเนื่องจากใช้ AES ในการเข้ารหัส / ถอดรหัส คีย์ใหม่ถูกสร้างขึ้นจากตัวเลขสุ่มที่สร้างขึ้นของเคอร์เนลและเข้ารหัส / ถอดรหัสโดยใช้คีย์ 'หลัก' ที่ระบุ คีย์ 'master' อาจเป็นประเภทคีย์ที่เชื่อถือได้หรือคีย์ผู้ใช้ ข้อเสียเปรียบหลักของคีย์ที่เข้ารหัสคือหากไม่ได้รูทในคีย์ที่เชื่อถือได้คีย์จะปลอดภัยเท่ากับคีย์ผู้ใช้ที่เข้ารหัสเท่านั้น ดังนั้นควรโหลดคีย์ผู้ใช้หลักให้ปลอดภัยที่สุดโดยเฉพาะอย่างยิ่งในช่วงเริ่มต้นของการบูต

ส่วนที่ถอดรหัสของคีย์ที่เข้ารหัสอาจมีทั้งคีย์สมมาตรธรรมดาหรือโครงสร้างที่ซับซ้อนกว่า รูปแบบของโครงสร้างที่ซับซ้อนมากขึ้นเป็นเฉพาะแอปพลิเคชันซึ่งระบุโดย "รูปแบบ"

Usage:
    keyctl add encrypted name "new [format] key-type:master-key-name keylen"
        ring
    keyctl add encrypted name "load hex_blob" ring
    keyctl update keyid "update key-type:master-key-name"

format:= 'default | ecryptfs'
key-type:= 'trusted' | 'user'

ตัวอย่างการใช้งานคีย์ที่เชื่อถือได้และเข้ารหัส

สร้างและบันทึกคีย์ที่เชื่อถือได้ชื่อ "kmk" ความยาว 32 ไบต์:

$ keyctl add trusted kmk "new 32" @u
440502848

$ keyctl show
Session Keyring
       -3 --alswrv    500   500  keyring: _ses
 97833714 --alswrv    500    -1   \_ keyring: _uid.500
440502848 --alswrv    500   500       \_ trusted: kmk

$ keyctl print 440502848
0101000000000000000001005d01b7e3f4a6be5709930f3b70a743cbb42e0cc95e18e915
3f60da455bbf1144ad12e4f92b452f966929f6105fd29ca28e4d4d5a031d068478bacb0b
27351119f822911b0a11ba3d3498ba6a32e50dac7f32894dd890eb9ad578e4e292c83722
a52e56a097e6a68b3f56f7a52ece0cdccba1eb62cad7d817f6dc58898b3ac15f36026fec
d568bd4a706cb60bb37be6d8f1240661199d640b66fb0fe3b079f97f450b9ef9c22c6d5d
dd379f0facd1cd020281dfa3c70ba21a3fa6fc2471dc6d13ecf8298b946f65345faa5ef0
f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b
e4a8aea2b607ec96931e6f4d4fe563ba

$ keyctl pipe 440502848 > kmk.blob

โหลดคีย์ที่เชื่อถือได้จากหยดที่บันทึกไว้:

$ keyctl add trusted kmk "load `cat kmk.blob`" @u
268728824

$ keyctl print 268728824
0101000000000000000001005d01b7e3f4a6be5709930f3b70a743cbb42e0cc95e18e915
3f60da455bbf1144ad12e4f92b452f966929f6105fd29ca28e4d4d5a031d068478bacb0b
27351119f822911b0a11ba3d3498ba6a32e50dac7f32894dd890eb9ad578e4e292c83722
a52e56a097e6a68b3f56f7a52ece0cdccba1eb62cad7d817f6dc58898b3ac15f36026fec
d568bd4a706cb60bb37be6d8f1240661199d640b66fb0fe3b079f97f450b9ef9c22c6d5d
dd379f0facd1cd020281dfa3c70ba21a3fa6fc2471dc6d13ecf8298b946f65345faa5ef0
f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b
e4a8aea2b607ec96931e6f4d4fe563ba

ผนึกคีย์ที่เชื่อถือได้อีกครั้งภายใต้ค่า pcr ใหม่:

$ keyctl update 268728824 "update pcrinfo=`cat pcr.blob`"
$ keyctl print 268728824
010100000000002c0002800093c35a09b70fff26e7a98ae786c641e678ec6ffb6b46d805
77c8a6377aed9d3219c6dfec4b23ffe3000001005d37d472ac8a44023fbb3d18583a4f73
d3a076c0858f6f1dcaa39ea0f119911ff03f5406df4f7f27f41da8d7194f45c9f4e00f2e
df449f266253aa3f52e55c53de147773e00f0f9aca86c64d94c95382265968c354c5eab4
9638c5ae99c89de1e0997242edfb0b501744e11ff9762dfd951cffd93227cc513384e7e6
e782c29435c7ec2edafaa2f4c1fe6e7a781b59549ff5296371b42133777dcc5b8b971610
94bc67ede19e43ddb9dc2baacad374a36feaf0314d700af0a65c164b7082401740e489c9
7ef6a24defe4846104209bf0c3eced7fa1a672ed5b125fc9d8cd88b476a658a4434644ef
df8ae9a178e9f83ba9f08d10fa47e4226b98b0702f06b3b8

ผู้ใช้เริ่มต้นของคีย์ที่เชื่อถือได้คือ EVM ซึ่งในเวลาบูตต้องการคีย์สมมาตรคุณภาพสูงสำหรับการป้องกัน HMAC ของข้อมูลเมตาของไฟล์ การใช้คีย์ที่เชื่อถือได้ให้การรับประกันที่แข็งแกร่งว่าคีย์ EVM ไม่ได้ถูกบุกรุกจากปัญหาระดับผู้ใช้และเมื่อปิดผนึกกับค่า PCR สำหรับบูตเฉพาะจะป้องกันการบูตและการโจมตีออฟไลน์ สร้างและบันทึกคีย์ที่เข้ารหัส "evm" โดยใช้คีย์ที่เชื่อถือได้ด้านบน "kmk":

ตัวเลือกที่ 1: ละเว้น 'รูปแบบ'

$ keyctl add encrypted evm "new trusted:kmk 32" @u
159771175

ตัวเลือกที่ 2: กำหนด 'รูปแบบ' เป็น 'ค่าเริ่มต้น' อย่างชัดเจน

$ keyctl add encrypted evm "new default trusted:kmk 32" @u
159771175

$ keyctl print 159771175
default trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b3
82dbbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0
24717c64 5972dcb82ab2dde83376d82b2e3c09ffc

$ keyctl pipe 159771175 > evm.blob

โหลดคีย์ที่เข้ารหัส "evm" จากหยดที่บันทึกไว้:

$ keyctl add encrypted evm "load `cat evm.blob`" @u
831684262

$ keyctl print 831684262
default trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b3
82dbbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0
24717c64 5972dcb82ab2dde83376d82b2e3c09ffc

คาดว่าจะมีการใช้งานอื่น ๆ สำหรับคีย์ที่เชื่อถือได้และเข้ารหัสเช่นการเข้ารหัสดิสก์และไฟล์ โดยเฉพาะอย่างยิ่งรูปแบบใหม่ 'ecryptfs' ได้รับการกำหนดเพื่อใช้คีย์ที่เข้ารหัสเพื่อติดตั้งระบบไฟล์ eCryptfs รายละเอียดเพิ่มเติมเกี่ยวกับการใช้งานสามารถพบได้ในไฟล์ 'Documentation / security / keys-ecryptfs.txt'


คุณมีความคิดหรือไม่เมื่อมีการเพิ่มคีย์ใหม่ทั้งสองประเภทนี้? ฉันหมายถึงเวอร์ชันไหน ตอนนี้ฉันใช้ 1.2 (แพ็คเกจของ บริษัท ) และอันนั้นไม่รองรับสิ่งเหล่านี้ อาจจะใน 1.5+?
Acapulco

1
ที่มาของการโพสต์นี้คืออะไร? ส่วนท้ายหมายถึงเอกสารDocumentation/security/keys-ecryptfs.tx
goodguys_activate

สิ่งเหล่านี้ดูเหมือนจะเป็นการเรียกโปรแกรมบรรทัดคำสั่ง ฉันไม่เห็นรหัสเกี่ยวกับวิธีใช้ TPM
Ian Boyd

3

ฉันจะเข้ารหัสไบต์โดยใช้โมดูล TPM ของเครื่องได้อย่างไร

ขึ้นอยู่กับเจตนาและสถานการณ์ของคุณ:

  • คุณมี TPM ประเภทใด (1-family หรือ 2-family)?
  • TPM อยู่ในสถานะใด ได้เป็นเจ้าของ? ได้จัดเตรียมไว้หรือไม่
  • ภาษาโปรแกรมของคุณคืออะไร?
  • คุณต้องการเข้ารหัสหรือลงนาม? (ซึ่งคลุมเครือจากคำถามที่เหลือ)
  • ข้อมูลที่คุณต้องการเข้ารหัสมีขนาดใหญ่เพียงใด
  • คุณต้องการใช้คีย์สมมาตรหรือคีย์อสมมาตร?
  • คุณต้องการใช้คีย์ที่มีอยู่แล้วใน TPM หรือคุณต้องการให้สร้างคีย์ขึ้นมาก่อน
  • โดย "เข้ารหัส" คุณอาจหมายถึง "ห่อกุญแจ" หรือไม่?
  • คุณต้องการล็อคข้อมูลที่เข้ารหัสไว้กับการกำหนดค่าระบบเพื่อให้สามารถถอดรหัสได้ก็ต่อเมื่อระบบกลับมาอยู่ในการกำหนดค่าเดิมหรือไม่?
  • คุณต้องการขอการอนุญาตในการถอดรหัสหรือไม่?
  • บางทีคุณไม่จำเป็นต้องเข้ารหัสเลย แต่ควรจัดเก็บข้อมูลไว้ใน TPM?
  • หากคุณกำลังจัดเก็บข้อมูลภายใน TPM คุณต้องการให้มีการอนุญาตหรือเพื่อให้ระบบอยู่ในการกำหนดค่าเฉพาะเพื่อการดึงข้อมูล?

แต่ละกรณีการใช้งานเหล่านี้ (และยังมีอีกมาก) - หรือการใช้งานร่วมกัน - นำเสนอเส้นทางการใช้งานที่แตกต่างกัน คิดว่า TPM เป็นอุปกรณ์เข้ารหัสลับของกองทัพสวิส: มีไม่มากที่คุณไม่สามารถทำได้ แต่ความสะดวกในการใช้งานนั้นทนทุกข์ทรมานสำหรับความเก่งกาจนั้น คำถามยังคงตีกลับระหว่างการเข้ารหัสการเซ็นชื่อและการล็อกการกำหนดค่าระบบ แต่ส่วนหลักของคำตอบนี้จะพิจารณาคำสั่ง Seal เพื่อให้ครอบคลุมความต้องการส่วนใหญ่ที่อธิบายไว้ในคำถาม

ตอนนี้ถึงเวลาที่จะก้าวไปอีกขั้น ฉันต้องการเข้ารหัสข้อมูลบางอย่าง (เช่นคีย์หลักสำหรับการเข้ารหัสฮาร์ดไดรฟ์) ที่สามารถถอดรหัสได้โดย TPM ในเครื่องเท่านั้น

นี่คือสิ่งที่คำสั่ง Bind มีไว้สำหรับ (แทนที่ด้วยคำสั่ง Create สำหรับ TPM 2) คุณโหลดคีย์ที่มาจากคีย์ที่ผูกกับ TPM และเข้ารหัสด้วยคีย์นั้น (หรือโดยตรงด้วยคีย์ที่เชื่อมโยงกับฮาร์ดแวร์) วิธีนี้สามารถถอดรหัสข้อมูลด้วยการเข้าถึง TPM เดียวกันเท่านั้น

กล่าวอีกนัยหนึ่งฉันต้องการแทนที่ Qualcomm Trusted Execution Environment (TEE) ในแผนภาพบล็อกด้านล่างสำหรับ Android ด้วย TPM ใน Windows:

ไม่แน่ใจว่าการจำลองกระบวนการทั้งหมดนี้เป็นความคิดที่ดีหรือไม่ ประการแรกไม่จำเป็นต้องใช้การลงนามที่ใดก็ได้ในกระบวนการนี้ ดูเหมือนว่าในขณะที่ Android 5 กำลังได้รับการพัฒนาKeystore API ถูก จำกัด ไว้ที่การลงชื่อและการยืนยัน การคาดเดาที่ดีที่สุดของฉันคือทีมเข้ารหัสดิสก์พยายามอย่างเต็มที่ในการทำงานกับสิ่งที่พวกเขามีและคิดค้นอัลกอริทึมโดยหนึ่งในคีย์กลางนั้นได้มาจากการดำเนินการเซ็นชื่อโดยใช้คีย์ TEE ที่เก็บไว้ดังนั้นจึงผูกกระบวนการทั้งหมดเข้ากับฮาร์ดแวร์ - คีย์ที่ผูกไว้พร้อมใช้งานบนแพลตฟอร์มเท่านั้นเนื่องจากการเซ็นชื่อเป็นวิธีเดียวที่จะทำได้ในเวลานั้น อย่างไรก็ตามไม่จำเป็นต้อง จำกัด ตัวเองด้วยวิธีดังกล่าวหากมีการเข้าถึง TPM ซึ่งให้ความสามารถมากกว่าที่คุณต้องการ!

ฉันตระหนักดีว่า TPM ไม่ได้ทำการลงนามข้อมูล

นี่เป็นเท็จ TPM ทั้งสองเวอร์ชันรองรับการลงนาม

(หรือถ้าเป็นเช่นนั้นก็ไม่รับประกันว่าการลงนามในข้อมูลเดียวกันจะให้ผลลัพธ์ไบนารีเดียวกันทุกครั้ง)

สิ่งนี้ไม่สมเหตุสมผล การลงนามข้อมูลเดียวกันด้วยคีย์เดียวกันจะทำให้เกิดลายเซ็นเดียวกัน คุณอาจสับสนระหว่างการดำเนินการเซ็นชื่อกับการดำเนินการ quoting ซึ่งจะผสมกันใน nonce

นั่นคือเหตุผลที่ฉันยินดีที่จะแทนที่ "RSA Signing" ด้วย "การเข้ารหัสหยด 256 บิตด้วยคีย์ที่ผูกกับฮาร์ดแวร์"

นี่ควรเป็นตัวเลือกที่ต้องการแม้ว่าทั้งสองอย่างจะเป็นไปได้ด้วย TPM ดูด้านบน.

ปัญหาคือการเขียนโปรแกรม TPM นั้นไม่มีเอกสารโดยสมบูรณ์บน MSDN ไม่มี API สำหรับดำเนินการใด ๆ

น่าเสียดายที่มีเอกสารไม่มาก Win API ถูก จำกัด ไว้ที่ฟังก์ชัน TBS สองสามฟังก์ชันซึ่งถูกลบออกจากไดรเวอร์หนึ่งระดับ

แต่คุณต้องหาสำเนาของ Software Stack ของ Trusted Computing Group (aka TSS) ให้หาคำสั่งที่จะส่งไปยัง TPM พร้อมเพย์โหลดตามลำดับและเรียกใช้ฟังก์ชัน Tbsip_Submit_Command ของ Window เพื่อส่งคำสั่งโดยตรง:

ที่จริงแล้วไม่ถ้าคุณมี TSS Tbsip_submit_Command()ที่คุณจะได้ไม่ต้องใช้ นั่นคือจุดรวมของการมี TSS - รายละเอียดระดับต่ำจะถูกแยกออกไป

Windows ไม่มี API ระดับที่สูงกว่าเพื่อดำเนินการ

ยังคงเป็นจริงสำหรับ TPM 1 แต่สำหรับ TPM 2 มีTSS.MSR

มันเทียบเท่าศีลธรรมในการพยายามสร้างไฟล์ข้อความโดยการออกคำสั่ง SATA I / O ไปยังฮาร์ดไดรฟ์ของคุณ

แก้ไข.

ทำไมไม่ใช้แค่กางเกง ... ปัญหาของรหัสนั้นคือไม่สามารถพกพาเข้าสู่โลก Windows ได้ ตัวอย่างเช่นคุณไม่สามารถใช้งานจาก Delphi คุณไม่สามารถใช้จาก C # ได้ มันต้องการ: OpenSSL, pThread

ไม่ชัดเจนว่านี่เป็นความท้าทายที่ผ่านไม่ได้ การเข้าถึง TrouSerS ผ่านการทำงานร่วมกันควรเป็นการเขียนโค้ดโครงสร้างข้อมูลใหม่ทั้งหมด นอกจากนี้doTSSในขณะที่เขียนคำถาม

รหัสเทียบเท่าในการเข้ารหัสข้อมูลโดยใช้ TPM คืออะไร? อาจเกี่ยวข้องกับคำสั่ง TPM_seal แม้ว่าฉันคิดว่าฉันไม่ต้องการปิดผนึกข้อมูล แต่ฉันคิดว่าฉันต้องการผูกมัน:

คำถามมีคำพูดที่อธิบายความแตกต่างระหว่างสองคำสั่งดังนั้นจึงไม่ควรสับสนมากนัก การปิดผนึกจะคล้ายกับการผูกโดยมีข้อ จำกัด เพิ่มเติมว่าสถานะของระบบจะต้องเหมือนกันเพื่อให้ข้อมูลถูกเปิดผนึก

ในทำนองเดียวกันฉันสามารถให้:

Byte[] ProtectBytes_Crypt(Byte[] plaintext)
{
   //...
   CryptProtectData(...); 
   //...
}

ใครสามารถจัดหาสิ่งที่เทียบเท่ากันได้:

Byte[] ProtectBytes_TPM(Byte[] plaintext)
{
   //...
   Tbsip_Submit_Command(...);
   Tbsip_Submit_Command(...);
   Tbsip_Submit_Command(...);
   //...snip...
   Tbsip_Submit_Command(...);
   //...
}

ที่ทำในสิ่งเดียวกันยกเว้นแทนที่จะเป็นกุญแจที่ถูกล็อคใน System LSA ถูกล็อคใน TPM หรือไม่?

ก่อนอื่นควรชี้ให้เห็นว่า TPM มีสองเวอร์ชันหลักซึ่งไม่สามารถใช้ร่วมกันได้โดยสิ้นเชิง ดังนั้นแทบไม่มีโค้ดที่คุณเขียนไว้สำหรับ TPM 1 จะใช้กับ TPM 2 ได้ TBS API เป็นรหัสทั่วไปเพียงรหัสเดียวระหว่างสองรหัสนี้และเพื่อความเป็นธรรมกับ Microsoft นี่อาจเป็นสาเหตุหนึ่งที่ทำให้ API นั้นไม่เติบโต ส่วนหลักของคำตอบจะแสดงรหัสสำหรับ TPM 1 ด้วยเหตุผลสองประการ:

  • คำถามนี้เต็มไปด้วยแนวคิดเฉพาะของ TPM 1 ดังนั้นผู้ที่ใช้ TPM 1 จึงมีแนวโน้มที่จะมาที่นี่เพื่อค้นหาพวกเขา
  • มีการใช้ TSS ของ Microsoft สำหรับ TPM 2

ประการที่สองให้คำถามเฉพาะเจาะจงมากขึ้น ฉันตีความใหม่ดังนี้:

How do I write code in C#, using only the TBS API, to interface with
an already owned and provisioned TPM to, without user interaction,
encrypt no more than 128 bytes of arbitrary data with an asymmetric
key already resident in the TPM and bound to it, but not protected
with a password, so that in order to decrypt the data the system may
need to be in the same state it was in at encryption time based on an
easily configurable variable?

คำสั่ง Seal เหมาะที่สุดสำหรับสิ่งนี้เนื่องจากทำหน้าที่เดียวกับคำสั่ง Bind เมื่อกำหนดขนาดการเลือก PCR เป็นศูนย์ แต่การเลือก PCR สามารถเปลี่ยนได้อย่างง่ายดายเพื่อรวม PCR ที่คุณต้องการ ทำให้สงสัยว่าทำไมคำสั่ง Bind จึงรวมอยู่ในข้อมูลจำเพาะทั้งหมดและตามที่ระบุไว้มันถูกลบออกในข้อมูลจำเพาะ TPM 2 และทั้งสองรวมอยู่ในคำสั่ง Create เดียว

นี่คือรหัส C # สำหรับใช้คำสั่ง TPM 1.2 Seal เพื่อเข้ารหัสข้อมูลด้วยฟังก์ชัน TBS เท่านั้น(หมายเหตุ: รหัสนี้ยังไม่ผ่านการทดสอบและไม่น่าจะทำงานได้หากไม่มีการดีบัก) :

[DllImport ("tbs.dll")]
unsafe static extern UInt32 Tbsi_Context_Create (UInt32 * version, IntPtr * hContext);

[DllImport ("tbs.dll")]
unsafe static extern UInt32 Tbsip_Context_Close (IntPtr hContext);

[DllImport ("tbs.dll")]
unsafe static extern UInt32 Tbsip_Submit_Command (
    IntPtr hContext, UInt32 Locality, 
    UInt32 Priority, 
    byte * pCommandBuf, 
    UInt32 CommandBufLen, 
    byte * pResultBuf, 
    UInt32 * pResultBufLen);

byte[] ProtectBytes_TPM (byte[] plaintext) {

    void AddUInt32Reversed (byte[] a, System.UInt32 o, ref int i) {
        byte[] bytes = System.BitConverter.GetBytes (o);
        Array.Reverse (bytes);
        Array.Copy (bytes, 0, a, i, bytes.Length);
        i += bytes.Length;
    }
    void AddUInt16Reversed (byte[] a, System.UInt16 o, ref int i) {
        byte[] bytes = System.BitConverter.GetBytes (o);
        Array.Reverse (bytes);
        Array.Copy (bytes, 0, a, i, bytes.Length);
        i += bytes.Length;
    }
    void AddBool (byte[] a, byte b, ref int i) {
        a[i] = b;
        i += 1;
    }
    void AddBlob (byte[] a, byte[] b, ref int i) {
        Array.Copy (b, 0, a, i, b.Length);
        i += b.Length;
    }
    byte[] Xor (byte[] text, byte[] key) {
        byte[] xor = new byte[text.Length];
        for (int i = 0; i < text.Length; i++) {
            xor[i] = (byte) (text[i] ^ key[i % key.Length]);
        }
        return xor;
    }

    int offset;

    Random rnd = new Random ();

    IntPtr hContext = IntPtr.Zero;
    unsafe {
        UInt32 version = 1;
        IntPtr handle = hContext;
        UInt32 result = Tbsi_Context_Create ( & version, & handle);

        if (result == 0) {
            hContext = handle;
        }
    }

    byte[] cmdBuf = new byte[768];

    //OSAP
    System.UInt32 outSize;

    byte[] oddOsap = new byte[20];
    byte[] evenOsap = new byte[20];
    byte[] nonceEven = new byte[20];
    byte[] nonceOdd = new byte[20];
    System.UInt32 hAuth = 0;

    offset = 0;
    AddUInt16Reversed (cmdBuf, 0x00C1, ref offset);
    offset = 6;
    AddUInt32Reversed (cmdBuf, 0x0000000B, ref offset);

    offset = 2 + 4 + 4; //2 for tag, 4 for size and 4 for command code

    AddUInt16Reversed (cmdBuf, 0x0004, ref offset); //Entity Type SRK = 0x0004
    AddUInt32Reversed (cmdBuf, 0x40000000, ref offset); //Entity Value SRK = 0x40000000
    rnd.NextBytes (oddOsap);
    AddBlob (cmdBuf, oddOsap, ref offset);
    uint cmdSize = (System.UInt32) offset;
    offset = 2;
    AddUInt32Reversed (cmdBuf, cmdSize, ref offset);

    outSize = (System.UInt32) (Marshal.SizeOf (hAuth) + nonceEven.Length + evenOsap.Length);

    byte[] response = new byte[outSize];
    unsafe {
        UInt32 result = 0;

        //uint cmdSize = (uint)offset;
        uint resSize = outSize;
        fixed (byte * pCmd = cmdBuf, pRes = response) {
            result = Tbsip_Submit_Command (hContext, 0, 200, pCmd, cmdSize, pRes, & resSize);
        }
    }

    byte contSession = 0;
    System.UInt32 hKey = 0x40000000; //TPM_KH_SRK;
    System.UInt32 pcrInfoSize = 0;
    byte[] srkAuthdata = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    uint inDataSize = (uint) plaintext.Length;

    offset = 2 + 4 + 4; //2 for tag, 4 for size and 4 for return code
    byte[] hauthbytes = new byte[Marshal.SizeOf (hAuth)];
    Array.Copy (response, offset, hauthbytes, 0, hauthbytes.Length);
    Array.Reverse (hauthbytes);
    hAuth = System.BitConverter.ToUInt32 (hauthbytes, 0);
    offset += Marshal.SizeOf (hAuth);
    Array.Copy (response, offset, nonceEven, 0, nonceEven.Length);
    offset += nonceEven.Length;
    Array.Copy (response, offset, evenOsap, 0, evenOsap.Length);

    //shared-secret = HMAC(srk_auth, even_osap || odd_osap)
    byte[] sharedSecretBuf = new byte[evenOsap.Length + oddOsap.Length];
    Array.Copy (evenOsap, 0, sharedSecretBuf, 0, evenOsap.Length);
    Array.Copy (oddOsap, 0, sharedSecretBuf, evenOsap.Length, oddOsap.Length);
    System.Security.Cryptography.HMACSHA1 sharedSecretHmac = new System.Security.Cryptography.HMACSHA1 (srkAuthdata);
    byte[] sharedSecret = sharedSecretHmac.ComputeHash (sharedSecretBuf);

    byte[] authSha1InBuf = new byte[sharedSecret.Length + nonceEven.Length];
    Array.Copy (sharedSecret, 0, authSha1InBuf, 0, sharedSecret.Length);
    Array.Copy (nonceEven, 0, authSha1InBuf, sharedSecret.Length, nonceEven.Length);
    System.Security.Cryptography.SHA1Managed sha1 = new System.Security.Cryptography.SHA1Managed ();
    byte[] authSha1 = sha1.ComputeHash (authSha1InBuf);
    byte[] encAuth = Xor (srkAuthdata, authSha1);

    //inParamDigest = sha1(1S ~ 6S) 
    int paramInDigestInBufSize =
        sizeof (System.UInt32) + 
        encAuth.Length +
        Marshal.SizeOf (pcrInfoSize) +
        Marshal.SizeOf (inDataSize) +
        (int) inDataSize;
    byte[] paramInDigestInBuf = new byte[paramInDigestInBufSize];
    offset = 0;
    AddUInt32Reversed (paramInDigestInBuf, 0x00000017, ref offset);
    AddBlob (paramInDigestInBuf, encAuth, ref offset);
    AddUInt32Reversed (paramInDigestInBuf, 0x0, ref offset); //PCR info size
    AddUInt32Reversed (paramInDigestInBuf, inDataSize, ref offset);
    AddBlob (paramInDigestInBuf, plaintext, ref offset);

    byte[] paramInDigest = sha1.ComputeHash (paramInDigestInBuf);

    int pubAuthInBufSize = paramInDigest.Length + nonceEven.Length + nonceOdd.Length + Marshal.SizeOf (contSession);
    byte[] pubAuthInBuf = new byte[pubAuthInBufSize];

    offset = 0;
    AddBlob (pubAuthInBuf, paramInDigest, ref offset);
    AddBlob (pubAuthInBuf, nonceEven, ref offset);
    AddBlob (pubAuthInBuf, nonceOdd, ref offset);
    AddBool (pubAuthInBuf, contSession, ref offset);
    System.Security.Cryptography.HMACSHA1 pubAuthHmac = new System.Security.Cryptography.HMACSHA1 (sharedSecret);
    byte[] pubAuth = pubAuthHmac.ComputeHash (pubAuthInBuf);

    //Seal
    offset = 0;
    AddUInt16Reversed (cmdBuf, 0x00C2, ref offset); // TPM_TAG_RQU_AUTH1_COMMAND;
    offset = 6;
    AddUInt32Reversed (cmdBuf, 0x00000017, ref offset); // TPM_ORD_SEAL;
    offset = 2 + 4 + 4; //2 for tag, 4 for size and 4 for command code

    AddUInt32Reversed (cmdBuf, hKey, ref offset);
    AddBlob (cmdBuf, encAuth, ref offset);
    AddUInt32Reversed (cmdBuf, pcrInfoSize, ref offset);
    AddUInt32Reversed (cmdBuf, inDataSize, ref offset);
    AddBlob (cmdBuf, plaintext, ref offset);

    AddUInt32Reversed (cmdBuf, hAuth, ref offset);
    AddBlob (cmdBuf, nonceOdd, ref offset);
    AddBool (cmdBuf, contSession, ref offset);
    AddBlob (cmdBuf, pubAuth, ref offset);
    cmdSize = (System.UInt32) offset;
    offset = 2;
    AddUInt32Reversed (cmdBuf, cmdSize, ref offset);

    outSize = 768;
    uint responseSize = 0;

    response = new byte[outSize];
    unsafe {
        UInt32 result = 0;

        uint resSize = outSize;
        fixed (byte * pCmd = cmdBuf, pRes = response) {
            result = Tbsip_Submit_Command (hContext, 0, 200, pCmd, cmdSize, pRes, & resSize);
        }
        responseSize = resSize;
    }

    byte[] retBuffer = new byte[responseSize - 10];
    Array.Copy (response, 10, retBuffer, 0, retBuffer.Length);
    Tbsip_Context_Close (hContext);
    return retBuffer;

}

การวิเคราะห์รหัส:

[DllImport ("tbs.dll")]
...

นี่คือฟังก์ชันบางส่วนที่มีอยู่ใน Tbs.h และฟังก์ชันเดียวที่เราจะใช้ที่นี่ โดยทั่วไปจะช่วยให้คุณสามารถเปิดที่จับไปยังอุปกรณ์และสื่อสารกับอุปกรณ์ได้โดยการส่งและรับไบต์ดิบ

    void AddUInt32Reversed (byte[] a, System.UInt32 o, ref int i) { ... }
    void AddUInt16Reversed (byte[] a, System.UInt16 o, ref int i) { ... }
    void AddBool (byte[] a, byte b, ref int i) { ... }
    void AddBlob (byte[] a, byte[] b, ref int i) { ... }

TPM เป็น endian ขนาดใหญ่ Windows มีน้อย ดังนั้นคำสั่งไบต์จะต้องถูกย้อนกลับสำหรับข้อมูลที่เราส่งไป เราต้องกังวลเกี่ยวกับการย้อนกลับ ints ที่ไม่ได้ลงนาม 32 บิตและ 16 บิตที่นี่เท่านั้น

    ...
    UInt32 result = Tbsi_Context_Create ( & version, & handle);
    ...

ที่นี่เราใช้Tbsi_Context_Create ()เพื่อเปิดที่จับเพื่อคุยกับ TPM TBS_CONTEXT_PARAMSพารามิเตอร์เป็นเพียง struct C ที่มีไม่ได้ลงนามฟิลด์ int หนึ่ง 32 บิตที่จะต้องตั้งค่าเป็น 1 เพื่อพูดคุยกับ TPM 1.2 เช่นและว่าสิ่งที่เรากำหนดให้

    byte[] cmdBuf = new byte[768];

นี้จะถูกระบุว่าเป็นขนาดของบัฟเฟอร์ขั้นต่ำในTPM Spec มันจะเกินพอสำหรับความต้องการของเราที่นี่

TPM 1.2 Spec ส่วนที่ 3กล่าวต่อไปนี้:

TPM_Seal requires the encryption of one parameter (“Secret”). For the
sake of uniformity with other commands that require the encryption of
more than one parameter, the string used for XOR encryption is
generated by concatenating a nonce (created during the OSAP session)
with the session shared secret and then hashing the result.

เราจำเป็นต้อง XOR เข้ารหัสพารามิเตอร์ "ลับ" นี้โดยใช้ nonce ที่สร้างขึ้นระหว่างเซสชัน OSAP หนึ่งในที่จับอินพุตคำสั่ง Seal ยังเป็นที่จับ OSAP:

The authorization session handle used for keyHandle authorization.
Must be an OSAP session for this command.

ดังนั้นเราต้องสร้างเซสชัน OSAP นี้ก่อน OSAP อธิบายไว้ในTPM 1.2 Spec Part 1ส่วนที่ 1 OSAP หรือ Object-Specific Authorization Protocol ถูกคิดค้นขึ้นเพื่อจัดการกรณีการใช้งานที่คุณต้องการใช้ออบเจ็กต์ TPM ที่ต้องมีการอนุญาตหลายครั้ง แต่ไม่ต้องการให้การอนุญาตในแต่ละครั้ง: จะใช้เซสชัน OSAP แทนซึ่งต้องอาศัย เกี่ยวกับแนวคิดของ "ความลับร่วมกัน" ซึ่งเป็นHMACซึ่งผสมในข้อมูลการอนุญาตอ็อบเจ็กต์กับ nonces ที่สร้างขึ้นในแต่ละด้านเพื่อป้องกันการโจมตีตอบกลับ ดังนั้น "ความลับที่ใช้ร่วมกัน" จึงเป็นที่รู้จักของทั้งสองฝ่ายในเซสชันนี้: ฝั่งที่เริ่มเซสชัน (ผู้ใช้) และฝั่งที่ยอมรับ (TPM); นอกจากนี้ทั้งสองฝ่ายจะต้องมีข้อมูลการอนุญาตออบเจ็กต์เดียวกันสำหรับ "ความลับที่ใช้ร่วมกัน" จะเหมือนกัน นอกจากนี้ "ความลับที่แชร์" ที่ใช้ในเซสชันหนึ่งจะไม่ถูกต้องในอีกเซสชันหนึ่ง แผนภาพนี้จากข้อมูลจำเพาะอธิบายกระบวนการ:

OSAP

เราจะไม่ใช้หลายเซสชันในกรณีนี้ (อันที่จริงพารามิเตอร์นั้นถูกละเว้นด้วยคำสั่ง Seal!) และคีย์ที่เราจะใช้ไม่จำเป็นต้องได้รับอนุญาต แต่น่าเสียดายที่เรายังคงผูกพันกับข้อกำหนดในการสร้าง OSAP เซสชัน

    offset = 0;
    AddUInt16Reversed (cmdBuf, 0x00C1, ref offset);
    offset = 6;
    AddUInt32Reversed (cmdBuf, 0x0000000B, ref offset);

    offset = 2 + 4 + 4; //2 for tag, 4 for size and 4 for command code

    AddUInt16Reversed (cmdBuf, 0x0004, ref offset); //Entity Type SRK = 0x0004
    AddUInt32Reversed (cmdBuf, 0x40000000, ref offset); //Entity Value SRK = 0x40000000
    rnd.NextBytes (oddOsap);
    AddBlob (cmdBuf, oddOsap, ref offset);
    uint cmdSize = (System.UInt32) offset;

คำสั่ง TPM_OSAP ถูกดำเนินการคือ:

TPM_OSAP ถูกดำเนินการ

คำสั่ง TPM 1.2 แต่ละคำสั่งมีลักษณะดังนี้:

  2 bytes       4 bytes             4 bytes
+---------+------------------+------------------+---------------------------
|   Tag   |       Size       |   Command code   |    Command body    ....
+---------+------------------+------------------+---------------------------

แท็กคือค่าสองไบต์ที่ระบุว่าสิ่งต่อไปนี้เป็นอินพุตหรือเอาต์พุตและมีค่าข้อมูลการตรวจสอบสิทธิ์ตามพารามิเตอร์คำสั่งหรือไม่ สำหรับ TPM_OSAP แท็กต้องเป็น TPM_TAG_RQU_COMMAND (0x00C1) ตามข้อมูลจำเพาะซึ่งหมายถึง "คำสั่งที่ไม่มีการอนุญาต"

ขนาดคือค่าสี่ไบต์ที่ระบุขนาดของคำสั่งเป็นไบต์รวมถึงแท็กและขนาดเอง เราจะตั้งค่านี้ในภายหลังเมื่อเราคำนวณแล้ว

รหัสคำสั่งคือค่าสี่ไบต์ที่เซิร์ฟเวอร์เป็น ID คำสั่งโดยจะบอก TPM ถึงวิธีตีความคำสั่งที่เหลือ รหัสคำสั่งของเราที่นี่คือ TPM_OSAP (0x0000000B)

สองสิ่งถัดไปที่ต้องตั้งค่าคือประเภทเอนทิตีและค่าเอนทิตี เนื่องจากเราต้องการใช้คีย์ที่มีอยู่แล้วใน TPM เราจะใช้เอนทิตีประเภท "SRK" (0x0004) และเนื่องจากเรากำลังดำเนินการภายใต้สมมติฐานที่ว่า TPM เป็นเจ้าของแล้วจึงปลอดภัยที่จะถือว่ามี SRK โหลดภายใต้แฮนเดิลถาวร 0x40000000 ตามข้อมูลจำเพาะดังนั้นเราจะใช้ค่าแฮนเดิลถาวรนี้สำหรับค่าเอนทิตีของเรา (SRK ย่อมาจาก "Storage Root Key" และเป็นคีย์หลักที่คีย์ที่เป็นเจ้าของ TPM ส่วนใหญ่ได้มา)

    result = Tbsip_Submit_Command (hContext, 0, 200, pCmd, cmdSize, pRes, & resSize);

ในที่สุดเราก็คำนวณขนาดคำสั่งและตั้งค่าและส่งคำสั่ง

    offset = 2 + 4 + 4; //2 for tag, 4 for size and 4 for return code
    byte[] hauthbytes = new byte[Marshal.SizeOf (hAuth)];
    Array.Copy (response, offset, hauthbytes, 0, hauthbytes.Length);
    Array.Reverse (hauthbytes);
    hAuth = System.BitConverter.ToUInt32 (hauthbytes, 0);
    offset += Marshal.SizeOf (hAuth);
    Array.Copy (response, offset, nonceEven, 0, nonceEven.Length);
    offset += nonceEven.Length;
    Array.Copy (response, offset, evenOsap, 0, evenOsap.Length);

ข้อมูลที่เราควรได้รับคืนจาก TPM บน TPM_OSAP คือ:

การตอบสนอง TPM_OSAP

เราจึงกลับมา:

  • ที่จับการอนุญาตเพื่อใช้กับคำสั่งหลักของเรา (Seal)
  • nonceEven: nonce ที่สร้างโดย TPM เพื่อใช้กับคำสั่งหลัก
  • nonceEvenOSAP: OSAP nonce ที่เป็นตัวต่อต้าน nonce ที่เราสร้างขึ้นในฝั่งของเราก่อนส่งคำสั่ง TPM_OSAP สองสิ่งนี้จะถูกใช้ในการสร้าง "ความลับที่ใช้ร่วมกัน"

เราแยกค่าเหล่านั้นและเก็บไว้ในตัวแปร

    byte[] sharedSecretBuf = new byte[evenOsap.Length + oddOsap.Length];
    Array.Copy (evenOsap, 0, sharedSecretBuf, 0, evenOsap.Length);
    Array.Copy (oddOsap, 0, sharedSecretBuf, evenOsap.Length, oddOsap.Length);
    System.Security.Cryptography.HMACSHA1 sharedSecretHmac = new System.Security.Cryptography.HMACSHA1 (srkAuthdata);
    byte[] sharedSecret = sharedSecretHmac.ComputeHash (sharedSecretBuf);

จากนั้นเราจะคำนวณ "ความลับที่ใช้ร่วมกัน" ตามข้อมูลจำเพาะค่าที่ใช้ในการคำนวณคือ OSAP สอง nonces (ค่าหนึ่งที่สร้างโดยผู้ใช้และค่าหนึ่งที่สร้างโดย TPM) และค่าการอนุญาตสำหรับคีย์ที่เราต้องการใช้ - SRK ตามแบบแผนค่าการตรวจสอบสิทธิ์ SRK คือ "การตรวจสอบสิทธิ์ที่รู้จักกันดี": บัฟเฟอร์ 20 ไบต์ที่เป็นศูนย์ ในทางเทคนิคเราสามารถเปลี่ยนค่านี้เป็นอย่างอื่นเมื่อเป็นเจ้าของ TPM แต่ไม่ได้ทำในทางปฏิบัติดังนั้นเราจึงสามารถสรุปได้อย่างปลอดภัยว่าค่า "การตรวจสอบสิทธิ์ที่รู้จักกันดี" นั้นดี

ต่อไปมาดูสิ่งที่เข้าสู่คำสั่ง TPM_Seal:

TPM_Seal

ส่วนใหญ่ของพารามิเตอร์เหล่านี้เป็นเล็กน้อยเพื่อสร้างยกเว้นสองของพวกเขาและencAuth pubAuthมาดูทีละคน

encAuthคือ "AuthData ที่เข้ารหัสสำหรับข้อมูลที่ปิดผนึก" AuthData ของเราในที่นี้คือ "auth ที่รู้จักกันดี" จากเมื่อก่อน แต่ใช่เรายังต้องเข้ารหัส เนื่องจากเราใช้เซสชัน OSAP จึงมีการเข้ารหัสตาม ADIP หรือโปรโตคอลการแทรกข้อมูลการอนุญาต จากข้อมูลจำเพาะ: "ADIP อนุญาตให้สร้างเอนทิตีใหม่และการแทรกที่ปลอดภัยของ AuthData เอนทิตีใหม่การส่ง AuthData ใหม่จะใช้การเข้ารหัสด้วยคีย์ตามความลับที่ใช้ร่วมกันของเซสชัน OSAP" นอกจากนี้: "สำหรับอัลกอริทึมการเข้ารหัส XOR ที่บังคับผู้สร้างจะสร้างคีย์การเข้ารหัสโดยใช้แฮช SHA-1 ของข้อมูลลับที่แชร์ของ OSAP และเซสชันที่ไม่ใช่เซสชันผู้สร้าง XOR จะเข้ารหัส AuthData ใหม่โดยใช้คีย์การเข้ารหัสเป็นแพดครั้งเดียวและ ส่งข้อมูลที่เข้ารหัสนี้พร้อมกับคำขอสร้างไปยัง TPM "

แผนภาพต่อไปนี้อธิบายวิธีการทำงานของ ADIP:

ADIP

pubAuthคือ "การสรุปเซสชันการอนุญาตสำหรับอินพุตและ keyHandle" ส่วนที่ 1 ของข้อมูลจำเพาะใน "การประกาศพารามิเตอร์สำหรับ OIAP และตัวอย่าง OSAP" จะอธิบายวิธีตีความตารางพารามิเตอร์ TPM_Seal ด้านบน: "คอลัมน์ HMAC # ให้รายละเอียดพารามิเตอร์ที่ใช้ในการคำนวณ HMAC พารามิเตอร์ 1S, 2S และอื่น ๆ จะเรียงต่อกันและ แฮชเป็น inParamDigest หรือ outParamDigest โดยปริยายเรียกว่า 1H1 และอาจเป็น 1H2 หากมีเซสชันการอนุญาตสองครั้งสำหรับเซสชันแรก 1H1, 2H1, 3H1 และ 4H1 จะเชื่อมต่อกันและ HMAC'ed สำหรับเซสชันที่สอง 1H2, 2H2, 3H2, และ 4H2 เชื่อมต่อกันและ HMAC'ed " ดังนั้นเราจะต้องแฮชข้อความธรรมดาขนาดของมันขนาดข้อมูล PCR encAuthจากด้านบนและลำดับ TPM_Seal จากนั้น HMAC ที่มีสอง nonces และบูลีน "ดำเนินการต่อ" โดยใช้ OSAP "

รวมทั้งหมดไว้ในแผนภาพ:

การคำนวณ pubAuth

สังเกตว่าเราตั้งค่า "ขนาดข้อมูล PCR" เป็นศูนย์ในรหัสนี้ได้อย่างไรเนื่องจากเราต้องการเข้ารหัสข้อมูลโดยไม่ต้องล็อกเป็นสถานะระบบ อย่างไรก็ตามการจัดเตรียมโครงสร้าง "ข้อมูล PCR" เป็นเรื่องเล็กน้อยหากจำเป็น

    offset = 0;
    AddUInt16Reversed (cmdBuf, 0x00C2, ref offset); 
    offset = 6;
    AddUInt32Reversed (cmdBuf, 0x00000017, ref offset); // TPM_ORD_SEAL;
    ...
    result = Tbsip_Submit_Command (hContext, 0, 200, pCmd, cmdSize, pRes, & resSize);

ในที่สุดเราก็สร้างคำสั่งและส่งไป

    byte[] retBuffer = new byte[responseSize - 10];
    Array.Copy (response, 10, retBuffer, 0, retBuffer.Length);
    Tbsip_Context_Close (hContext);
    return retBuffer;

เราใช้ฟังก์ชัน Tbsip_Context_Close ()เพื่อปิดจุดจับการสื่อสารของเรา

เราส่งคืนการตอบกลับตามที่อยู่ที่นี่ ตามหลักการแล้วคุณต้องการย้อนกลับไบต์อีกครั้งและตรวจสอบความถูกต้องโดยการคำนวณresAuthค่าใหม่เพื่อป้องกันการโจมตีจากคนตรงกลาง


สิ่งที่ทำให้สับสนคือไม่มีคำสั่ง Tspi_Data_Bind

เนื่องจาก Tspi_Data_Bind เป็นคำสั่ง TSS ไม่ใช่คำสั่ง TPM เหตุผลก็เพราะว่ามันไม่ต้องการความลับ (ใช้เฉพาะคีย์สาธารณะเท่านั้น) จึงสามารถทำได้โดยไม่ต้องเกี่ยวข้องกับ TPM อย่างไรก็ตามสิ่งนี้ทำให้เกิดความสับสนและแม้แต่คำสั่งที่ไม่ต้องการความลับก็รวมอยู่ในข้อกำหนด TPM 2 แล้ว

ฉันจะเข้ารหัสคีย์ด้วยคีย์สาธารณะของ TPM ได้อย่างไร

ขึ้นอยู่กับเวอร์ชัน TPM ด้วยคำสั่ง TPM_CreateWrapKey สำหรับ TPM 1.2 ด้วยคำสั่ง TPM2_Create สำหรับ TPM 2

นักพัฒนาจะล็อคคีย์ของ TPM ได้อย่างไร?

ไม่ว่าจะสร้างใน TPM หรือห่อหรือใช้วิธีการอื่นที่มีอยู่

TPM2_Create ระบุคีย์ HMAC

ข้อความในหนังสือสับสน คุณไม่ได้ระบุคีย์ HMACคุณระบุว่าคุณต้องการคีย์ HMAC

ความจริงที่ว่าคีย์ HMAC ไม่ใช่ความลับก็สมเหตุสมผลแล้ว

ไม่มันไม่สมเหตุสมผล ที่สำคัญคือความลับ

... ใช้กุญแจในขณะที่รักษาความปลอดภัยในอุปกรณ์ฮาร์ดแวร์ ... ยอดเยี่ยม! คุณจะทำอย่างไรมันได้หรือไม่!?

มีคำสั่งสำหรับสร้างคีย์หรือนำเข้าสำหรับ TPM ทั้งสองเวอร์ชัน สำหรับ TPM 1 มีเพียงรูทคีย์เดียวเท่านั้นคือ SRK ซึ่งคุณสามารถสร้างลำดับชั้นของคีย์ได้โดยการสร้างคีย์แบบห่อ ด้วย TPM 2 คุณสามารถมีคีย์หลักหรือรูทหลายคีย์ได้

TPM มีความสามารถในการสร้างคีย์การเข้ารหัสและปกป้องความลับภายในขอบเขตฮาร์ดแวร์หรือไม่ เป็นเช่นนั้นอย่างไร?

ดูด้านบน.

ยอดเยี่ยม! นี่คือกรณีการใช้งานที่ฉันต้องการ นอกจากนี้ยังเป็นกรณีการใช้งานที่ Microsoft ใช้ TPM สำหรับ. ฉันต้องทำอย่างไร!?

อาจขึ้นอยู่กับประเภทของไดรฟ์ ในกรณีของไดรฟ์ที่ไม่ใช่ SED คีย์เข้ารหัสของไดรฟ์อาจถูกพันด้วยคีย์ TPM ในกรณีของไดรฟ์ SED รหัสผ่าน Admin1 (หรือมากกว่านั้น) จะถูกปิดผนึกด้วย TPM

คีย์การรับรองหรือ EK ... ที่ไหนสักแห่งใน TPM เป็นคีย์ส่วนตัว RSA กุญแจนั้นถูกล็อคไว้ที่นั่น - โลกภายนอกจะไม่เห็น ฉันต้องการให้ TPM เซ็นชื่อด้วยคีย์ส่วนตัว (เช่นเข้ารหัสด้วยคีย์ส่วนตัว)

EK ไม่ใช่คีย์การลงนาม แต่เป็นคีย์เข้ารหัส อย่างไรก็ตามไม่ใช่คีย์การเข้ารหัสที่มีวัตถุประสงค์ทั่วไปแต่สามารถใช้ได้ในบางบริบทเท่านั้น

แต่สิ่งที่อยากทำจริงๆคือ "ปิดผนึก" ข้อมูลบางส่วน

ดูด้านบน.


2

เมื่อกล่าวว่า

การระบุคีย์ HMAC

ก็ไม่ได้หมายความให้คีย์ HMAC - มันหมายถึง"ชี้ไปที่คีย์ HMAC ที่คุณต้องการใช้งาน"

TPM สามารถใช้คีย์ HMAC ได้ไม่ จำกัด จำนวนตามที่ระบุไว้ในหนังสือ คุณต้องบอก TPM ว่าจะใช้อันไหน


ดังนั้นอาจมีตัวอย่างโค้ดที่แสดงวิธีระบุ (ชี้ไปที่) คีย์ HMAC ที่จะใช้ในภาษา C # หรือภาษาอื่นหรือไม่?
ชาด
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.