ฉันได้ยุ่งกับการเข้ารหัส (สำหรับการใช้งานสันทนาการ) และฉันสร้างสคริปต์การเข้ารหัสแบบ one-time-pad ของฉันเองใน C ตอนนี้ฉันยอมรับอย่างอิสระว่าฉันไม่ได้เป็นผู้เชี่ยวชาญด้านการเข้ารหัส ฉันรู้ว่ากฎข้อที่ 1 ของการเข้ารหัสคือห้ามทำด้วยตัวเอง อย่างไรก็ตาม ฉันสนใจจริงๆ ว่าสคริปต์การเข้ารหัสของฉันปลอดภัย (ในทางทฤษฎี) หรือไม่
อันดับแรก ต่อไปนี้เป็นข้อมูลสรุปเบื้องต้นเกี่ยวกับสิ่งที่ฉันพยายามทำให้สำเร็จด้วยวิธีการเข้ารหัสของฉัน:
เป้าหมายคือเพื่อให้ได้การเข้ารหัสแบบ One Time Pad ซึ่งใช้ทั้ง (1) ตารางแฮชและ (2) คีย์การเข้ารหัส ตารางแฮช (ในกรณีนี้) ถูกเข้ารหัสไว้ล่วงหน้าโดยมีค่าเป็น 01-98
คีย์การเข้ารหัสคำนวณดังนี้:
- รับอินพุตจากผู้ใช้แบบสุ่ม (อย่างน้อยความยาวเท่ากับข้อความ)
- รับดัชนีที่สอดคล้องกันสำหรับถ่านใน validChars[] (ซอร์สโค้ดด้านล่าง)
- รับตัวเลขใน defaultHashTable ที่สอดคล้องกับดัชนีของ #2
ข้อความถูกเข้ารหัสดังนี้:
- รับข้อความและแปลงเป็นค่า defaultHashTable ที่สอดคล้องกัน
- นำคีย์ที่สร้างไว้ก่อนหน้านี้และเพิ่มลงในข้อความที่แปลงแล้ว
- ตอนนี้มันถูกเข้ารหัสแล้ว (สมมติว่าคีย์เดิมจะไม่ใช้อีก)
ตัวอย่างเช่น:
- ข้อความ: สวัสดี
- แปลงเป็นค่า defaultHashTable ที่สอดคล้องกัน: สวัสดี -> 0805121215
- รับตัวอักษรสุ่มสำหรับคีย์: abkdh
- แปลงเป็นค่า defaultHashTable ที่สอดคล้องกัน: abkdh -> 0102110408
- เพิ่มรหัส: 0805121215 + 0102110408 = 0907231623
- ข้อความเข้ารหัส: 0907231623
นี่คือซอร์สโค้ด (หมายเหตุ: นี่คือการรวมกันของฟังก์ชันที่อยู่ในไฟล์ส่วนหัว C แยกต่างหาก ดังนั้นฉันจึงไม่โพสต์ฟังก์ชัน main ()):
// คีย์ (สำหรับข้อความ) จะมีค่าสูงสุด [50,000][3] (ดังนั้น อาร์เรย์แต่ละตัวจะมีอักขระ 2 ตัว):
โครงสร้าง typedef {
ปุ่มถ่าน[MAX_SIZE][3];
} สำคัญ;
คีย์ globalKey;
// ข้อความที่เข้ารหัสจะถูกส่งกลับในโครงสร้างนี้ (เพราะเป็นวิธีที่ง่ายในการคืนค่าอาร์เรย์สองมิติจากฟังก์ชันใน C):
โครงสร้าง typedef {
char encryptedMessage[MAX_SIZE][3];
} ข้อความเข้ารหัส;
// ตารางแฮชเป็นอาร์เรย์สองมิติที่เข้ารหัสไว้ล่วงหน้า (ซึ่งโหลดใน initDefaultHashTable()) ซึ่งจะใช้ร่วมกับคีย์เพื่อเข้ารหัสข้อความ:
// หมายเหตุ: ยังมีโหมดการเข้ารหัสอื่นที่ฉันไม่ได้รวมไว้ (เพื่อพยายามทำให้กระชับ) ซึ่งคุณต้องพิมพ์ตัวเลขสองหลักแบบสุ่มด้วยตนเอง (97 ในนั้น) สำหรับตารางแฮช
โครงสร้าง typedef {
ถ่าน hashtable [HASHTABLE_CAPACITY][3];
} DefaultHashTable;
DefaultHashTable defaultHashTable; // ประกาศ global defaultHashTable ที่จะเก็บ hashtable นี้
// โหลด defaultHashTable ด้วย 1-98 ตามลำดับ:
เป็นโมฆะ initDefaultHashTable (){
สำหรับ (int i = 0; i < HASHTABLE_CAPACITY; i++){
ถ่าน [3];
sprintf(s, "%d", (i+1));
ถ้า (ฉัน < 10){
ถ่าน tmp = s [0];
s[0] = '0';
s[1] = tmp;
}
สำหรับ (int j = 0; j < 2; j++){
defaultHashTable.hashtable[i][j] = s[j];
}
}
}
// ตัวอักษรที่ถูกต้องที่ข้อความสามารถมีได้ (97 ตัว):
ถ่าน validChars[] = {'a','b','c','d','e','f','g','h','i','j','k', 'l','m','n','o','p','q','r',','t','u','v','w','x ','y','z','A','B','C','D','E','F','G','H','I','J', 'K','L','M','N','O','P','Q','R','S','T','U','V','W ','X','Y','Z','!','@','#','$','%','^','&','*','(', ')','-','+',' ',',','.',':',';','\'','\"','[',']',' {','}','_','=','|','\','/','<','>','?','`','~','\ n','\t','0','1','2','3','4','5','6','7','8','9'};
// สำหรับ char return ล้มเหลว (ฉันรู้สึกว่ามีวิธีที่ดีกว่าในการทำส่วนนี้):
ถ่านล้มเหลว = (ถ่าน)255;
// ค้นหาดัชนีของถ่านที่ถูกต้อง (จาก validChars) หรือ FALSE หากไม่มีอยู่:
int findChar (ถ่าน c) {
สำหรับ (int i = 0; i < strlen(validChars); i++){
ถ้า (validChars[i] == ค){
กลับฉัน;
}
}
กลับ FALSE;
}
// ส่งคืนถ่านจากดัชนี ValidChars ที่กำหนด:
ถ่านกลับถ่าน (ดัชนี int) {
กลับ validChars [ดัชนี];
}
// รับดัชนีของค่าตารางแฮชที่กำหนด (จาก defaultHashTable) จากนั้น ถ้าทำได้ ถ่านที่เกี่ยวข้องใน validChars:
ถ่าน findHashTableValue (ถ่าน n[3], ถ่าน hashtable[][3]){
สำหรับ (int i = 0; i < HASHTABLE_CAPACITY; i++){
ถ้า (hashtable[i][0] == n[0] && hashtable[i][1] == n[1])
ส่งคืน returnChar (i);
}
ส่งคืนล้มเหลว
}
// ส่วนหลักของรหัส (ฟังก์ชัน c หลักจะเรียกสิ่งนี้): เข้ารหัสโดยใช้การเข้ารหัสแผ่นเวลาเดียว แต่ใช้ตารางแฮชเริ่มต้นเพื่อประหยัดเวลา:
เป็นโมฆะ goThroughLightEnryptionProcess (ถ่าน * str, ถ่าน * write_to_file){
// โหลด defaultHashTable:
initDefaultHashTable();
// ใช้ฟังก์ชันเพื่อสร้างคีย์สุ่ม (ขึ้นอยู่กับการป้อนข้อมูลของผู้ใช้แบบสุ่ม):
createRandomKey(strlen(str), MAX_SIZE, FALSE);
// เข้ารหัสข้อความ:
EncryptedMessage encryptMsg = otpEncrypt (defaultHashTable.hashtable, str, globalKey.key);
// วนซ้ำและพิมพ์เนื้อหา (หากไม่ได้เขียนลงไฟล์):
ถ้า (write_to_file == NULL){
สำหรับ (int i = 0; i < strlen(str); i++){
สำหรับ (int j = 0; j < 2; j++){
printf("%c", encryptMsg.encryptedMessage[i][j]);
}
}
printf("\n");
} อื่น {
// เขียนข้อความที่เข้ารหัสไปยังไฟล์:
// หมายเหตุ: นี่เป็นพารามิเตอร์อื่นที่คุณสามารถส่งผ่านในโปรแกรมจริง (ซึ่งใหญ่กว่านี้มาก) ซึ่งคุณสามารถเขียนลงในไฟล์แทนการแสดงในเทอร์มินัล:
// หมายเหตุ: ฉันไม่ได้รวมโค้ดอาร์เรย์ writeFileWithTwoDimensionalArray() นี้ไว้ที่นี่เนื่องจากไม่เกี่ยวข้อง เนื่องจากเป็นเพียงการเขียนไปยังไฟล์
writeFileWithTwoDimensionalArray (encryptMsg.encryptedMessage, HASHTABLE_CAPACITY, write_to_file);
}
}
// (ฟังก์ชันตัวช่วย) โหลดอาร์เรย์อักขระสองตัวลงในคีย์:
ถือเป็นโมฆะ loadIntoKeyForRandoKey (int ที่, ถ่าน n [3]){
สำหรับ (int i = 0; i < 2; i++){
globalKey.key[ที่][i] = n[i];
}
}
// สร้างคีย์ตามการป้อนข้อมูลของผู้ใช้แบบสุ่ม:
เป็นโมฆะ createRandomKey (int password_length, int max_size, บูล use_global){
// @ใช้ globalHashTable | DefaultHashTable
// @ใช้ globalKey
ถ่านตอบสนอง [max_size];
printf("ป้อนอักขระแบบสุ่มสำหรับคีย์ (a-z,A-Z,!@#$%%^&*()-+=, ความยาวขั้นต่ำของ %d): ", password_length);
fgets (ตอบสนอง, max_size, stdin);
// ลบอักขระ '\n' ที่ส่วนท้าย:
ถ่าน * p;
ถ้า ((p = strchr(การตอบสนอง '\n')) != NULL){
*p = '\0';
} อื่น {
scanf("%*[^\n]");
scanf("%*ค");
}
// ตรวจสอบให้แน่ใจว่าผู้ใช้ป้อนเป็น >= password_length:
ถ้า (strlen (ตอบกลับ) < password_length){
printf("\n[ ข้อผิดพลาด ] : อักขระสุ่มต้องมากกว่าหรือเท่ากับ %d.\n", password_length);
ส่งคืน createRandomKey (password_length, max_size, use_global);
}
// แปลงตัวอักษรสุ่มให้มีค่าเท่ากันใน hashtable ตามลำดับ:
สำหรับ (int i = 0; i < password_length; i++){
int getCharIndex = findChar (ตอบกลับ [i]);
// ตรวจสอบให้แน่ใจว่าพบเรียบร้อยแล้ว:
ถ้า (getCharIndex == FALSE){
printf("\n[ ข้อผิดพลาด ] ตัวอักษร '%c' ไม่ถูกต้อง ลองอีกครั้ง\n", ตอบกลับ[i]);
ส่งคืน createRandomKey (password_length, max_size, use_global); // ทำมันอีกครั้ง
}
// โหลดค่า hashtable ที่สอดคล้องกันลงในคีย์:
ถ้า (use_global == จริง){
loadIntoKeyForRandoKey (i, globalHashTable.hashtable[getCharIndex]);
} อื่น {
loadIntoKeyForRandoKey (i, defaultHashTable.hashtable[getCharIndex]);
}
}
// เขียนคีย์สุ่มไปยังไฟล์:
createFileWithTwoDimensionalArray (globalKey.key, password_length, "คีย์");
}
// (ฟังก์ชันตัวช่วย) สำหรับการโหลดลงในโครงสร้าง EncryptedMessage:
ถือเป็นโมฆะ loadIntoEncryptedMessage (int at, char n[3], EncryptedMessage *encryptedMsg){
ถ้า (strlen(n) == 1){
// ต่อท้าย '0':
ถ่าน tmp = n[0];
n[0] = '0';
n[1] = tmp;
}
สำหรับ (int i = 0; i < 2; i++){
encryptedMsg->encryptedMessage[ที่][i] = n[i];
}
}
/*
เข้ารหัสข้อความที่กำหนดแฮชเทเบิลและคีย์ที่ถูกต้อง
*/
EncryptedMessage otpEncrypt(char hashtable[][3], char * msg, char key[MAX_SIZE][3]){
EncryptedMessage encryptedMsg;
สำหรับ (int i = 0; i < strlen(msg); i++){
// แปลงค่าคีย์เป็นจำนวนเต็ม:
int ConvertKeyValueIntoInt = safeConvertToInt(คีย์[i]);
// ตรวจสอบให้แน่ใจว่าแปลงอย่างถูกต้อง:
ถ้า (แปลง KeyValueIntoInt == FALSE){
printf("[ ERROR ] : คีย์เสียหายที่ %d (ค่า = %s)\n", i, คีย์[i]);
ทางออก (1);
}
// แปลงข้อความของผู้ใช้ให้เทียบเท่าใน hashtable:
int indexOfMsgChar = findChar(msg[i]);
// ตรวจสอบให้แน่ใจว่า findChar() พบค่าอย่างถูกต้อง:
ถ้า (indexOfMsgChar == FALSE){
printf("[ ERROR ] : รหัสผ่าน (msg) เสียหายที่ %d (ค่า = %s) สิ่งนี้อาจเกิดขึ้นเนื่องจากไม่อนุญาตให้ใช้อักขระ '%c'\n", i, msg, msg[i ]);
ทางออก (1);
}
ถ่าน * ที่สอดคล้องกันEncryptMsgChars = hashtable [indexOfMsgChar];
// แปลงตัวอักษร encryptMsg ที่สอดคล้องกันเป็น int:
int ConvertEncryptMsgCharsIntoInt = safeConvertToInt (ที่สอดคล้องกันEncryptMsgChars);
// ตรวจสอบให้แน่ใจว่าแปลงอย่างถูกต้อง:
ถ้า (แปลงEncryptMsgCharsIntoInt == FALSE){
printf("[ ข้อผิดพลาด ] : ตารางแฮชเสียหายที่ %d (ค่า = %s)\n", indexOfMsgChar, สอดคล้องEncryptMsgChars);
ทางออก (1);
}
// ทำการคำนวณ:
int encryptedFrag = otpeAdd (แปลง EncryptMsgCharsIntoInt, ConvertKeyValueIntoInt);
// แปลงเป็นสตริง:
ถ่านเข้ารหัส FragStr [3];
sprintf(encryptedFragStr, "%d", encryptedFrag);
loadIntoEncryptedMessage(i, encryptedFragStr, &encryptedMsg);
}
ส่งคืน encryptedMsg;
}
คำถามทันทีของฉันคือ: ถ้าฉันใช้ตารางแฮชที่เข้ารหัสไว้ล่วงหน้า (ที่ใครๆ ก็อนุมานได้) นั่นทำให้การเข้ารหัสไม่ปลอดภัย (แม้ว่าคีย์ที่สอดคล้องกับค่าตารางแฮชจะสุ่มโดยสมบูรณ์ผ่านการป้อนข้อมูลของผู้ใช้) จะปลอดภัยก็ต่อเมื่อฉันสุ่มหมายเลขตารางแฮช (01-98) (และอาจสุ่มค่า validChars[])
ฉันสนใจจริง ๆ ว่าตรรกะของฉันมีเหตุผลหรือไม่ ดังนั้นความคิดเห็น ข้อเสนอแนะ หรือคำวิจารณ์ใด ๆ จะได้รับการชื่นชมอย่างมาก