ข้ามไปยังเนื้อหาหลัก

ค้นหาใน CooLWJ

选择搜索范围,输入关键词后按回车。

ภาษา

ศิลปะแห่งการเข้ารหัสและถอดรหัส

หนึ่ง การเข้ารหัสแบบสมมาตร

การเข้ารหัสแบบสมมาตรและแบบอสมมาตรเป็นวิธีเข้ารหัสสองแบบที่แตกต่างกัน ซึ่งมีบทบาทสำคัญต่อความปลอดภัยของข้อมูลและการส่งข้อมูล ต่อไปผมจะแนะนำเทคโนโลยีการเข้ารหัสทั้งสองแบบนี้แยกกัน:

1.1 การเข้ารหัสแบบสมมาตร(Symmetric Encryption)

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

อัลกอริทึมการเข้ารหัสแบบสมมาตรที่พบบ่อย:

  • AES(มาตรฐานการเข้ารหัสขั้นสูง)

  • DES(มาตรฐานการเข้ารหัสข้อมูล)

  • 3DES(อัลกอริทึมเข้ารหัสข้อมูลสามชั้น)

1.2 ลักษณะของการเข้ารหัสแบบสมมาตร

โดยทั่วไป การเข้ารหัสแบบสมมาตรมีลักษณะดังต่อไปนี้:

  1. ความเร็วค่อนข้างสูง:เนื่องจากการเข้ารหัสและถอดรหัสใช้กุญแจเดียวกัน การเข้ารหัสแบบสมมาตรจึงมักเร็วกว่าแบบอสมมาตร

  2. การจัดการกุญแจเข้ารหัส:ความท้าทายหลักของการเข้ารหัสแบบสมมาตรอยู่ที่การแจกจ่ายและการจัดการกุญแจ หากกุญแจรั่วไหล ความปลอดภัยของการเข้ารหัสก็จะถูกคุกคาม

  3. เหมาะสำหรับข้อมูลจำนวนมาก:เนื่องจากทำงานรวดเร็ว การเข้ารหัสแบบสมมาตรจึงเหมาะกับการเข้ารหัสข้อมูลปริมาณมาก

จากตรงนี้จะเห็นได้ว่า การเข้ารหัสแบบสมมาตรมีข้อได้เปรียบหลักสองประการ:ข้อแรกคือคำนวณได้เร็ว;ข้อที่สองคือเหมาะกับข้อมูลปริมาณมาก。

แต่การเข้ารหัสแบบสมมาตรมีปัญหาร้ายแรงข้อหนึ่ง นั่นคือการจัดการกุญแจ จะส่งกุญแจจากฝั่งเซิร์ฟเวอร์ไปยังไคลเอนต์อย่างปลอดภัยได้อย่างไร นี่เป็นปัญหาหนึ่ง!อีกทั้งเมื่อสื่อสารแบบหนึ่งต่อหลาย การจัดการกุญแจไม่ให้รั่วไหลก็เป็นความท้าทายเช่นกัน นี่คือข้อบกพร่องของการเข้ารหัสแบบสมมาตร。

ภาพประกอบเชิงศิลปะของผนังสีเขียวอมฟ้ากับลูกกลิ้งทาสี

1.3 ตัวอย่างโค้ด

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

การใช้การเข้ารหัสแบบสมมาตรใน Java โดยทั่วไปจะใช้คลาสและอินเทอร์เฟซที่ Java Cryptography Architecture(JCA)จัดเตรียมไว้

ด้านล่างคือตัวอย่างง่าย ๆ ของการเข้ารหัสและถอดรหัสแบบสมมาตรด้วยอัลกอริทึม AES(มาตรฐานการเข้ารหัสขั้นสูง):

public class SymmetricEncryptionExample {    // 生成密钥
    public static SecretKey generateKey() throws Exception {     
       KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128); // 可以是128, 192或256位
        return keyGenerator.generateKey();
    }    
    // 加密方法
    public static String encrypt(String data, SecretKey key) throws Exception {      
      Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, key);       
         byte[] encryptedBytes = cipher.doFinal(data.getBytes());        
         return Base64.getEncoder().encodeToString(encryptedBytes);
    }    
    // 解密方法
    public static String decrypt(String encryptedData, SecretKey key) throws Exception {        
    Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, key);       
         byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedData));       
          return new String(decryptedBytes);
    }    
    public static void main(String[] args) {        
    try {           
             // 生成密钥
            SecretKey key = generateKey();           
             // 原始数据
            String originalData = "Hello, JavaBoy!";            
            // 加密
            String encryptedData = encrypt(originalData, key);
            System.out.println("加密数据: " + encryptedData);            
            // 解密
            String decryptedData = decrypt(encryptedData, key);
            System.out.println("解密数据: " + decryptedData);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  1. สร้างกุญแจ:ใช้ KeyGenerator สร้างกุญแจ AES หนึ่งชุด。

  2. การเข้ารหัส:ใช้ Cipher คลาสเพื่อเข้ารหัส โดยแปลงข้อมูลเป็นไบต์ก่อนเข้ารหัส แล้วใช้การเข้ารหัส Base64 แปลงเป็นสตริง เพื่อให้จัดเก็บหรือส่งต่อได้สะดวก。

  3. ถอดรหัส:ถอดรหัสสตริงที่เข้ารหัสไว้กลับเป็นไบต์ จากนั้นใช้กุญแจเดียวกันถอดรหัสลับ。

สิ่งที่ทุกคนต้องสังเกตในโค้ดข้างต้นคือ:

  • ควรเลือกความยาวของกุญแจ(เช่น 128 บิต)ตามความต้องการด้านความปลอดภัย

  • จัดเก็บกุญแจให้ปลอดภัย อย่าฮาร์ดโค้ดกุญแจไว้ในโค้ด。

  • สำหรับสภาพแวดล้อมการใช้งานจริง ควรพิจารณาใช้กลยุทธ์จัดการกุญแจที่ปลอดภัยยิ่งขึ้น。

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

public static SecretKey generateKeyFromPassword(String password, int keySize) throws NoSuchAlgorithmException, InvalidKeySpecException {   
  SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");   
   KeySpec spec = new PBEKeySpec(password.toCharArray(), "salt".getBytes(), 65536, keySize);   
   return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
}

เท่านี้ก็สามารถควบคุมกุญแจเข้ารหัสผ่านพารามิเตอร์ที่ส่งเข้ามาเองได้。

1.4 การทำงานร่วมกันของฟรอนต์เอนด์และแบ็กเอนด์

เมื่อใช้อัลกอริทึม AES เข้ารหัสและถอดรหัสข้ามภาษา(เช่น JavaScript และ Java) สิ่งสำคัญคือต้องแน่ใจว่าทั้งสองฝั่งใช้กุญแจเดียวกัน โหมดอัลกอริทึมเดียวกัน(เช่น CBC, ECB เป็นต้น) รูปแบบการเติมข้อมูลเดียวกัน(เช่น PKCS5Padding, PKCS7Padding เป็นต้น) และเวกเตอร์เริ่มต้นเดียวกัน(IV หากใช้โหมดที่ต้องมี IV เช่น CBC)。

ก่อนหน้านี้มีเพื่อนคนหนึ่งบอกว่า หลังเข้ารหัสที่ฝั่งฟรอนต์เอนด์แล้ว ฝั่งแบ็กเอนด์กลับถอดรหัสไม่ได้อยู่เสมอ พี่ซงจึงขอยกตัวอย่างการใช้ฟรอนต์เอนด์คู่กับแบ็กเอนด์ไว้ที่นี่ด้วย。

เข้ารหัสที่ส่วนหน้า ถอดรหัสที่ส่วนหลัง

โค้ดส่วนหน้า:

<!DOCTYPE html><html lang="en"><head>
    <meta charset="UTF-8">
    <title>AES加密示例</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
    </head>
    <body>
    <script>
    function encryptAES(text, secretKey) {        
    const key = CryptoJS.enc.Utf8.parse(secretKey);        
    const iv = CryptoJS.lib.WordArray.random(128 / 8); 
    // 对于CBC模式,需要IV
    
        const encrypted = CryptoJS.AES.encrypt(text, key, {           
         iv: iv,           
          mode: CryptoJS.mode.CBC,            
          padding: CryptoJS.pad.Pkcs7
        });        
        // 返回加密后的文本和IV(Base64格式),实际使用中可能需要安全地传输这些值
        return {          
          ciphertext: encrypted.toString(),          
            iv: iv.toString(CryptoJS.enc.Base64)
        };
    }    
    const secretKey = 'helloworldhelloworldhelloworld11'; /
    / 确保密钥是32个字符长(256位)
    const text = 'Hello, javaboy!';    
    const result = encryptAES(text, secretKey);    
    console.log(result);
    </script>
    </body>
    </html>


โค้ดฝั่งแบ็กเอนด์:

import javax.crypto.Cipher;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;import java.util.Base64;public class AESDecrypt {    public static String decryptAES(String encryptedData, String secretKey, String iv) throws Exception {        IvParameterSpec ivParameterSpec = new IvParameterSpec(Base64.getDecoder().decode(iv));        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes("UTF-8"), "AES");        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);        byte[] decodedValue = Base64.getDecoder().decode(encryptedData);        byte[] decryptedValue = cipher.doFinal(decodedValue);        return new String(decryptedValue, "UTF-8");
    }    public static void main(String[] args) {        try {            //前端加密后的文本
            String encryptedText = "PYANpAjMsRnBIEhovtEXQw==";            String secretKey = "helloworldhelloworldhelloworld11";            //前端 IV,要和加密后的文本一起传到后端
            String iv = "y/jUHcgSOpOiyNlsfjNUBg==";            String decryptedText = decryptAES(encryptedText, secretKey, iv);
            System.out.println("解密文本: " + decryptedText);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

โปรดสังเกตว่าเมื่อเข้ารหัสที่ฝั่งฟรอนต์เอนด์จะสร้างพารามิเตอร์ iv ขึ้นมา ซึ่งต้องส่งไปยังแบ็กเอนด์พร้อมกับผลการเข้ารหัสจากฟรอนต์เอนด์

เข้ารหัสที่แบ็กเอนด์ ถอดรหัสที่ฟรอนต์เอนด์

เมื่อเข้ารหัส AES ใน Java แล้วถอดรหัสใน JavaScript จำเป็นต้องตรวจสอบเช่นกันว่าทั้งสองฝั่งใช้กุญแจเดียวกัน โหมดอัลกอริทึมเดียวกัน(เช่น CBC、ECB เป็นต้น)โหมดการเติมข้อมูลเดียวกัน(เช่น PKCS5Padding、PKCS7Padding เป็นต้น)และเวกเตอร์เริ่มต้น(IV)เดียวกัน(หากมีการใช้งาน)。

โค้ดฝั่งแบ็กเอนด์:

public class AESEncrypt {    public static String encryptAES(String plainText, String secretKey, String iv) throws Exception {        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(256); // 对于AES-256
        SecretKey secret = new SecretKeySpec(secretKey.getBytes("UTF-8"), "AES");        IvParameterSpec ivParameterSpec = new IvParameterSpec(Base64.getDecoder().decode(iv));        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret, ivParameterSpec);        byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));        return Base64.getEncoder().encodeToString(encrypted);
    }    public static void main(String[] args) {        try {            String plainText = "Hello, 江南一点雨!";            String secretKey = "helloworldhelloworldhelloworld11"; // 确保密钥是32个字符长(256位)
            String iv = Base64.getEncoder().encodeToString(new byte[16]); // 示例IV,实际应用中应更安全地生成

            String encryptedText = encryptAES(plainText, secretKey, iv);
            System.out.println("Encrypted text: " + encryptedText);
            System.out.println("IV (Base64): " + iv); // 确保将IV发送给解密方

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

โค้ดส่วนหน้า:

<!DOCTYPE html><html lang="en"><head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
    <script>
        function decryptAES(ciphertext, secretKey, iv) {            const key = CryptoJS.enc.Utf8.parse(secretKey);            const ivParsed = CryptoJS.enc.Base64.parse(iv);            const decrypted = CryptoJS.AES.decrypt(
                {                    ciphertext: CryptoJS.enc.Base64.parse(ciphertext)
                },
                key,
                {                    iv: ivParsed,                    mode: CryptoJS.mode.CBC,                    padding: CryptoJS.pad.Pkcs7
                }
            );            return decrypted.toString(CryptoJS.enc.Utf8);
        }        const secretKey = 'helloworldhelloworldhelloworld11';        const iv = 'AAAAAAAAAAAAAAAAAAAAAA=='; // 从Java代码获取
        const ciphertext = '1lPNVF1injas78KUWeKp5FusEr6f0pGgcrLAg9ELFr8='; // 从Java代码获取

        const decryptedText = decryptAES(ciphertext, secretKey, iv);        console.log(decryptedText);    </script></head><body></body></html>

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

สอง การเข้ารหัสแบบอสมมาตร

2.1 การเข้ารหัสแบบอสมมาตรคืออะไร

การเข้ารหัสแบบอสมมาตร หรือเรียกอีกอย่างว่าการเข้ารหัสด้วยกุญแจสาธารณะ เป็นวิธีเข้ารหัสที่ใช้กุญแจสองดอกที่แตกต่างกัน(กุญแจสาธารณะและกุญแจส่วนตัว)。

โดยทั่วไป การเข้ารหัสแบบอสมมาตรมีลักษณะเด่นหลายประการดังต่อไปนี้:

  1. กุญแจสาธารณะและกุญแจส่วนตัว

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

  1. มีความปลอดภัยสูง

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

  • การต้านทานการโจมตีด้วยคอมพิวเตอร์ควอนตัม:โครงการบล็อกเชนบางโครงการเริ่มใช้อัลกอริทึมเข้ารหัสที่ต้านทานการโจมตีด้วยคอมพิวเตอร์ควอนตัม เช่น อัลกอริทึมลายเซ็นดิจิทัลเส้นโค้งวงรี(ECDSA)รุ่นที่ปลอดภัยจากควอนตัม เพื่อรับมือกับภัยคุกคามจากคอมพิวเตอร์ควอนตัมในอนาคต

  1. แจกจ่ายกุญแจสาธารณะได้สะดวก

  • การเปิดเผยกุญแจสาธารณะ:กุญแจสาธารณะสามารถเปิดเผยให้ใครก็ได้ จึงแจกจ่ายได้สะดวกมาก ทุกคนสามารถใช้กุญแจสาธารณะเข้ารหัสข้อมูลได้ แต่มีเพียงผู้ถือกุญแจส่วนตัวเท่านั้นที่ถอดรหัสได้。

  1. การยืนยันตัวตนและลายเซ็นดิจิทัล

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

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

  1. การสื่อสารที่ปลอดภัย

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

  1. การควบคุมสินทรัพย์ดิจิทัล

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

  1. ความเร็วในการเข้ารหัสและถอดรหัส

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

2.2 การใช้งานการเข้ารหัสแบบอสมมาตร

การเข้ารหัสแบบอสมมาตรมีกรณีการใช้งานหลักที่พบได้ทั่วไปสองแบบ。

  1. การเข้ารหัส:นี่คือการใช้งานที่เราคุ้นเคยที่สุด คือใช้กุญแจสาธารณะเข้ารหัส และใช้กุญแจส่วนตัวถอดรหัส。

  2. ลายเซ็น:เนื่องจากเครือข่ายไม่น่าไว้วางใจ ข้อมูลอาจถูกแก้ไขระหว่างส่งได้ ในกรณีนี้สามารถใช้คีย์สาธารณะและคีย์ส่วนตัวสลับบทบาทกัน โดยใช้คีย์ส่วนตัวลงลายเซ็นข้อมูล และใช้คีย์สาธารณะตรวจสอบลายเซ็น เพื่อให้แน่ใจว่าข้อมูลปลอดภัยและครบถ้วน

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

แม้อัลกอริทึมการเข้ารหัสแบบอสมมาตรจะใช้เข้ารหัสข้อมูลและสร้างลายเซ็นดิจิทัลได้ในทางทฤษฎี แต่ในทางปฏิบัติ ความซับซ้อนในการคำนวณที่สูงและประสิทธิภาพที่ต่ำกลายเป็นอุปสรรคสำคัญ

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

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

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

2.3 ตัวอย่างการเข้ารหัส

ตัวอย่างโค้ด Java ที่ใช้ RSA เข้ารหัสและถอดรหัส:

public class RsaDemo {    public static void main(String[] args) {        try {            KeyPair keyPair = generateRSAKeyPair();            PublicKey publicKey = keyPair.getPublic();            PrivateKey privateKey = keyPair.getPrivate();            String originalData = "Hello, 江南一点雨!";            String encryptedData = encrypt(publicKey, originalData);            String decryptedData = decrypt(privateKey, encryptedData);

            System.out.println("加密后的数据: " + encryptedData);
            System.out.println("解密后的数据: " + decryptedData);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }    public static String decrypt(PrivateKey privateKey, String encryptedData) throws Exception {        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedData));        return new String(decryptedBytes);
    }    public static String encrypt(PublicKey publicKey, String data) throws Exception {        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);        byte[] bytes = cipher.doFinal(data.getBytes());        return Base64.getEncoder().encodeToString(bytes);
    }    public static KeyPair generateRSAKeyPair() throws NoSuchAlgorithmException {        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048); // 可以指定密钥长度,如2048位
        return keyGen.generateKeyPair();
    }
}

2.4 การใช้ส่วนหน้าและส่วนหลังร่วมกัน

เข้ารหัสที่ส่วนหน้า ถอดรหัสที่ส่วนหลัง

โค้ดฝั่งแบ็กเอนด์เหมือนกับตัวอย่างข้างต้น ต่างกันตรงที่หลังจากได้รับกุญแจสาธารณะแล้ว เราสามารถพิมพ์กุญแจสาธารณะออกมาได้ โดยกุญแจนี้จะต้องส่งต่อให้ฟรอนต์เอนด์ในภายหลัง:

public static void main(String[] args) {    try {        KeyPair keyPair = generateRSAKeyPair();        PublicKey publicKey = keyPair.getPublic();        PrivateKey privateKey = keyPair.getPrivate();
        System.out.println("公钥: " + Base64.getEncoder().encodeToString(publicKey.getEncoded()));        String originalData = "Hello, 江南一点雨!";        String encryptedData = encrypt(publicKey, originalData);        String decryptedData = decrypt(privateKey, encryptedData);
        System.out.println("加密后的数据: " + encryptedData);
        System.out.println("解密后的数据: " + decryptedData);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

โค้ดส่วนหน้ามีดังนี้:

<!DOCTYPE html><html lang="en"><head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RSA Encryption Example</title>
    <!-- 引入jsencrypt库 -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/bin/jsencrypt.min.js"></script></head><body><script>
    // 重写前端加密方法
    function encryptData(publicKey, data) {        // 创建一个新的JSEncrypt对象
        var encryptor = new JSEncrypt();        // 设置公钥
        encryptor.setPublicKey(publicKey);        // 加密数据
        var encrypted = encryptor.encrypt(data);        return encrypted;
    }    // 示例公钥(实际使用时应该替换为服务器提供的公钥)
    var publicKey = `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnP5FOXIghidLDE2FgFwzi4Y+qTdYjnc0eMoiL5i4gdOeTE+7Uu9YvDB51GcBWKD9lvmZr5rX8z0OBpwe526qsTekNpXoIVk9DB34US0HOrAXEEwpUTVuSR656cJGAwmWBkVaalQynEz4Dlzrm53zExVYueruYUuzFyuZDaQcFnl3rWUH/XDkCIe23z0R1TfT3Q2OYNKft0u56r0S/ko99utXuYJK9yowe7QGT6q4cSJwsITQTomCARAq9q+bSNuGEYa4FlYCKIKWIhKbMhz0FYIMB2fJN10GyZbbvKASqeMkuCoD2Efgd8/6uMwOaMcx9LgEkcFaQ3qgDutsPXNUswIDAQAB`;    // 要加密的数据
    var data = 'Hello, javaboy!';    // 调用加密方法
    var encryptedData = encryptData(publicKey, data);    // 输出加密后的数据
    console.log('Encrypted Data:', encryptedData);</script></body></html>

เข้ารหัสที่แบ็กเอนด์ ถอดรหัสที่ฟรอนต์เอนด์

การใช้ขั้นตอนวิธี RSA เข้ารหัสข้อมูลใน Java แล้วถอดรหัสข้อมูลเหล่านั้นใน JavaScript หมายความว่าฝั่งเซิร์ฟเวอร์ใช้กุญแจสาธารณะของส่วนหน้าเข้ารหัส และส่วนหน้าใช้กุญแจส่วนตัวของตัวเองถอดรหัส ในสถานการณ์เช่นนี้ กุญแจส่วนตัวของส่วนหน้าถูกขโมยได้ง่าย จึงไม่แนะนำวิธีใช้งานแบบนี้ ผมจึงไม่ยกตัวอย่าง

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


ความคิดเห็น

กำลังส่ง

บทความยอดนิยม

เลือกธีมที่ชอบ

ธีมที่เลือกจะใช้ทั่วทั้งเว็บไซต์