首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 加密通訊實戰:基於 CipherInputStream/OutputStream 的安全 Socket 封裝

     編輯:Java 相關知識

利用 JCE (Java Cryptography Extension) 將對稱加密(AES/DES)透明套用在 Socket 流上。核心類 SecretSocket 封裝 CipherInputStream/CipherOutputStream,對上層應用完全隱藏加解密細節。

架構圖

Application
    │
    ▼
SecretSocket (extends Socket)
    ├─ getInputStream()  → CipherInputStream  → DECrypt → 原始 Socket InputStream
    └─ getOutputStream() → CipherOutputStream → ENcrypt → 原始 Socket OutputStream

SecretSocket 關鍵實作

public class SecretSocket extends Socket {
    private final Cipher encryptCipher;
    private final Cipher decryptCipher;

    public SecretSocket(Socket socket, SecretKey key, String algorithm) throws Exception {
        super(); // 不自動連線,手動初始化
        this.impl = socket.impl; // 共用底層 SocketImpl (需反射或繼承策略)
        // 簡化示範:實際建議用組合而非繼承
        encryptCipher = Cipher.getInstance(algorithm);
        encryptCipher.init(Cipher.ENCRYPT_MODE, key);
        decryptCipher = Cipher.getInstance(algorithm);
        decryptCipher.init(Cipher.DECRYPT_MODE, key);
    }

    @Override
    public InputStream getInputStream() throws IOException {
        return new CipherInputStream(super.getInputStream(), decryptCipher);
    }

    @Override
    public OutputStream getOutputStream() throws IOException {
        return new CipherOutputStream(super.getOutputStream(), encryptCipher);
    }
}

Server/Client 整合範例

// Server
public class SecureServer {
    public static void main(String[] args) throws Exception {
        SecretKey key = KeyGenerator.getInstance("AES").generateKey(); // 實際應安全分發
        try (ServerSocket server = new ServerSocket(8888)) {
            while (true) {
                Socket client = server.accept();
                SecretSocket sec = new SecretSocket(client, key, "AES");
                new Thread(() -> handle(sec)).start();
            }
        }
    }
    static void handle(SecretSocket s) {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"));
             PrintWriter out = new PrintWriter(new OutputStreamWriter(s.getOutputStream(), "UTF-8"), true)) {
            String msg;
            while ((msg = in.readLine()) != null) {
                System.out.println("收到解密: " + msg);
                out.println("Server Echo: " + msg);
            }
        } catch (IOException e) { e.printStackTrace(); }
    }
}

// Client
public class SecureClient {
    public static void main(String[] args) throws Exception {
        SecretKey key = ...; // 與 Server 共享同一把鑰
        try (SecretSocket s = new SecretSocket(new Socket("localhost", 8888), key, "AES");
             PrintWriter out = new PrintWriter(new OutputStreamWriter(s.getOutputStream(), "UTF-8"), true);
             BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"))) {
            out.println("Hello Secure World");
            System.out.println("Server 回應: " + in.readLine());
        }
    }
}

生產環境必備強化

  • 金鑰協商:不可硬編碼金鑰,需用 Diffie-Hellman 或 RSA 非對稱加密交換對稱金鑰,或引入 TLS/SSL (JSSE) 直接使用標準 HTTPS。
  • 完整性校驗:AES-GCM/CCM 模式同時提供加密與認證,防止竄改。
  • 重放攻擊防護:在協議層加入 Sequence Number 或 Timestamp + HMAC。
  • 效能:Cipher 流層屬同步操作,高併發建議用 Netty + OpenSSL (BoringSSL) 原生實現。

總結

CipherInputStream/OutputStream 是 JDK 提供的「裝飾者模式」加密流,幾行代碼即可為任意 InputStream/OutputStream 增加透明加密。但自行實作安全協議極易踩坑,正式專案優先使用成熟的 TLS (JSSE/Netty SSL) 或成熟框架(Spring Security、Apache MINA/Netty SSL),僅在特殊嵌入式/舊系統無法使用 TLS 時才考慮自行封裝。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved