นี่คือหน้าแรกที่ปรากฏขึ้นผ่าน Google และช่องโหว่ด้านความปลอดภัยในการใช้งานทั้งหมดทำให้ฉันประจบประแจงดังนั้นฉันจึงโพสต์สิ่งนี้เพื่อเพิ่มข้อมูลเกี่ยวกับการเข้ารหัสสำหรับผู้อื่นเนื่องจาก7 ปีนับจากโพสต์ต้นฉบับ ฉันสำเร็จการศึกษาระดับปริญญาโทด้านวิศวกรรมคอมพิวเตอร์และใช้เวลาศึกษาและเรียนรู้การเข้ารหัสมากมายดังนั้นฉันจึงโยนสองเซ็นต์ของฉันเพื่อทำให้อินเทอร์เน็ตปลอดภัยยิ่งขึ้น
นอกจากนี้โปรดทราบว่าการนำไปใช้จำนวนมากอาจปลอดภัยสำหรับสถานการณ์ที่กำหนด แต่เหตุใดจึงใช้สิ่งเหล่านั้นและอาจทำให้เกิดข้อผิดพลาดโดยไม่ตั้งใจ ใช้เครื่องมือที่แข็งแกร่งที่สุดที่คุณมีอยู่ยกเว้นว่าคุณมีเหตุผลเฉพาะที่ไม่ควรทำ โดยรวมแล้วฉันแนะนำให้ใช้ห้องสมุดและอยู่ห่างจากรายละเอียดเล็ก ๆ น้อย ๆ ถ้าคุณทำได้
อัปเดต 4/5/18:ฉันเขียนใหม่บางส่วนเพื่อให้ง่ายต่อการเข้าใจและเปลี่ยนไลบรารี่ที่แนะนำจากJasyptไปเป็น Tink ไลบรารี่ใหม่ของ Googleฉันขอแนะนำให้ลบJasyptออกจากการตั้งค่าที่มีอยู่ทั้งหมด
คำนำ
ฉันจะร่างพื้นฐานของการเข้ารหัสแบบสมมาตรที่ปลอดภัยด้านล่างและชี้ให้เห็นข้อผิดพลาดทั่วไปที่ฉันเห็นทางออนไลน์เมื่อผู้คนติดตั้ง crypto ด้วยตนเองด้วยไลบรารี Java มาตรฐาน หากคุณต้องการข้ามรายละเอียดทั้งหมดไปที่ห้องสมุดใหม่ของ Google Tinkนำเข้าสู่โครงการของคุณและใช้โหมด AES-GCM สำหรับการเข้ารหัสทั้งหมดของคุณและคุณจะปลอดภัย
ตอนนี้ถ้าคุณต้องการเรียนรู้รายละเอียด nitty gritty เกี่ยวกับวิธีการเข้ารหัสใน java อ่าน :)
บล็อกยันต์
สิ่งแรกอันดับแรกคุณต้องเลือก Block Cipher key symmetric Block Cipher เป็นฟังก์ชัน / โปรแกรมคอมพิวเตอร์ที่ใช้สร้าง Pseudo-Randomness Pseudo-Randomness เป็นการสุ่มแบบปลอมที่ไม่มีคอมพิวเตอร์เครื่องอื่นนอกเหนือจาก Quantum Computer จะสามารถบอกความแตกต่างระหว่างมันและการสุ่มที่แท้จริงได้ Block Cipher นั้นเหมือนกับ Building Block ถึงการเข้ารหัสและเมื่อใช้กับโหมดหรือแบบแผนต่าง ๆ เราสามารถสร้างการเข้ารหัสได้
ตอนนี้เกี่ยวกับบล็อก Cipher อัลกอริทึมที่มีอยู่ในวันนี้ให้แน่ใจว่าจะไม่ฉันทำซ้ำไม่เคยใช้DESผมแม้จะพูดไม่เคยใช้3DES เพียงตัวเลขบล็อกว่าแม้ Snowden ปล่อยเอ็นเอสเอก็สามารถที่จะตรวจสอบความเป็นจริงใกล้เคียงกับการสุ่มหลอกที่เป็นไปได้คือการเข้ารหัส AES 256 นอกจากนี้ยังมี AES 128; ความแตกต่างคือ AES 256 ทำงานในบล็อก 256 บิตในขณะที่ AES 128 ทำงานใน 128 บล็อก สรุปแล้ว AES 128 นั้นถือว่าปลอดภัยแม้ว่าจะมีการค้นพบจุดอ่อน แต่ 256 นั้นแข็งแกร่งพอ ๆ กับที่ได้รับ
ความจริงเรื่องความสนุกDESถูกทำลายโดย NSA เมื่อมันถูกก่อตั้งขึ้นในตอนแรกและจริง ๆ แล้วเก็บเป็นความลับไม่กี่ปี ถึงแม้ว่าบางคนยังคงเรียกร้อง3DESมีความปลอดภัยมีค่อนข้างไม่กี่เอกสารงานวิจัยที่ได้พบและวิเคราะห์จุดอ่อนใน3DES
โหมดการเข้ารหัส
การเข้ารหัสจะถูกสร้างขึ้นเมื่อคุณใช้บล็อกตัวเลขและใช้รูปแบบที่เฉพาะเจาะจงเพื่อให้การรวมแบบสุ่มกับคีย์ในการสร้างสิ่งที่สามารถย้อนกลับได้ตราบใดที่คุณรู้ว่ากุญแจ สิ่งนี้เรียกว่าโหมดการเข้ารหัส
นี่คือตัวอย่างของโหมดการเข้ารหัสและโหมดที่ง่ายที่สุดที่รู้จักกันในนาม ECB เพื่อให้คุณสามารถเข้าใจด้วยตาว่าเกิดอะไรขึ้น:
โหมดการเข้ารหัสที่คุณจะเห็นได้ทั่วไปทางออนไลน์ ได้แก่
ECB CTR, CBC, GCM
มีโหมดอื่น ๆ นอกเหนือจากที่อยู่ในรายการและนักวิจัยมักจะทำงานในโหมดใหม่เพื่อปรับปรุงปัญหาที่มีอยู่
ทีนี้เรามาดูการใช้งานและสิ่งที่ปลอดภัย ไม่เคยใช้ ECB นี้ไม่ดีที่หลบซ่อนตัวอยู่ซ้ำข้อมูลที่แสดงโดยที่มีชื่อเสียงเพนกวินลินุกซ์
เมื่อใช้งานใน Java โปรดทราบว่าหากคุณใช้รหัสต่อไปนี้โหมด ECB จะถูกตั้งค่าตามค่าเริ่มต้น:
Cipher cipher = Cipher.getInstance("AES");
... อันตรายนี่คือความเลวทราม! และน่าเสียดายที่สิ่งนี้มีอยู่ทั่ว StackOverflow และออนไลน์ในบทแนะนำและตัวอย่าง
Nonces และ IV
ในการตอบสนองต่อปัญหาที่พบในคำนามโหมด ECB หรือที่เรียกว่า IV ถูกสร้างขึ้น แนวคิดคือเราสร้างตัวแปรสุ่มใหม่และแนบกับการเข้ารหัสทุกครั้งดังนั้นเมื่อคุณเข้ารหัสข้อความสองข้อความที่เหมือนกันพวกเขาจะแตกต่างกันออกไป ความงามที่อยู่เบื้องหลังนี้คือ IV หรือ nonce เป็นความรู้สาธารณะ นั่นหมายความว่าผู้โจมตีสามารถเข้าถึงสิ่งนี้ได้ แต่ตราบใดที่พวกเขาไม่มีกุญแจของคุณพวกเขาไม่สามารถทำอะไรกับความรู้นั้นได้
ปัญหาทั่วไปที่ฉันจะเห็นคือผู้คนจะตั้งค่า IV เป็นค่าคงที่เช่นเดียวกับในค่าคงที่เดียวกันในรหัสของพวกเขา และนี่คือข้อผิดพลาดที่เกิดขึ้นกับ IV เมื่อคุณพูดย้ำอีกครั้งว่าคุณได้ทำลายความปลอดภัยทั้งหมดของการเข้ารหัสของคุณ
การสร้างแบบสุ่ม IV
SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
byte[] iv = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
หมายเหตุ: SHA1 นั้นใช้งานไม่ได้ แต่ฉันไม่สามารถหาวิธีนำ SHA256 ไปใช้ในกรณีการใช้งานได้อย่างถูกต้องดังนั้นหากใครต้องการที่จะถอดรหัสและอัพเดตมันจะยอดเยี่ยมมาก! การโจมตีของ SHA1 นั้นยังคงไม่เป็นไปตามปกติเนื่องจากอาจใช้เวลาสองสามปีในการโจมตีแบบกลุ่มใหญ่ ตรวจสอบรายละเอียดที่นี่
การใช้ CTR
ไม่จำเป็นต้องใช้ช่องว่างภายในสำหรับโหมด CTR
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
การนำ CBC ไปใช้
หากคุณเลือกที่จะใช้โหมด CBC ทำได้ด้วย PKCS7Padding ดังนี้:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
ช่องโหว่ CBC และ CTR และทำไมคุณควรใช้ GCM
แม้ว่าโหมดอื่น ๆ เช่น CBC และ CTR จะปลอดภัย แต่พวกเขาก็พบเจอปัญหาที่ผู้โจมตีสามารถพลิกข้อมูลที่เข้ารหัสได้เปลี่ยนค่าเมื่อถอดรหัส สมมติว่าคุณเข้ารหัสข้อความธนาคารในจินตนาการ "ขาย 100" ข้อความที่เข้ารหัสของคุณจะมีลักษณะเช่นนี้ "eu23ng" ผู้โจมตีเปลี่ยนหนึ่งบิตเป็น "eu53ng" และในทันทีเมื่อถอดรหัสข้อความของคุณมันจะอ่านว่า "ขาย 900"
เพื่อหลีกเลี่ยงปัญหานี้อินเทอร์เน็ตส่วนใหญ่ใช้ GCM และทุกครั้งที่คุณเห็น HTTPS พวกเขาอาจใช้ GCM GCM ลงนามข้อความที่เข้ารหัสด้วยแฮชและตรวจสอบเพื่อยืนยันว่าข้อความไม่ได้ถูกเปลี่ยนโดยใช้ลายเซ็นนี้
ฉันจะหลีกเลี่ยงการนำ GCM ไปใช้เนื่องจากความซับซ้อน คุณควรใช้ห้องสมุดใหม่ของ Googles Tinkเพราะที่นี่อีกครั้งถ้าคุณทำซ้ำ IV โดยไม่ตั้งใจคุณกำลังทำกุญแจสำคัญในกรณีด้วย GCM ซึ่งเป็นข้อบกพร่องด้านความปลอดภัยขั้นสูงสุด นักวิจัยใหม่กำลังทำงานกับโหมดการเข้ารหัสที่ทนทานต่อการทำซ้ำ IV ซึ่งแม้ว่าคุณจะทำซ้ำ IV กุญแจนั้นไม่ได้อยู่ในอันตราย แต่สิ่งนี้ยังไม่ได้เกิดขึ้น
ตอนนี้ถ้าคุณไม่ต้องการที่จะใช้ GCM นี่คือการเชื่อมโยงไปยังการดำเนินงานที่ดี GCM อย่างไรก็ตามฉันไม่สามารถรับรองความปลอดภัยหรือหากมีการใช้งานอย่างเหมาะสม แต่จะทำให้พื้นฐานลดลง โปรดทราบด้วย GCM ว่าไม่มีช่องว่างภายใน
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
คีย์เทียบกับรหัสผ่าน
สิ่งสำคัญอีกข้อหนึ่งคือเมื่อมีการเข้ารหัสคีย์และรหัสผ่านจะไม่เหมือนกัน กุญแจสำคัญในการเข้ารหัสต้องมีจำนวนเอนโทรปีและการสุ่มเพื่อพิจารณาความปลอดภัย นี่คือเหตุผลที่คุณต้องแน่ใจว่าใช้ไลบรารี่เข้ารหัสที่เหมาะสมเพื่อสร้างคีย์ให้คุณ
ดังนั้นคุณจริงๆมีสองการใช้งานที่คุณสามารถทำได้ที่นี่เป็นครั้งแรกคือการใช้รหัสที่พบในด้าย StackOverflow นี้ได้สุ่มรุ่นที่สำคัญ โซลูชันนี้ใช้ตัวสร้างตัวเลขสุ่มที่ปลอดภัยเพื่อสร้างคีย์ตั้งแต่เริ่มต้นที่คุณสามารถใช้ได้
อีกทางเลือกที่ปลอดภัยน้อยกว่าคือการใช้อินพุตของผู้ใช้เช่นรหัสผ่าน ปัญหาที่เรากล่าวถึงคือรหัสผ่านมีเอนโทรปีไม่เพียงพอดังนั้นเราจะต้องใช้PBKDF2ซึ่งเป็นอัลกอริทึมที่ใช้รหัสผ่านและสร้างความแข็งแกร่งให้กับมัน นี่คือการดำเนินการ StackOverflow ฉันชอบ อย่างไรก็ตามห้องสมุด Google Tink มีสิ่งเหล่านี้ทั้งหมดและคุณควรใช้ประโยชน์จากมัน
นักพัฒนา Android
จุดสำคัญอย่างหนึ่งที่ชี้ให้เห็นที่นี่คือรู้ว่ารหัส Android ของคุณสามารถย้อนกลับได้และส่วนใหญ่โค้ด Java ก็เช่นกัน นั่นหมายความว่าถ้าคุณเก็บรหัสผ่านเป็นข้อความธรรมดาในรหัสของคุณ แฮกเกอร์สามารถเรียกดูได้อย่างง่ายดาย โดยปกติสำหรับการเข้ารหัสประเภทนี้คุณต้องการใช้ Asymmetric Cryptography และอื่น ๆ นี่อยู่นอกขอบเขตของโพสต์นี้ดังนั้นฉันจะหลีกเลี่ยงการลงไป
การอ่านที่น่าสนใจจากปี 2013 : ชี้ให้เห็นว่า 88% ของการใช้ Crypto ใน Android นั้นทำได้ไม่ถูกต้อง
ความคิดสุดท้าย
อีกครั้งฉันขอแนะนำให้หลีกเลี่ยงการใช้ไลบรารี java สำหรับ crypto โดยตรงและใช้Google Tinkมันจะช่วยให้คุณปวดหัวเพราะพวกเขาทำงานได้ดีมากในการใช้อัลกอริธึมทั้งหมดอย่างถูกต้อง และจากนั้นตรวจสอบให้แน่ใจว่าคุณตรวจสอบปัญหาที่เกิดขึ้นใน Tink GitHub ช่องโหว่จะปรากฏขึ้นที่นี่และที่นั่น
หากคุณมีคำถามหรือข้อเสนอแนะอย่าลังเลที่จะแสดงความคิดเห็น! การรักษาความปลอดภัยมีการเปลี่ยนแปลงอยู่ตลอดเวลาและคุณต้องทำให้ดีที่สุดเพื่อให้ทัน :)