一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 基于Java Swing和BouncyCastle的證書生成工具

基于Java Swing和BouncyCastle的證書生成工具

2023-11-26 01:15未知服務器之家 Java教程

"Almost no one will remember what he had just not interested." - Nobody “幾乎沒有人會記得他所絲毫不感興趣的事情。” —— 佚名 0x00 大綱 目錄 0x00 大綱 0x01 前言 0x02 技術選型 0x03 需求分析 目標用戶 用戶故事 功能需求 安全需求 兼容需求 性能

"Almost no one will remember what he had just not interested." - Nobody

“幾乎沒有人會記得他所絲毫不感興趣的事情。” —— 佚名

0x00 大綱

目錄
  • 0x00 大綱
  • 0x01 前言
  • 0x02 技術選型
  • 0x03 需求分析
    • 目標用戶
    • 用戶故事
    • 功能需求
    • 安全需求
    • 兼容需求
    • 性能需求
  • 0x04 原型設計
    • 主窗體
    • RSA根證書生成頁面
    • ECC根證書生成頁面
    • RSA證書生成頁面
    • ECC證書生成頁面
  • 0x05 架構設計
  • 0x06 概要設計
  • 0x07 詳細設計
  • 0x08 編碼實現
    • RSA根證書生成(節選關鍵部分)
    • ECC根證書生成
  • 0x09 小結
    • 運行效果

0x01 前言

隨著這些年人們對于信息安全的愈加重視,工作中經常用到各種數字證書,最主要的用途就是加密和簽名。但是反復生成用于測試的數字證書是一件麻煩事,雖然感謝有強大的OpenSSL工具,但是問就是記不住命令,問就是不想看文檔。為了提高工作效率,降低苦痛指數,遂決定開發一個證書生成小工具。

0x02 技術選型

我們需要一個簡單的GUI,在Java的領域中,可以選擇使用JavaFX或著Swing來實現,鑒于我們不需要太花哨的東西,只需要幾個簡單的布局和控件,這里選擇了使用Swing來開發圖形界面。小聲BB:甲方是我,乙方也是我,能用就行,要啥自行車。

我們需要用到RSA或著國密的數字證書,湊巧BouncyCastle就是一個提供了很多哈希算法和加密算法的第三方庫。老牌子,易使用。

初步估計工期為一周,太長容易從入門到放棄,太短則對心臟不友好。

0x03 需求分析

目標用戶

  • 給開發人員用
  • 給業務人員用
  • 給測試人員用

用戶故事

作為使用者:

  • 我需要工具同時支持生成RSA和國密的證書;
  • 我想簡單點幾下按鈕就能生成自己想要的證書,我不想記一大串又臭又長的命令行;
  • 我不希望到處搜索一堆奇奇怪怪的參數,最好什么都不用我填,什么都不用我自己思考;
  • 什么YES or NO統統不要,問就是YES......
  • 我希望你界面盡量不要太花哨,時間長了看的我眼花;
  • 最好支持批量操作,免得折了我鼠標的壽。

功能需求

  • 使用GUI操作的小工具,包含四個功能菜單:
    • RSA根證書生成
    • RSA證書生成
    • ECC根證書生成,支持批量操作;
    • ECC證書生成,支持批量操作;
    • 生成的同時通過文件選擇對話框選擇保存路徑;
  • RSA根證書簽發:
    • 可以根據選定的密鑰算法和簽名算法,生成RSA和國密的非對稱密鑰對,默認使用123456對私鑰進行加密,可指定密碼,也可一鍵生成隨機密碼;
    • 證書
    • 對于同一對密鑰,需要同時導出:
      • DER編碼的PKCS#8加密私鑰,文件后綴名為.key;
      • PEM編碼的PKCS#8加密私鑰,文件后綴名為.pri.pem;
      • PEM編碼的X.509公鑰,文件后綴名為.pub.pem;
      • DER編碼的X.509公鑰,文件后綴名為.cer;
      • 同時包含X.509公鑰和PKCS#8加密私鑰的PKCS#12證書,文件后綴名為.pfx;
      • 包含私鑰密碼的文本文件,文件后綴為.txt;
        以上文件在一個壓縮包中打包導出,壓縮文件后綴為.zip;
  • RSA證書簽發:
    • 使用選定的根證書,簽發中間證書或葉子證書;
    • 導出要求同上;
  • ECC證書簽發:
    • 同RSA根證書簽發;
  • ECC證書簽發:
    • 使用國密sm2p256v1曲線,其余同RSA證書簽發;
  • 對于RSA證書,擬支持2048(首選)、1024、4096密鑰位數,支持SHA1withRSA、SHA256withRSA、MD5withRSA簽名算法;
  • 對于ECC證書,擬支持sm2p256v1曲線,支持SM3withSM2、SHA256withSM2簽名算法;
  • 證書頒發者信息至少包含:
    • country code (C)
    • locality name (L)
    • state/province name (ST)
    • organization (O)
    • common name (CN)
    • organizational unit name (OU)
      最好都有默認值,能不填就盡量不要填,免得浪費我喝咖啡的時間;
  • 證書使用者信息默認同頒發者信息;
  • 證書有效期默認十年(部分系統不允許過長的證書有效期,第一個版本不考慮這么多);

安全需求

略,見功能需求加密部分。

兼容需求

應與操作系統和其他軟硬加密機生成的證書互相兼容。

性能需求

能用就行。

0x04 原型設計

有了大體上的功能需求分析,就可以進入設計階段了,既然是GUI程序,那就先從界面入手,簡單做一下原型。正好idea上帶有Swing UI Designer,所見即所得,原型可以直接轉化為后期工程。

主窗體

使用JTabbedPane作為容器,承載四個主要功能菜單,簡化交互設計。再加上四個功能界面功能上高度相似,也意味著GUI元素的高度相似,只要設計出一個,其他幾個直接Ctrl+C,Ctrl+V即可。

為了減少動態窗體大小帶來的布局調整和元素Resize,直接使用固定大小窗體,初步定為 640*560 像素。

RSA根證書生成頁面

大部分GUI元素都是按鈕(JButton),下拉框(JComboBox)和輸入框(JTextField or JPasswordField),因此可以考慮左邊為標簽(JLabel),右邊為交互元素的表單結構,首選布局即為Grid Layout。剩下的就是往JPanel上扔控件了。經過一番努力,我們得到了這樣的窗體設計:

基于Java Swing和BouncyCastle的證書生成工具

于是通過復制粘貼,很快可以完成剩余的三個界面:

ECC根證書生成頁面

基于Java Swing和BouncyCastle的證書生成工具

RSA證書生成頁面

基于Java Swing和BouncyCastle的證書生成工具

ECC證書生成頁面

基于Java Swing和BouncyCastle的證書生成工具

0x05 架構設計

由于證書生成工具的定位是C端程序,區別于B/S模型的應用,它更適合使用傳統老三層模型(USL、BLL、DAL),而不是Web應用上經常使用的MVC分層模式。

通過前面的原型設計,已經基本完成了USL表示層中的視圖部分,接下來需要實現USL的控制部分和BLL層的業務邏輯(其實就是實現各個控件需要關注的事件監聽以及對應的事件處理),由于我們的數據持久方式就是文件,所以數據訪問層反而比較簡單了。

DAL層雖然簡單,但是我們保持開放修改的后路,萬一哪天要用數據庫呢?嘿嘿~

0x06 概要設計

通過需求分析和原型設計已經大致可以劃分出功能模塊了,核心部分就是幾個按鈕的事件監聽和處理。

它們都可以統合到一個流程模型中:

參數錄入->點擊按鈕->獲取參數->驗證參數->生成數據->更新UI

以生成RSA根證書處理流程為例:

  1. 參數錄入:界面上選擇密鑰位數、簽名算法、證書密碼(可選)、證書頒發者信息(可選);
  2. 點擊按鈕:監聽按鈕點擊事件;
  3. 獲取參數:獲取UI和后臺的相關參數;
  4. 驗證參數:進行參數合法性檢查,包括但不限于長度,格式,關聯性等;
  5. 生成數據:根據參數,調用BouncyCastle庫生成RSA密鑰對;適配和打包輸出壓縮文件;
  6. 更新UI:提示生成結果,選擇文件存儲路徑等;

異常處理:

  1. 界面彈出提示框;
  2. 后臺記錄日志等;

0x07 詳細設計

將主業務流程的各個節點展開并詳細描述其實現,必要時借助偽代碼進行邏輯表示;這里就不寫了,問就是懶……

0x08 編碼實現

RSA根證書生成(節選關鍵部分)

public final class RSA {
    public static final String MD5_WITH_RSA = "MD5withRSA";
    public static final String SHA1_WITH_RSA = "SHA1withRSA";
    public static final String SHA256_WITH_RSA = "SHA256withRSA";
    public static final int KEY_SIZE_1024 = 1024;
    public static final int KEY_SIZE_2048 = 2048;
    public static final int KEY_SIZE_4096 = 4096;

    private RSA() {
    }

    public static KeyPair generateKeyPair(int keySize) throws NoSuchAlgorithmException {
        if ((keySize & keySize - 1) != 0) {
            throw new InvalidParameterException("非法RSA密鑰位數" + keySize);
        }
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(Global.ALGO_NAME_RSA);
        keyPairGenerator.initialize(keySize);
        return keyPairGenerator.generateKeyPair();
    }
}
private ActionListener rsaRootGenerateButtonListener() {
    return e -> {
        try {
            checkRSARootCertificateConfig();
            JFileChooser fileChooser = makeSaveFileChooser();
            if (JFileChooser.APPROVE_OPTION == fileChooser.showSaveDialog(mainFrame)) {
                String saveDir = fileChooser.getSelectedFile().getAbsolutePath();
                char[] passwordChars = rsaRootPasswordField.getPassword();
                X500Name issuer = obtainIssuerEntry(rsaIssuerCField, rsaIssuerLField, rsaIssuerSTField, rsaIssuerOField, rsaIssuerCNField, rsaIssuerOUField).getValue();
                KeyPair caKeyPair = RSA.generateKeyPair(rsaRootKeySizeBox.getItemAt(rsaRootKeySizeBox.getSelectedIndex()));
                X509Certificate caCertificate = CertificateUtil.generateCertificate(rsaRootSignAlgoBox.getItemAt(rsaRootSignAlgoBox.getSelectedIndex()), caKeyPair, issuer);
                caCertificate.checkValidity(caCertificate.getNotBefore());
                caCertificate.checkValidity(caCertificate.getNotAfter());
                caCertificate.verify(caKeyPair.getPublic());
                PKCS8EncryptedPrivateKeyInfo caPrivateKeyInfo = KeyUtil.makePKCS8EncryptedKey(caKeyPair.getPrivate(), passwordChars);
                PKCS12PfxPdu caPfxPdu = KeyUtil.makePfx(caCertificate, caKeyPair.getPrivate(), passwordChars);
                saveCertificateFiles(saveDir, rsaIssuerCNField.getText(), caPrivateKeyInfo, caCertificate, caPfxPdu, passwordChars);
            }
        } catch (RuntimeException | IOException | GeneralSecurityException | OperatorCreationException | PKCSException ex) {
            JOptionPane.showMessageDialog(mainFrame, ex.getLocalizedMessage(), "錯誤提示", JOptionPane.ERROR_MESSAGE);
        }
    };
}
public static X509Certificate generateCertificate(String signatureAlgorithm, KeyPair keyPair, X500Name subject) throws OperatorCreationException, IOExcepti
    return generateCertificate(signatureAlgorithm, keyPair, subject, Duration.ofDays(365L * 10));
}

public static X509Certificate generateCertificate(String signatureAlgorithm, KeyPair keyPair, X500Name subject, Duration duration) throws OperatorCreationE
    ContentSigner contentSigner = makeContentSigner(signatureAlgorithm, keyPair.getPrivate());
    PKCS10CertificationRequest csr = generateCsr(contentSigner, keyPair, subject, true);
    BcX509ExtensionUtils extUtils = new BcX509ExtensionUtils();
    final Date notBefore = new Date();
    X509v3CertificateBuilder v3CertificateBuilder = new X509v3CertificateBuilder(
            csr.getSubject(),
            BigInteger.valueOf(UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE),
            notBefore,
            new Date(notBefore.getTime() + duration.toMillis()),
            Locale.CHINA,
            csr.getSubject(),
            csr.getSubjectPublicKeyInfo());
    v3CertificateBuilder.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));
    v3CertificateBuilder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign));
    v3CertificateBuilder.addExtension(Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(csr.getSubjectPublicKeyInfo()));
    v3CertificateBuilder.addExtension(Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(csr.getSubjectPublicKeyInfo()));
    return new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCertificate(v3CertificateBuilder.build(contentSigner));
}
public static PKCS8EncryptedPrivateKeyInfo makePKCS8EncryptedKey(PrivateKey privateKey, char[] passwordChars) {
    PKCS8EncryptedPrivateKeyInfoBuilder privateKeyInfoBuilder = new JcaPKCS8EncryptedPrivateKeyInfoBuilder(privateKey);
    return privateKeyInfoBuilder.build(new BcPKCS12PBEOutputEncryptorBuilder(
            PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC,
            new CBCBlockCipher(new DESedeEngine())).build(passwordChars));
}

public static PKCS12PfxPdu makePfx(X509Certificate x509Certificate, PrivateKey privateKey, char[] passwordChars) throws IOException, PKCSException {
    PKCS12SafeBagBuilder certBagBuilder = new JcaPKCS12SafeBagBuilder(x509Certificate);
    certBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Forge CA Certification"));
    certBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, ASN1Primitive.fromByteArray(x509Certificate.getExtensionValue(Extension.subjectKeyIdentifier.getId())));
    PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privateKey,
            new BcPKCS12PBEOutputEncryptorBuilder(
                    PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC,
                    new CBCBlockCipher(new DESedeEngine())).build(passwordChars));
    keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Forge CA Key"));
    keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, ASN1Primitive.fromByteArray(x509Certificate.getExtensionValue(Extension.subjectKeyIdentifier.getId())));
    PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder();
    PKCS12SafeBag[] certs = new PKCS12SafeBag[1];
    certs[0] = certBagBuilder.build();
    pfxPduBuilder.addEncryptedData(new BcPKCS12PBEOutputEncryptorBuilder(
                    PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC,
                    new CBCBlockCipher(new RC2Engine())).build(passwordChars),
            certs);
    pfxPduBuilder.addData(keyBagBuilder.build());
    return pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), passwordChars);
}

ECC根證書生成

略,與RSA大同小異。

0x09 小結

運行效果

基于Java Swing和BouncyCastle的證書生成工具

基于Java Swing和BouncyCastle的證書生成工具

基于Java Swing和BouncyCastle的證書生成工具

基于Java Swing和BouncyCastle的證書生成工具

基于Java Swing和BouncyCastle的證書生成工具

基于Java Swing和BouncyCastle的證書生成工具

基于Java Swing和BouncyCastle的證書生成工具

基于Java Swing和BouncyCastle的證書生成工具

基于Java Swing和BouncyCastle的證書生成工具

完成任務。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 99草视频| 亚洲精品人成网在线播放影院 | 性派对xxxhd| 免费黄色片在线观看 | avav一区| 色花堂国产精品首页第一页 | 大肥臀风间由美 中文字幕 大东北chinesexxxx露脸 | 99热最新| 女同久久另类99精品国产 | 国产haodiaose最新 | 不卡视频一区二区 | 成人毛片1024你懂的 | 国产精品女同久久免费观看 | 国产在线91 | 日本免费观看的视频在线 | 日本一卡2卡3卡4卡乱 | 国产小嫩模好紧 | 国产午夜一区二区在线观看 | 波多野结衣在线观看视频 | 好紧好爽再叫浪一点点潘金莲 | 乌克兰呦12~14 | chanelpreston欧美网站 | 亚洲不卡视频 | 韩国免费视频 | www.一区二区三区.com | 国产成人www免费人成看片 | 日本最大的黄色网站 | 美女在尿口隐私视频 | 按摩院已婚妇女中文字幕 | 久久毛片视频 | 插插好爽爽爽 | 男人天堂资源网 | 日韩毛片基地一区二区三区 | 韩国最新理论片奇忧影院 | 美女机机对机机的视频(免费) | 成年看片免费高清观看 | 日日操综合 | 大jjjj免费看视频 | 欧式午夜理伦三级在线观看 | 消息称老熟妇乱视频一区二区 | 亚洲 综合 欧美在线视频 |