โปรดทราบว่าคำตอบที่ยอดเยี่ยมนี้เป็นของ Ossifrage คลื่นไส้ ว่าเลิกอุดหนุน! ฉันทำสำเนาและวางแล้วสร้างชุมชน การลงคะแนนคำตอบนี้ไม่ได้สร้างประโยชน์อะไรให้กับฉัน ถ้าคุณสามารถลงคะแนนให้พวกเขา อินโฟเซค.
จากตัวอย่างรหัสที่ให้มา เป็นไปได้ที่จะกำหนดรหัสผ่านที่ถูกต้องโดยการจับเวลารหัสเมื่อได้รับอินพุตต่างๆ
ขั้นแรก คุณไม่ควรตรวจสอบรหัสผ่านโดยตรง! ที่ อย่างน้อยที่สุดคุณควรแฮชรหัสผ่านด้วยแฮชรหัสผ่านเช่น Argon2id ก่อน และเปรียบเทียบแฮชรหัสผ่านของอินพุตกับแฮชรหัสผ่านที่คุณเก็บไว้ระหว่างการลงทะเบียนผู้ใช้ (หรือเมื่อผู้ใช้เปลี่ยนรหัสผ่านครั้งล่าสุด)
ยิ่งไปกว่านั้น คุณควรใช้โปรโตคอลข้อตกลงคีย์ที่ตรวจสอบสิทธิ์ด้วยรหัสผ่าน เช่น OPAQUE แต่สิ่งเหล่านี้อาจเกินระดับการชำระเงินของคุณในขณะนี้ จนกว่าจะเห็นการยอมรับและการนำไปใช้อย่างแพร่หลายมากขึ้น
ฉันจะทำอย่างไรเพื่อให้แน่ใจว่ารหัสของฉันไม่เสี่ยงต่อการถูกโจมตีตามเวลาดังกล่าว
วิธีที่ดีที่สุดในการเริ่มต้นคือการใช้รูทีนของไลบรารีหรือแบบดั้งเดิมนั้น คนอื่น ได้เขียนไว้แล้วและมีเหตุผลที่จะคงไว้ ตัวอย่างเช่น ใน NaCl/libsodium คุณสามารถใช้ crypto_verify_32
เพื่อเปรียบเทียบสตริงขนาด 32 ไบต์สองรายการ เช่น แฮช Argon2id สองรายการ หรือรหัสยืนยันข้อความ HMAC-SHA256 สองรายการ จากนั้นความพยายามที่จะตอบคำถามนี้สามารถมุ่งเน้นไปที่ที่เดียวที่จะได้รับความสนใจและการตรวจสอบอย่างละเอียดและจะติดตามความก้าวหน้า
แต่สมมุติว่าคุณไม่มี crypto_verify_32
หรือต้องการนำไปปฏิบัติเอง คุณทำอะไรได้บ้าง?
ในการเริ่มต้น คุณต้องเข้าใจว่าการดำเนินการใดมีช่องทางด้านข้าง มันคือ ดึงดูด เพื่อบอกว่าเป็นคำตอบอื่น ๆ ที่ช่องด้านข้างเกิดขึ้นเพียงเพราะ แต่แรก
ยกเลิก. แต่นั่นไม่ใช่เรื่องราวทั้งหมด โดยทั่วไปก็มี การดำเนินการหลายอย่าง (ในที่นี้เขียนด้วยภาษาซีเพื่อประกอบ) นั้นอาจใช้ระยะเวลาขึ้นอยู่กับ ค่า ของอินพุต เราเรียกการดำเนินการเหล่านี้ว่า เวลาผันแปร การดำเนินงานตรงกันข้ามกับ เวลาคงที่*:
สำหรับ (i = 0; i < n; i++) ถ้า (x[i] == y[i]) คืนค่า EFAIL;
เห็นได้ชัดว่าใช้เวลา การวนซ้ำน้อยลง ดังนั้นจึงรับประกันได้ว่าจะทำงานในเวลาผันแปรขึ้นอยู่กับค่าลับของ x[ผม]
และ ย [ฉัน]
.
เงื่อนไขขึ้นอยู่กับความลับเพียงอย่างเดียว สำหรับ (i = 0; i < n; i++) ถ้า (x[i]) ไม่ดี++;
, ถ้า x[ผม]
เป็นความลับอาจทำงานในเวลาที่ผันแปรเช่นกัน แม้ว่าการวนซ้ำจะไม่ยกเลิกก่อนกำหนด. ทำไม
นี่คือค่าประมาณคร่าวๆ คำสั่งเครื่องที่ CPU อาจดำเนินการมีลักษณะดังนี้:
0: tmp := x[i]
แยกเป็น 1 ถ้า tmp เป็นศูนย์
แย่ := แย่ + 1
1: ผม := ผม + 1
แยกเป็น 0 ถ้า i < n
เดอะ จำนวนคำแนะนำ ดำเนินการขึ้นอยู่กับค่าของ x[ผม]
อยู่ที่การทำซ้ำแต่ละครั้ง: เราข้ามไป แย่ := แย่ + 1
ในการวนซ้ำบางอย่าง นี่เป็นรูปแบบที่ดีสำหรับการโจมตีช่วงต้น เช่น., RSA ทำงานเหมือนใน เอกสารสำคัญของ Kocher เกี่ยวกับการโจมตีแบบกำหนดเวลา: ลูปการยกกำลังแบบโมดูลาร์หลักคำนวณ a (พูด) 2048 บิตโมดูลาร์กำลังสองโดยไม่มีเงื่อนไข แต่คำนวณการคูณแบบโมดูลาร์ 2048 บิต อย่างมีเงื่อนไข ขึ้นอยู่กับค่าของเลขชี้กำลังลับ การข้ามการคูณจะเปลี่ยนเวลาที่ใช้โดยการดำเนินการทั้งหมดอย่างมาก
มีเหตุผลอื่นอีก แต่เกี่ยวข้องกับ การทำนายสาขาซึ่งเป็นองค์ประกอบการออกแบบที่สำคัญในสิ่งที่ทำให้ CPU สมัยใหม่ทำงานได้อย่างรวดเร็วในเวิร์กโหลดจำนวนมาก แม้ว่าคุณจะเขียนโค้ดจำนวนเท่ากัน (เช่น จำนวนคำสั่งเครื่องเท่าเดิม และคุณรับประกันได้ว่าจะใช้จำนวนรอบเท่ากันในการคำนวณ ) ในแต่ละสาขาของเงื่อนไข เวลาที่ใช้ในการดำเนินการอาจขึ้นอยู่กับว่าเงื่อนไขดำเนินไปอย่างไร
โดยทั่วไปแล้ว CPU นั้นไม่ดีในการเก็บรักษา คำสั่งใดได้รับการดำเนินการ ความลับดังนั้นอย่าทำให้ ทางเลือกของคำแนะนำ ขึ้นอยู่กับความลับ
การค้นหาตาราง/อาร์เรย์อาจใช้เวลาแตกต่างกัน ขึ้นอยู่กับหน่วยความจำที่ถูกแคชในแคช CPU ดังนั้น หากผ ตำแหน่งในอาร์เรย์ ที่คุณกำลังอ่านนั้นขึ้นอยู่กับความลับ เวลาที่ใช้อาจขึ้นอยู่กับความลับซึ่งถูกนำไปใช้ กู้คืนคีย์ AES ตามเวลาแคช.
(สิ่งนี้ทำให้ AES เป็นการออกแบบที่ค่อนข้างน่าสงสัยเมื่อมองย้อนกลับไป โดยตั้งใจใช้การค้นหาตารางที่ขึ้นกับคีย์! NIST's เผยแพร่เหตุผล (§3.6.2 การโจมตีการนำไปใช้: บทบาทของการปฏิบัติการ) อ้างอย่างน่าสงสัยว่าการค้นหาตาราง "ไม่เสี่ยงต่อการโจมตีแบบกำหนดเวลา" แม้ว่าจะมีรายงานการโจมตีดังกล่าวหลายครั้งนับตั้งแต่นั้นเป็นต้นมา)
ระยะแปรผันเช่น x = y << z
อาจใช้เวลามากขึ้นใน CPU บางตัวหาก ซี
มีขนาดใหญ่ขึ้นและใช้เวลาน้อยลงหากมีขนาดเล็กลง
(สิ่งนี้ทำให้ RC5 และผู้เข้ารอบสุดท้ายของ AES RC6 การออกแบบที่ค่อนข้างน่าสงสัยเมื่อมองย้อนกลับไปโดยตั้งใจใช้ระยะการหมุนที่ขึ้นกับคีย์!)
ใน CPU บางรุ่น การคูณอาจทำงานเร็วขึ้นหรือช้าลง ขึ้นอยู่กับว่าครึ่งบนของอินพุตเป็นศูนย์หรือไม่
โดยหลักการแล้วการเพิ่มจำนวนเต็ม 64 บิตบน CPU 32 บิตอาจใช้เวลามากขึ้น ขึ้นอยู่กับว่ามีการพกพาหรือไม่ ทั้งนี้เพราะเมื่อ x
, ย
, และ ซี
, เป็นจำนวนเต็ม 64 บิต, ลอจิก x = y + z
อาจมีลักษณะดังนี้:
int พกพา = 0;
x[0] = y[0] + z[0];
ถ้า (การเพิ่มก่อนหน้านี้มากเกินไป)
พกพา = 1;
x[1] = y[1] + z[1] + พกพา;
ดังนั้น เวลาที่ใช้อาจขึ้นอยู่กับว่ามีการพกพาจากผลรวมของซีก 32 บิตต่ำไปยังผลรวมของซีก 32 บิตสูงหรือไม่ (ในทางปฏิบัติ มักจะเป็นปัญหาเฉพาะกับ CPU ที่แปลกใหม่หรือสำหรับช่องด้านข้างประเภทอื่นๆ เช่น การวิเคราะห์พลังงาน ซึ่งเกี่ยวข้องกับสมาร์ทการ์ดมากกว่าแล็ปท็อปและโทรศัพท์)
นี่อาจฟังดูล้นหลามเล็กน้อย พวกเราทำอะไรได้บ้าง?
มีการดำเนินการบางอย่างที่ โดยทั่วไปแล้ว ทำงานตลอดเวลาบน CPU ส่วนใหญ่ พวกเขาเป็น:
- การดำเนินการระดับบิต:
x & y
, x | ย
, x ^ ย
, ~x
และอื่น ๆ ที่ไม่ปรากฏใน C เช่น AND-with-complement
- ระยะทางคงที่ กะและการหมุน เหมือนกะ
x << 3
หรือการหมุนx <<< 3
(ไม่ใช่ภาษาซีมาตรฐาน แต่พบได้ทั่วไปในการเข้ารหัส หมายถึง (x << 3) | (x >> (32 - 3))
, ถ้า x
เป็น 32 บิต)
- มักจะ การบวกและการลบจำนวนเต็ม:
x + ย
, x - ย
, เมื่อไร x
และ ย
คือ (พูด) จำนวนเต็ม 32 บิตที่ไม่ได้ลงนามบน CPU 32 บิต และมักจะเป็นจำนวนเต็ม 64 บิตบน CPU 32 บิตด้วยความช่วยเหลือของคำสั่ง ADD-with-carry
- บางครั้ง การคูณจำนวนเต็ม, แต่ เรื่องราวเกี่ยวกับการคูณคือ ที่ซับซ้อนซึ่งน่าเสียดายสำหรับการเข้ารหัสเนื่องจากการคูณผสมบิตรอบ ๆ ค่อนข้างดีและมีคุณสมบัติเกี่ยวกับพีชคณิตที่เป็นประโยชน์
เพื่อความชัดเจน: ฉันไม่ได้หมายความอย่างนั้น คอมไพเลอร์ภาษาซี รับประกันการดำเนินการเหล่านี้ในเวลาคงที่หากคุณใช้ในโปรแกรม C ฉันแค่ใช้สัญลักษณ์ C สำหรับการดำเนินการที่ ซีพียู โดยทั่วไปดำเนินการในเวลาคงที่ (เพิ่มเติมเกี่ยวกับคำเตือนนี้ในอีกสักครู่)
“แต่เดี๋ยวก่อน” คุณท้วงว่า “ฉันจะเขียนโปรแกรมที่เป็นประโยชน์จากการดำเนินการเหล่านี้ได้อย่างไร ไม่มีเงื่อนไข? ไม่มีลูป? ไม่มีอาร์เรย์?â
ขั้นแรก คุณไม่จำเป็นต้องหลีกเลี่ยงเงื่อนไข การวนซ้ำ หรืออาร์เรย์ โดยสิ้นเชิง. พวกเขาทำไม่ได้ ขึ้นอยู่กับความลับ. ตัวอย่างเช่น, สำหรับ (i = 0; i < 32; i++) ... x[i] ...
ไม่เป็นไร แต่ สำหรับ (i = 0; i < m[0]; i++) ...
ไม่เป็นไรถ้า เมตร[0]
ควรจะเป็นความลับและ สำหรับ (i = 0; ฉัน < m[0]; i++) ... แท็บ[x[i]] ...
ไม่เป็นไรถ้า x[ผม]
น่าจะเป็นความลับ
ประการที่สอง คุณยังสามารถสร้างสิ่งเหล่านี้ได้! มันค่อนข้างยุ่งยากกว่าเล็กน้อย ตัวอย่างเช่นสมมติว่า ข
เป็น uint32_t ที่เป็น 0 หรือ 1 จากนั้น ข - 1
คือ -1 = 0xffffffff หรือ 0 ตามลำดับ ดังนั้น
x = ((ข - 1) & z) | (~(ข - 1) & y);
สาเหตุ x = ย
ถ้า ข
คือ 1, หรือ x = z
ถ้า ข
คือ 0âมาก เช่น x = (ข ? y : z)
แต่ไม่มีสาขา. แน่นอนว่าสิ่งนี้ต้องใช้คอมพิวเตอร์ ทั้งสอง ย
และ ซี
จึงมีผลกระทบด้านประสิทธิภาพบ้าง! ในทำนองเดียวกัน คุณสามารถค้นหาองค์ประกอบของตารางได้โดยการค้นหา ทั้งหมด องค์ประกอบของตารางและเลือกสิ่งที่คุณต้องการด้วยการดำเนินการระดับบิตเช่นนี้ ไม่เร็วเท่า x[ผม]
แต่ก็ไม่รั่วเหมือนกัน
โดยทั่วไปแล้วคุณ สามารถ แปลงโปรแกรมที่มีเงื่อนไขให้เป็นวงจรลอจิกที่ไม่มีเงื่อนไข แม้ว่าคุณจะไม่มีก็ตาม ต้องการ เพื่อเหตุผลด้านประสิทธิภาพ มีเคล็ดลับที่คล้ายกันอื่น ๆ อีกมากมายที่คุณสามารถทำได้ คุณอาจร่างรูทีนความเท่าเทียมกันของหน่วยความจำเวลาคงที่ เช่น crypto_verify_32
แบบนี้ สมมติว่า x และ y เป็นอาร์เรย์ uint8_t:
ผลลัพธ์ uint32_t = 0;
สำหรับ (i = 0; i < 32; i++)
ผลลัพธ์ |= x[i] ^ y[i];
กลับ ((ผลลัพธ์ - 1) >> 8) & 1;
แบบฝึกหัด: สิ่งนี้ส่งคืน 0 สำหรับเท่ากับและ 1 สำหรับไม่เท่ากัน หรือ 0 สำหรับไม่เท่ากัน และ 1 สำหรับเท่ากับ
การเขียนโปรแกรมเช่นนี้และการนำระบบเข้ารหัสเช่น X25519 มาใช้ ให้กำลังใจ การใช้งานที่มีลักษณะเช่นนี้ แทนที่จะเป็นระบบเข้ารหัสเช่น RSA หรือ AES นั้น ให้กำลังใจ การใช้งานที่เกี่ยวข้องกับสาขาที่ขึ้นอยู่กับความลับหรือการค้นหาตารางที่ขึ้นกับความลับเป็นการเริ่มต้นที่ดีสำหรับการเสียบช่องทางด้านเวลา
แต่มีการจับ! จำได้ไหมเมื่อฉันบอกว่าคอมไพเลอร์ C ไม่รับประกันเวลาคงที่? คอมไพเลอร์ C อัจฉริยะเช่น Clang/LLVM อาจ จำได้ ว่าฉลาด crypto_verify_32
ลูปด้านบนสามารถดำเนินการได้ ได้อย่างมีประสิทธิภาพมากขึ้น โดยการทำให้ยกเลิกก่อนเวลา และอาจยกเลิกการทำงานอย่างหนักที่คุณทำเพื่อเขียนใหม่เป็นวงจรลอจิกที่ทำงานในเวลาคงที่ (ในกรณีอื่นๆ อาจช่วยคุณได้ เช่น การแปลง x = (ข ? y : z);
เป็นคำสั่งย้ายแบบมีเงื่อนไข CMOV โดยไม่มีสาขา แต่โดยปกติแล้วคุณไม่สามารถพึ่งพาความปรารถนาดีของคอมไพเลอร์ C ได้)
มีเคล็ดลับบางอย่างที่คุณสามารถทำได้เพื่อขัดขวางสิ่งนี้ เช่น ชิ้นส่วนแอสเซมบลีแบบอินไลน์ที่ทำให้คอมไพเลอร์ทิ้งสมมติฐานทั้งหมดสำหรับการปรับให้เหมาะสม:
ผลลัพธ์ uint32_t = 0;
สำหรับ (i = 0; i < 32; i++)
ผลลัพธ์ |= x[i] ^ y[i];
asm ระเหย ("" ::: "หน่วยความจำ");
กลับ ((ผลลัพธ์ - 1) >> 8) & 1;
สิ่งนี้อาจใช้ได้หรือไม่ได้กับคอมไพเลอร์ของคุณ เพื่อความมั่นใจ คุณต้องตรวจสอบรหัสเครื่องที่สร้างขึ้นโดยคอมไพเลอร์จริงๆ และถึงอย่างนั้น คอมไพเลอร์ก็อาจทำการปรับให้เหมาะสมแบบทันท่วงที เขียนใหม่ รหัสเครื่องตามการวิเคราะห์โปรไฟล์ โดยเฉพาะในภาษาระดับสูงกว่าเช่น Java ดังนั้นคุณอาจต้องการ เขียนตรรกะในการประกอบ (หรือในภาษาการเขียนโปรแกรมเช่น qhasm ที่สามารถสร้างแอสเซมบลีที่ปรับแต่งแล้วได้อย่างน่าเชื่อถือมากกว่าคอมไพเลอร์ C) และเรียกมันจาก C
บางทีสักวันหนึ่งคอมไพเลอร์ C จะนำไฟล์ ความลับ
รอบคัดเลือกเช่น คอสต์
หรือ ระเหย
ซึ่งบังคับให้คอมไพเลอร์สร้างเฉพาะคำสั่งเครื่องที่รู้จักใน CPU บางรุ่น!â ให้รันในเวลาคงที่เมื่อทำงานกับออบเจกต์ และป้องกันไม่ให้คอมไพเลอร์ใช้ทางลัด เช่น ยกเลิกก่อนกำหนดที่ขึ้นอยู่กับความลับ ห่วง แต่วันนั้นยังมาไม่ถึง
นอกจากนี้ยังมีเรื่องของคำสั่งเครื่องที่ทำงานจริงในเวลาคงที่บน CPU ซึ่งบางครั้งได้รับการจัดทำเป็นเอกสารและบางครั้งก็เชื่อถือได้ ดังนั้นนอกจากจะทำ วิศวกรรม ในการสร้างโปรแกรมของคุณจากวงจรลอจิก คุณต้องทำเช่นกัน ศาสตร์ เพื่อหาว่าการดำเนินการใดที่ปลอดภัยสำหรับใช้งานบน CPU
สิ่งนี้นำเรากลับไปสู่จุดเดิม: คุณต้องการมุ่งเน้นความพยายามในการรักษาสิ่งนี้ให้เป็นรูทีนของไลบรารี เพื่อให้โปรแกรมเมอร์แต่ละคนไม่ต้องติดตามความหลากหลายของคอมไพเลอร์ (และการออกแบบ CPU!) ในโค้ดและเวลาที่สร้างขึ้น ด้วยตัวเองและสามารถปล่อยทิ้งไว้ได้ หมีเพื่อนบ้านที่เป็นมิตรของเรา.
มีวิธีตอบโต้อื่นนอกเหนือจากลอจิกเวลาคงที่หรือไม่ บางครั้งใช่.
คุณสามารถส่งเสียงรบกวนแบบสุ่มเข้าไปในตรรกะของคุณ โดยหวังว่ามันจะทำให้การวัดของผู้โจมตีสับสน แต่มีสัญญาณรบกวนอยู่แล้วในการวัด เช่น การตั้งเวลาในระบบปฏิบัติการ ดังนั้นพวกเขาจึงต้องเก็บตัวอย่างมากขึ้น—และปรากฎว่าสัญญาณรบกวนคือ ไม่ใช่มาตรการตอบโต้ช่องทางด้านข้างที่มีประสิทธิภาพมากนัก.
โดยเฉพาะอย่างยิ่ง เสียงประดิษฐ์จะเพิ่มค่าใช้จ่ายของผู้โจมตีมากที่สุดประมาณกำลังสองของอัตราส่วนของเสียงเทียมต่อเสียงจริง ซึ่งต่ำกว่าสิ่งที่มักจะถือว่าเป็นช่องว่างที่ยอมรับได้สำหรับการรักษาความปลอดภัยในการเข้ารหัส ดังนั้นคุณจึงเสียเวลาส่วนใหญ่ไปกับการไม่ทำอะไรเลย
คุณสามารถใช้คุณสมบัติเชิงพีชคณิตของระบบเข้ารหัสเพื่อสุ่มได้ บางครั้งเรียกว่า âblindingâ ตัวอย่างเช่น แทนที่จะใช้คอมพิวเตอร์ y^d ม็อด n
ที่ไหน ง
เป็นเลขชี้กำลังลับใน RSA คุณสามารถเลือกได้ ร
สุ่มคำนวณ s := r^e ม็อด n
ที่ไหน e*d â¡ 1 (สมัย (n))
คูณ ย
โดย ส
ที่จะได้รับ (y * r^e) ม็อด n
,คำนวณ (y * r^e)^d mod n = (r * y^d) mod n
แล้วแบ่งออก ร
.
การใช้งานจำนวนมาก เช่น OpenSSL ใช้วิธีนี้เนื่องจากเป็นวิธีที่ง่ายในการปรับเปลี่ยนการใช้งานระบบเข้ารหัสลับที่มีอยู่เช่น RSA ซึ่งมีโครงสร้างพีชคณิตที่จำเป็น ไม่ใช่ความคิดที่ไม่ดีเหมือนสัญญาณรบกวนแบบสุ่ม แต่มันมีค่าใช้จ่าย คุณต้องทำงานพิเศษสำหรับการสุ่ม คุณต้องมีการแบ่งแบบแยกส่วนหรือตรรกะผกผัน และช่องด้านข้างอาจยังรั่วไหลข้อมูลเกี่ยวกับ ร
และ ง
. ตัวอย่างเช่น แม้แต่การยกกำลังแบบโมดูลาร์แบบปิดตาก็จะทำให้ Hamming Weight รั่วไหล ง
เว้นแต่คุณจะใช้มาตรการตอบโต้เพิ่มเติม เช่น การเพิ่มตัวคูณแบบสุ่มของ (น)
ถึง ง
ก่อนâซึ่งอาจเปิดช่องด้านข้างเพิ่มเติม เป็นต้น
สำหรับกรณีเฉพาะของการเปรียบเทียบสตริงสองไบต์เพื่อความเท่าเทียมกัน (เช่น รหัสยืนยันข้อความสองรหัส) ทางเลือกหนึ่งที่เหมาะสมคือการแฮชสตริงเหล่านี้ด้วยกลุ่มฟังก์ชันสุ่มเทียม เช่น HMAC-SHA256 ภายใต้รหัสลับแบบใช้ครั้งเดียว เค
และตรวจสอบว่า HMAC-SHA256_k(x) == HMAC-SHA256_k(y)
.
ความน่าจะเป็นของผลบวกลวงคือ 1/2256ซึ่งเป็นโอกาสที่น้อยกว่าที่คุณเคยต้องกังวล คุณสามารถใช้ความเท่าเทียมกันของเวลาผันแปรได้อย่างปลอดภัยสำหรับ HMAC เนื่องจากถ้า x
เป็น ไม่ เท่ากับ ย
แล้วระยะเวลาแม้ใน ไร้เดียงสาที่สุด รูทีนความเท่าเทียมกันของสตริงไบต์ (สมมติว่ามันไม่ได้ประกันตัวที่ศูนย์ไบต์แรกหรืออะไรโง่ ๆ แบบนั้น!) จะเป็นอิสระจากค่าของ x
และ ย
: มีความน่าจะเป็น 255/256 ที่มันจะหยุดหลังจากวนซ้ำ 1 ครั้ง ความน่าจะเป็น 65535/65536 หลังจากวนซ้ำ 2 ครั้ง เป็นต้น
แน่นอนว่าสิ่งนี้จะช่วยได้ก็ต่อเมื่อคุณสามารถใช้ HMAC-SHA256 ในเวลาคงที่เท่านั้น! โชคดีที่ SHA-256 ได้รับการออกแบบให้ใช้งานเป็นวงจรลอจิกเวลาคงที่ได้อย่างง่ายดาย ดังนั้นการใช้งาน C มีแนวโน้ม เพื่อให้ทนทานต่อแชนแนลข้างเคียงพอสมควร—แต่พูดได้ว่า Python จะทำให้คุณมีปัญหาเพราะแคชจำนวนเต็มขนาดเล็ก ถ้าไม่มีอะไรอย่างอื่น
* น่าเสียดายที่คำศัพท์ทำให้เกิดความสับสนเล็กน้อย ที่นี่ เวลาคงที่ หมายความว่า ระยะเวลาไม่แตกต่างกันไปขึ้นอยู่กับอินพุตและไม่เหมือนกับ ไม่มีอาการ แนวคิดของ “เวลาคงที่” ในวิทยาการคอมพิวเตอร์ มักเขียนเป็น O(1) ซึ่งหมายถึง ระยะเวลาอาจแตกต่างกันไปขึ้นอยู่กับอินพุต แต่ถูกจำกัดด้วยค่าคงที่. ฉันเสียใจ. ฉันไม่ได้คิดค้นคำศัพท์ ฉันอาจเลือก âfixed-timeâ เทียบกับ âเวลาผันแปรâ แต่มันสายเกินไปแล้วเวลาคงที่ââconstant-timeâ เป็นที่ยึดเหนี่ยวในวรรณคดี