เทคนิคในการปิดบังสตริงที่ละเอียดอ่อนใน C ++


88

ฉันต้องการจัดเก็บข้อมูลที่ละเอียดอ่อน (คีย์เข้ารหัสแบบสมมาตรที่ฉันต้องการเก็บไว้เป็นส่วนตัว) ในแอปพลิเคชัน C ++ ของฉัน วิธีง่ายๆคือทำสิ่งนี้:

std::string myKey = "mysupersupersecretpasswordthatyouwillneverguess";

อย่างไรก็ตามการเรียกใช้แอปพลิเคชันผ่านstringsกระบวนการ (หรืออื่น ๆ ที่แยกสตริงจากแอปไบนารี) จะเปิดเผยสตริงด้านบน

ควรใช้เทคนิคใดในการปิดบังข้อมูลที่ละเอียดอ่อนดังกล่าว

แก้ไข:

โอเคคุณทุกคนบอกว่า"ไฟล์ปฏิบัติการของคุณสามารถย้อนกลับทางวิศวกรรมได้"แน่นอน! นี่เป็นสัตว์เลี้ยงของฉันดังนั้นฉันจะคุยโวสักหน่อยที่นี่:

เหตุใด 99% (โอเคดังนั้นบางทีฉันพูดเกินจริงเล็กน้อย) ของคำถามเกี่ยวกับความปลอดภัยทั้งหมดในไซต์นี้ได้รับคำตอบพร้อมกับฝนตกหนักว่า "ไม่มีวิธีที่เป็นไปได้ในการสร้างโปรแกรมที่ปลอดภัยอย่างสมบูรณ์แบบ" ซึ่งไม่เป็นประโยชน์ ตอบ! ความปลอดภัยเป็นระดับเลื่อนระหว่างการใช้งานที่สมบูรณ์แบบและไม่มีการรักษาความปลอดภัยที่ปลายด้านหนึ่งและความปลอดภัยที่สมบูรณ์แบบ แต่ไม่มีการใช้งานที่อื่น

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

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

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


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

3
สำเนาที่แน่นอน: stackoverflow.com/questions/926172/…
Kirill V. Lyadvinsky

4
@Kirill: ยากที่จะเรียกคำถามนี้ว่าตรงกับคำถามที่คุณพูดถึง แท้จริงความคิดเหมือนกัน คำถามคือไม่
xtofl

1
@xtofl คุณมีอิสระที่จะไม่ลงคะแนน สำหรับฉันดูเหมือนคำถามที่เหมือนกันสองคำถาม
Kirill V. Lyadvinsky

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

คำตอบ:


42

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

แต่ถ้าคุณต้องการให้แน่ใจว่าคีย์ไม่ปรากฏขึ้นเมื่อทำงานstringsบนไบนารีของคุณตัวอย่างเช่นคุณสามารถตรวจสอบให้แน่ใจว่าคีย์นั้นไม่อยู่ในช่วงที่พิมพ์ได้

คีย์ปิดบังด้วย XOR

ตัวอย่างเช่นคุณสามารถใช้ XOR เพื่อแบ่งคีย์ออกเป็นสองไบต์อาร์เรย์:

key = key1 XOR key2

หากคุณสร้าง key1 ที่มีความยาวไบต์เท่ากันกับที่keyคุณสามารถใช้ค่าไบต์แบบสุ่ม (ทั้งหมด) จากนั้นคำนวณkey2:

key1[n] = crypto_grade_random_number(0..255)
key2[n] = key[n] XOR key1[n]

คุณสามารถทำได้ในสภาพแวดล้อมการสร้างของคุณจากนั้นจัดเก็บkey1และkey2ในแอปพลิเคชันของคุณเท่านั้น

ปกป้องไบนารีของคุณ

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

หนึ่งในเครื่องมือชั้นนำคือThemidaซึ่งทำหน้าที่ปกป้องไบนารีของคุณได้อย่างยอดเยี่ยม มักใช้โดยโปรแกรมที่รู้จักกันดีเช่น Spotify เพื่อป้องกันการทำวิศวกรรมย้อนกลับ มีคุณสมบัติในการป้องกันการดีบักในโปรแกรมเช่น OllyDbg และ Ida Pro

นอกจากนี้ยังมีรายการที่มีขนาดใหญ่อาจจะค่อนข้างล้าสมัยของเครื่องมือในการปกป้องไบนารีของคุณ
บางส่วนของพวกเขาฟรี

การจับคู่รหัสผ่าน

มีคนพูดถึงการแฮชรหัสผ่าน + เกลือ

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

สุดท้ายคุณสามารถใช้เทคนิคทั้งหมดข้างต้นร่วมกันได้


หากเป็นรหัสผ่านที่ผู้ใช้ต้องป้อนให้เก็บแฮช + เกลือของรหัสผ่าน ดูคำตอบด้านล่าง

1
@hapalibashi: คุณเก็บเกลืออย่างปลอดภัยในใบสมัครได้อย่างไร? ฉันไม่คิดว่า OP ต้องการระบบการจับคู่รหัสผ่านทางเดียวเพียงแค่วิธีการจัดเก็บคีย์แบบคงที่โดยทั่วไป
csl

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

2
@kb - นั่นเป็นจุดที่น่าสนใจ ฉันเดาว่าคุณจะเห็นบิตและและหรือเกิดขึ้นมากกว่า xor มาก ก ^ b == (a & ~ b) || (~ a & b)
Jeremy Powell

4
การรู้ค่าเกลือมักจะไม่ทำให้ฝ่ายตรงข้ามได้เปรียบ - ประเด็นของเกลือคือการหลีกเลี่ยง "การโจมตีด้วยพจนานุกรม" โดยที่ผู้โจมตีได้คำนวณแฮชไว้ล่วงหน้าสำหรับอินพุตที่เป็นไปได้หลายอย่าง การใช้เกลือบังคับให้พวกเขาคำนวณพจนานุกรมล่วงหน้าด้วยคำศัพท์ใหม่โดยอิงจากเกลือ หากเกลือแต่ละชนิดถูกใช้เพียงครั้งเดียวการโจมตีด้วยพจนานุกรมก็ไร้ประโยชน์โดยสิ้นเชิง
Edward Dixon

8

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

มี 4 สิ่งที่คุณสามารถทำได้ที่จะเพิ่มโอกาสในการซ่อนตัวสักพัก

1) ซ่อนองค์ประกอบของสตริงไม่ทางใดก็ทางหนึ่ง - สิ่งที่ชัดเจนเช่น xoring (ตัวดำเนินการ ^) สตริงที่มีสตริงอื่นจะดีพอที่จะทำให้ไม่สามารถค้นหาสตริงได้

2) แยกสตริงออกเป็นชิ้น ๆ - แยกสตริงของคุณและป๊อปบิตของมันออกเป็นวิธีการที่มีชื่อแปลก ๆ ในโมดูลแปลก ๆ อย่าทำให้ง่ายต่อการค้นหาและค้นหาวิธีการที่มีสตริงอยู่ในนั้น แน่นอนว่าบางวิธีจะต้องเรียกบิตเหล่านี้ทั้งหมด แต่ก็ยังทำให้ยากขึ้นเล็กน้อย

3) อย่าสร้างสตริงในหน่วยความจำ - แฮกเกอร์ส่วนใหญ่ใช้เครื่องมือที่ให้พวกเขาเห็นสตริงในหน่วยความจำหลังจากที่คุณเข้ารหัสแล้ว ถ้าเป็นไปได้หลีกเลี่ยงสิ่งนี้ ตัวอย่างเช่นหากคุณกำลังส่งคีย์ออกไปยังเซิร์ฟเวอร์ให้ส่งทีละอักขระดังนั้นสตริงทั้งหมดจะไม่อยู่รอบ ๆ แน่นอนว่าถ้าคุณใช้มันจากการเข้ารหัส RSA สิ่งนี้จะยุ่งยากกว่า

4) ทำอัลกอริทึมเฉพาะกิจ - เหนือสิ่งอื่นใดให้เพิ่มการบิดที่ไม่ซ้ำกันหรือสองอย่าง อาจเพิ่ม 1 ในทุกสิ่งที่คุณผลิตหรือทำการเข้ารหัสสองครั้งหรือเพิ่มน้ำตาล สิ่งนี้ทำให้ยากขึ้นเล็กน้อยสำหรับแฮ็กเกอร์ที่รู้อยู่แล้วว่าต้องค้นหาอะไรเมื่อมีคนใช้เช่นการแฮช vanilla md5 หรือการเข้ารหัส RSA

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


5

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

ตัวอย่าง:

กำหนดอาร์เรย์ของอักขระ (ตัวเลขและขีดกลางใช้สำหรับการอ้างอิงเท่านั้น)

0123456789
----------
ALFHNFELKD
LKFKFLEHGT
FLKRKLFRFK
FJFJJFJ!JL

และสมการที่มีผลลัพธ์หกรายการแรก: 3, 6, 7, 10, 21, 47

ย่อมเกิดคำว่า "HELLO!" จากอาร์เรย์ด้านบน


ความคิดที่ดี - ฉันคิดว่าคุณสามารถปรับปรุงเพิ่มเติมได้โดยใช้อักขระที่ไม่พิมพ์ในอาร์เรย์ ...
Thomi

4

ฉันเห็นด้วยกับ @Checkers ไฟล์ปฏิบัติการของคุณสามารถออกแบบย้อนกลับได้

วิธีที่ดีกว่าเล็กน้อยคือการสร้างแบบไดนามิกเช่น:

std::string myKey = part1() + part2() + ... + partN();

จริงอยู่ที่หลีกเลี่ยงการเปิดเผยสตริงเมื่อค้นหาไบนารี อย่างไรก็ตามสตริงของคุณยังคงอยู่ในหน่วยความจำ .. ทางออกของคุณน่าจะดีพอสำหรับสิ่งที่ฉันกำลังทำอยู่
Thomi

@ คุณโทมิแน่นอนคุณสามารถทำลายมันได้ทันทีที่คุณทำกับมัน แต่ถึงกระนั้นก็ไม่ใช่วิธีที่ดีที่สุดในการจัดการกับสตริงที่ละเอียดอ่อน
Nick Dandoulakis

... เนื่องจากการทำลายมันไม่ได้รับประกันว่าหน่วยความจำจะถูกนำกลับมาใช้ทันที
Thomi

4

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

ดังที่กล่าวมาคุณมักจะสามารถทำให้สิ่งต่างๆปลอดภัยเพียงพอโดยการเพิ่มอุปสรรคที่ผู้คนต้องเอาชนะเพื่อเปิดเผยข้อมูลส่วนตัวของคุณ นั่นมักจะเป็นการประนีประนอมที่ดี

ในกรณีของคุณคุณสามารถทำให้สตริงของคุณยุ่งเหยิงด้วยข้อมูลที่ไม่สามารถพิมพ์ได้จากนั้นถอดรหัสที่รันไทม์โดยใช้ฟังก์ชันตัวช่วยง่ายๆดังนี้:

void unscramble( char *s )
{
    for ( char *str = s + 1; *str != 0; str += 2 ) {
        *s++ = *str;
    }
    *s = '\0';
}

void f()
{
    char privateStr[] = "\001H\002e\003l\004l\005o";
    unscramble( privateStr ); // privateStr is 'Hello' now.

    string s = privateStr;
    // ...
}

4

ฉันได้สร้างเครื่องมือเข้ารหัสอย่างง่ายสำหรับสตริงมันสามารถสร้างสตริงที่เข้ารหัสโดยอัตโนมัติและมีตัวเลือกพิเศษบางอย่างในการทำเช่นนั้นตัวอย่างบางส่วน:

สตริงเป็นตัวแปรส่วนกลาง:

// myKey = "mysupersupersecretpasswordthatyouwillneverguess";
unsigned char myKey[48] = { 0xCF, 0x34, 0xF8, 0x5F, 0x5C, 0x3D, 0x22, 0x13, 0xB4, 0xF3, 0x63, 0x7E, 0x6B, 0x34, 0x01, 0xB7, 0xDB, 0x89, 0x9A, 0xB5, 0x1B, 0x22, 0xD4, 0x29, 0xE6, 0x7C, 0x43, 0x0B, 0x27, 0x00, 0x91, 0x5F, 0x14, 0x39, 0xED, 0x74, 0x7D, 0x4B, 0x22, 0x04, 0x48, 0x49, 0xF1, 0x88, 0xBE, 0x29, 0x1F, 0x27 };

myKey[30] -= 0x18;
myKey[39] -= 0x8E;
myKey[3] += 0x16;
myKey[1] += 0x45;
myKey[0] ^= 0xA2;
myKey[24] += 0x8C;
myKey[44] ^= 0xDB;
myKey[15] ^= 0xC5;
myKey[7] += 0x60;
myKey[27] ^= 0x63;
myKey[37] += 0x23;
myKey[2] ^= 0x8B;
myKey[25] ^= 0x18;
myKey[12] ^= 0x18;
myKey[14] ^= 0x62;
myKey[11] ^= 0x0C;
myKey[13] += 0x31;
myKey[6] -= 0xB0;
myKey[22] ^= 0xA3;
myKey[43] += 0xED;
myKey[29] -= 0x8C;
myKey[38] ^= 0x47;
myKey[19] -= 0x54;
myKey[33] -= 0xC2;
myKey[40] += 0x1D;
myKey[20] -= 0xA8;
myKey[34] ^= 0x84;
myKey[8] += 0xC1;
myKey[28] -= 0xC6;
myKey[18] -= 0x2A;
myKey[17] -= 0x15;
myKey[4] ^= 0x2C;
myKey[9] -= 0x83;
myKey[26] += 0x31;
myKey[10] ^= 0x06;
myKey[16] += 0x8A;
myKey[42] += 0x76;
myKey[5] ^= 0x58;
myKey[23] ^= 0x46;
myKey[32] += 0x61;
myKey[41] ^= 0x3B;
myKey[31] ^= 0x30;
myKey[46] ^= 0x6C;
myKey[35] -= 0x08;
myKey[36] ^= 0x11;
myKey[45] -= 0xB6;
myKey[21] += 0x51;
myKey[47] += 0xD9;

เป็นสตริง Unicode ที่มีลูปถอดรหัส:

// myKey = "mysupersupersecretpasswordthatyouwillneverguess";
wchar_t myKey[48];

myKey[21] = 0x00A6;
myKey[10] = 0x00B0;
myKey[29] = 0x00A1;
myKey[22] = 0x00A2;
myKey[19] = 0x00B4;
myKey[33] = 0x00A2;
myKey[0] = 0x00B8;
myKey[32] = 0x00A0;
myKey[16] = 0x00B0;
myKey[40] = 0x00B0;
myKey[4] = 0x00A5;
myKey[26] = 0x00A1;
myKey[18] = 0x00A5;
myKey[17] = 0x00A1;
myKey[8] = 0x00A0;
myKey[36] = 0x00B9;
myKey[34] = 0x00BC;
myKey[44] = 0x00B0;
myKey[30] = 0x00AC;
myKey[23] = 0x00BA;
myKey[35] = 0x00B9;
myKey[25] = 0x00B1;
myKey[6] = 0x00A7;
myKey[27] = 0x00BD;
myKey[45] = 0x00A6;
myKey[3] = 0x00A0;
myKey[28] = 0x00B4;
myKey[14] = 0x00B6;
myKey[7] = 0x00A6;
myKey[11] = 0x00A7;
myKey[13] = 0x00B0;
myKey[39] = 0x00A3;
myKey[9] = 0x00A5;
myKey[2] = 0x00A6;
myKey[24] = 0x00A7;
myKey[46] = 0x00A6;
myKey[43] = 0x00A0;
myKey[37] = 0x00BB;
myKey[41] = 0x00A7;
myKey[15] = 0x00A7;
myKey[31] = 0x00BA;
myKey[1] = 0x00AC;
myKey[47] = 0x00D5;
myKey[20] = 0x00A6;
myKey[5] = 0x00B0;
myKey[38] = 0x00B0;
myKey[42] = 0x00B2;
myKey[12] = 0x00A6;

for (unsigned int fngdouk = 0; fngdouk < 48; fngdouk++) myKey[fngdouk] ^= 0x00D5;

สตริงเป็นตัวแปรส่วนกลาง:

// myKey = "mysupersupersecretpasswordthatyouwillneverguess";
unsigned char myKey[48] = { 0xAF, 0xBB, 0xB5, 0xB7, 0xB2, 0xA7, 0xB4, 0xB5, 0xB7, 0xB2, 0xA7, 0xB4, 0xB5, 0xA7, 0xA5, 0xB4, 0xA7, 0xB6, 0xB2, 0xA3, 0xB5, 0xB5, 0xB9, 0xB1, 0xB4, 0xA6, 0xB6, 0xAA, 0xA3, 0xB6, 0xBB, 0xB1, 0xB7, 0xB9, 0xAB, 0xAE, 0xAE, 0xB0, 0xA7, 0xB8, 0xA7, 0xB4, 0xA9, 0xB7, 0xA7, 0xB5, 0xB5, 0x42 };

for (unsigned int dzxykdo = 0; dzxykdo < 48; dzxykdo++) myKey[dzxykdo] -= 0x42;

1
ไม่ฉันใช้เว็บไซต์stringencrypt.comในการทำงาน มีตัวอย่างสำหรับ C / C ++ stringencrypt.com/c-cpp-encryptionคุณอาจพิจารณาใช้เพื่อเข้ารหัสสตริงแบบธรรมดาโดยอัตโนมัติ
Bartosz Wójcik

2

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

แก้ไข: หากคุณกำลังจะทำการผสมผสานของเทคนิคที่ Chris ชี้ให้เห็นจะดีกว่า rot13


2

ดังที่ได้กล่าวไว้ก่อนหน้านี้ไม่มีวิธีใดที่จะปกป้องสายอักขระของคุณได้ทั้งหมด แต่มีวิธีการป้องกันอย่างปลอดภัยตามสมควร

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

แน่นอนว่าอาจถูกแฮ็กได้ แต่ต้องใช้แฮ็กเกอร์ที่ตั้งใจในการทำเช่นนั้น


ความคิดที่ดี - ความคลุมเครืออีกรูปแบบหนึ่งคือการใช้สตริงที่ยังคงแข็งแรงพอสมควร (ยาววรรคตอนและแจ๊สทั้งหมด) แต่ดูไม่เหมือนรหัสผ่านอย่างชัดเจน
Thomi

1

หากคุณใช้ DPAPI ของผู้ใช้ windows http://msdn.microsoft.com/en-us/library/ms995355.aspx

ตามที่โพสต์ก่อนหน้านี้บอกว่าถ้าคุณใช้ mac ให้ใช้พวงกุญแจ

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

นี่เป็นปัญหาที่แก้ไขได้และคำตอบคืออย่าเก็บกุญแจไว้ในโปรแกรมของคุณ :)


1

ลองนี้ ซอร์สโค้ดอธิบายวิธีการเข้ารหัสและถอดรหัสในทันทีสตริงทั้งหมดในโครงการ Visual Studio c ++ ที่กำหนด


1

วิธีหนึ่งที่ฉันเพิ่งลองใช้คือ:

  1. ใช้แฮช (SHA256) ของข้อมูลส่วนตัวและเติมในรหัสเป็น part1
  2. ใช้ XOR ของข้อมูลส่วนตัวและแฮชของมันแล้วใส่รหัสเป็น part2
  3. เติมข้อมูล: อย่าจัดเก็บเป็น char str [] แต่เติมข้อมูลบนรันไทม์โดยใช้คำสั่งการกำหนด (ดังแสดงในมาโครด้านล่าง)
  4. ตอนนี้สร้างข้อมูลส่วนตัวตามเวลาทำงานโดยใช้ XOR ของpart1และpart2
  5. ขั้นตอนเพิ่มเติม : part1กัญชาคำนวณของข้อมูลที่สร้างขึ้นและเปรียบเทียบกับ จะตรวจสอบความสมบูรณ์ของข้อมูลส่วนตัว

MACRO เพื่อเติมข้อมูล:

สมมติว่าข้อมูลส่วนตัวมีขนาด 4 ไบต์ เรากำหนดมาโครสำหรับมันซึ่งจะบันทึกข้อมูลด้วยคำสั่งการมอบหมายในลำดับสุ่ม

#define POPULATE_DATA(str, i0, i1, i2, i3)\
{\
    char *p = str;\
    p[3] = i3;\
    p[2] = i2;\
    p[0] = i0;\
    p[1] = i1;\
}

ตอนนี้ใช้มาโครนี้ในโค้ดที่คุณต้องบันทึกpart1และpart2ดังนี้:

char part1[4] = {0};
char part2[4] = {0};
POPULATE_DATA(part1, 1, 2, 3, 4); 
POPULATE_DATA(part2, 5, 6, 7, 8);

1

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

โค้ดต่อไปนี้จะไม่เก็บสตริง "hello world" ไว้ในไบนารีที่คอมไพล์แล้ว

#include "obfuscate.h"

int main()
{
  std::cout << AY_OBFUSCATE("Hello World") << std::endl;
  return 0;
}

ฉันได้ทดสอบกับ c ++ 17 และ visual studio 2019 แล้วและตรวจสอบผ่าน IDA และฉันยืนยันว่าสตริงถูกซ่อนอยู่ ข้อได้เปรียบที่มีค่าอย่างหนึ่งเมื่อเทียบกับADVobfuscatorคือสามารถแปลงเป็นสตริง std :: (ในขณะที่ยังซ่อนอยู่ในไบนารีที่คอมไพล์แล้ว):

std::string var = AY_OBFUSCATE("string");

0

แทนที่จะเก็บคีย์ส่วนตัวไว้ในไฟล์ปฏิบัติการของคุณคุณอาจต้องการขอจากผู้ใช้และจัดเก็บโดยใช้เครื่องมือจัดการรหัสผ่านภายนอกซึ่งคล้ายกับ MacOS X Keychain Access


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

หากรู้สึกไม่ปลอดภัย (แม้ว่าจะได้รับคำชี้แจงของคุณอาจจะเพียงพอ) คุณสามารถรวมพวงกุญแจและรหัส

0

ขึ้นอยู่กับบริบท แต่คุณสามารถจัดเก็บแฮชของคีย์บวกกับเกลือได้

จากนั้นเมื่อ (ถ้า) ผู้ใช้ป้อนคีย์ให้คุณใส่เกลือคำนวณแฮชและเปรียบเทียบ

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

แฮ็กเกอร์ยังคงต้องแทรกคำสั่ง jmp ไว้ที่ใดที่หนึ่งเพื่อหลีกเลี่ยงจำนวนมากทั้งหมด แต่มันค่อนข้างซับซ้อนกว่าการค้นหาข้อความธรรมดา


นี่คือคีย์เข้ารหัสไม่ใช่แฮชรหัสผ่าน ฉันต้องการคีย์จริงในการเข้ารหัสและถอดรหัสข้อมูล ผู้ใช้ไม่เคยเห็นคีย์ไม่เคยเก็บไว้นอกไบนารี
Thomi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.