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

Java 實現 RSA 與 DSA 數字簽名算法完整指南

     編輯:Java 相關知識

RSA 非對稱加密算法

核心原理

  • 密鑰生成:選兩大素數 p、q,計算 N=pq、φ(N)=(p-1)(q-1)。選 e 與 φ(N) 互質,求 d ≡ e⁻¹ mod φ(N)。公鑰 (N,e),私鑰 (N,d)。
  • 加密:C ≡ Mᵉ mod N(公鑰加密)。
  • 解密:M ≡ Cᵈ mod N(私鑰解密)。
  • 簽名/驗簽:私鑰簽名,公鑰驗證,確保完整性、不可抵賴性。

Java 實現(JCA 標準 API)

public class RSA {
    static final String KEY_ALGORITHM = "RSA";
    static final String CIPHER_ECB_PKCS1 = "RSA/ECB/PKCS1Padding";

    public static void main(String[] args) throws Exception {
        String data = "斯柯達U*(Sfsad7f()*^%%$";
        // 1. 公鑰加密,私鑰解密
        encryptDecryptByPublicKey(data);
        // 2. 私鑰加密,公鑰解密(簽名場景)
        encryptDecryptByPrivateKey(data);
        // 3. 指定 Padding 模式
        encryptDecryptWithExplicitPadding(data);
    }

    static void encryptDecryptByPublicKey(String str) throws Exception {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        KeyPair kp = kpg.generateKeyPair();
        PublicKey pub = kp.getPublic();
        PrivateKey pri = kp.getPrivate();

        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM); // 默認 ECB/PKCS1Padding
        cipher.init(Cipher.ENCRYPT_MODE, pub);
        byte[] enc = cipher.doFinal(str.getBytes());
        System.out.println("公鑰加密: " + Arrays.toString(enc));

        cipher.init(Cipher.DECRYPT_MODE, pri);
        byte[] dec = cipher.doFinal(enc);
        System.out.println("私鑰解密: " + new String(dec));
    }
    // 其他方法類似...
}

注意:RSA 直接加密數據長度受限於密鑰長度(1024bit 密鑰最多加密 117 字節)。實際項目中採用混合加密:AES 加密數據,RSA 加密 AES 密鑰。

DSA 數字簽名算法

特點

  • 僅用於簽名/驗證,不可用於加密解密、密鑰交換。
  • 基於有限域離散對數難題,安全性與 RSA 相當,但簽名速度更快。
  • 美國 NIST 制定為 DSS (Digital Signature Standard)。

流程

  1. 發送方用私鑰對數據生成簽名。
  2. 接收方用發送方公鑰驗證簽名與數據是否匹配。
  3. 數據本身可不加密(明文傳輸),簽名保證完整性與來源認證。

Java 實現

public class DSA {
    static final String KEY_ALGORITHM = "DSA";
    static final String SIGNATURE_ALGORITHM = "DSA"; // 或 "SHA1withDSA"
    static final String DEFAULT_SEED = "$%^*%^()(HJG8awfjas7";

    public static void main(String[] args) throws Exception {
        String str = "!@#$!#^$#&ZXVDF呆兵工路愛著你*()_+";
        byte[] data = str.getBytes();

        Map<String, Object> keyMap = initKey(); // 生成密鑰對
        PublicKey pub = (PublicKey) keyMap.get("DSAPublicKey");
        PrivateKey pri = (PrivateKey) keyMap.get("DSAPrivateKey");

        String sign = sign(data, getPrivateKey(keyMap)); // 私鑰簽名
        System.out.println("簽名: " + sign);

        boolean v1 = verify("aaa".getBytes(), getPublicKey(keyMap), sign); // 錯誤數據
        System.out.println("錯誤數據驗證: " + v1); // false

        boolean v2 = verify(data, getPublicKey(keyMap), sign); // 正確數據
        System.out.println("正確數據驗證: " + v2); // true
    }

    static Map<String, Object> initKey(String seed) throws Exception {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        SecureRandom sr = new SecureRandom(seed.getBytes());
        kpg.initialize(640, sr); // 512-1024 位,64 的倍數
        KeyPair kp = kpg.genKeyPair();
        Map<String, Object> map = new HashMap<>();
        map.put("DSAPublicKey", kp.getPublic());
        map.put("DSAPrivateKey", kp.getPrivate());
        return map;
    }

    static String sign(byte[] data, String privateKeyBase64) throws Exception {
        byte[] keyBytes = decryptBASE64(privateKeyBase64);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        PrivateKey pri = KeyFactory.getInstance(KEY_ALGORITHM).generatePrivate(spec);
        Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
        sig.initSign(pri);
        sig.update(data);
        return encryptBASE64(sig.sign());
    }

    static boolean verify(byte[] data, String publicKeyBase64, String signBase64) throws Exception {
        byte[] keyBytes = decryptBASE64(publicKeyBase64);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        PublicKey pub = KeyFactory.getInstance(KEY_ALGORITHM).generatePublic(spec);
        Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
        sig.initVerify(pub);
        sig.update(data);
        return sig.verify(decryptBASE64(signBase64));
    }

    // BASE64 編解碼輔助方法...
}

RSA 也可做數字簽名

將 KEY_ALGORITHM="RSA"、SIGNATURE_ALGORITHM="MD5withRSA" 或 SHA256withRSA,流程與 DSA 完全一致。RSA 簽名較慢,但兼容性更廣。

工程落地建議

  1. 密鑰管理:生產環境密鑰應存儲於 HSM 或密鑰管理系統,嚴禁硬編碼。
  2. 填充模式:RSA 加密必須指定 OAEPWithSHA-256AndMGF1Padding,避免 PKCS#1 v1.5 填充被選擇密文攻擊。
  3. 簽名算法選型:新項目優先 RSA-PSS (SHA256withRSAandMGF1) 或 ECDSA,DSA 漸被淘汰(密鑰長度限制)。
  4. Base64 編碼:密鑰、簽名傳輸統一使用 Base64(URL-safe 版本)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved