`

Java实现数字证书生成签名

    博客分类:
  • java
阅读更多
package com.ylsoft.cert;  
  
import java.io.File;  
import java.io.FileInputStream;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.security.InvalidKeyException;  
import java.security.KeyPair;  
import java.security.KeyPairGenerator;  
import java.security.KeyStore;  
import java.security.KeyStoreException;  
import java.security.NoSuchAlgorithmException;  
import java.security.NoSuchProviderException;  
import java.security.PrivateKey;  
import java.security.SecureRandom;  
import java.security.Signature;  
import java.security.SignatureException;  
import java.security.UnrecoverableKeyException;  
import java.security.cert.Certificate;  
import java.security.cert.CertificateException;  
import java.security.cert.X509Certificate;  
import java.util.Date;  
import java.util.Vector;  
  
import sun.misc.BASE64Encoder;  
import sun.security.util.ObjectIdentifier;  
import sun.security.x509.AlgorithmId;  
import sun.security.x509.CertAndKeyGen;  
import sun.security.x509.CertificateAlgorithmId;  
import sun.security.x509.CertificateExtensions;  
import sun.security.x509.CertificateSerialNumber;  
import sun.security.x509.CertificateValidity;  
import sun.security.x509.CertificateVersion;  
import sun.security.x509.CertificateX509Key;  
import sun.security.x509.ExtendedKeyUsageExtension;  
import sun.security.x509.Extension;  
import sun.security.x509.KeyIdentifier;  
import sun.security.x509.KeyUsageExtension;  
import sun.security.x509.SubjectKeyIdentifierExtension;  
import sun.security.x509.X500Name;  
import sun.security.x509.X500Signer;  
import sun.security.x509.X509CertImpl;  
import sun.security.x509.X509CertInfo;  
  
/** 
 * 首先生成CA的根证书,然后有CA的根证书签署生成ScriptX的证书 
 *  
 * @author Administrator 
 *  
 */  
public class GenX509Cert {  
    /** 提供强加密随机数生成器 (RNG)* */  
    private SecureRandom sr;  
  
    public GenX509Cert() throws NoSuchAlgorithmException,  
            NoSuchProviderException {  
        // 返回实现指定随机数生成器 (RNG) 算法的 SecureRandom 对象。  
        sr = SecureRandom.getInstance("SHA1PRNG", "SUN");  
    }  
  
    public void createCert(X509Certificate certificate, PrivateKey rootPrivKey,  
            KeyPair kp) throws CertificateException, IOException,  
            InvalidKeyException, NoSuchAlgorithmException,  
            NoSuchProviderException, SignatureException {  
  
        // X.509 v1 证书的抽象类。此类提供了一种访问 X.509 v1 证书所有属性的标准方式。  
        byte certbytes[] = certificate.getEncoded();  
  
        // The X509CertImpl class represents an X.509 certificate.  
        X509CertImpl x509certimpl = new X509CertImpl(certbytes);  
  
        // The X509CertInfo class represents X.509 certificate information.  
        X509CertInfo x509certinfo = (X509CertInfo) x509certimpl  
                .get("x509.info");  
  
        // This class defines the X509Key attribute for the Certificate.  
        x509certinfo.set("key", new CertificateX509Key(kp.getPublic()));  
  
        // This class defines the Extensions attribute for the Certificate  
        CertificateExtensions certificateextensions = new CertificateExtensions();  
  
        certificateextensions.set("SubjectKeyIdentifier",  
                new SubjectKeyIdentifierExtension((new KeyIdentifier(kp  
                        .getPublic())).getIdentifier()));  
  
        x509certinfo.set("extensions", certificateextensions);  
  
        // 设置issuer域  
        X500Name issuer = new X500Name(  
                "CN=RootCA,OU=hackwp,O=wp,L=BJ,S=BJ,C=CN");  
        x509certinfo.set("issuer.dname", issuer);  
  
        // Constructs a name from a conventionally formatted string, such as  
        // "CN=Dave, OU=JavaSoft, O=Sun Microsystems, C=US". (RFC 1779 or RFC  
        // 2253 style).  
        X500Name subject = new X500Name(  
                "CN=scriptx, OU=wps, O=wps, L=BJ, ST=BJ, C=CN");  
  
        x509certinfo.set("subject.dname", subject);  
  
        // 此 Signature 类用来为应用程序提供数字签名算法功能。返回实现指定签名算法的 Signature 对象。  
        Signature signature = Signature.getInstance("MD5WithRSA");  
  
        // 初始化这个用于签名的对象。如果使用其他参数再次调用此方法,此调用的结果将无效。  
        signature.initSign(kp.getPrivate());  
  
        // This class provides a binding between a Signature object and an  
        // authenticated X.500 name (from an X.509 certificate chain), which is  
        // needed in many public key signing applications.  
        X500Signer signer = new X500Signer(signature, issuer);  
  
        // This class identifies algorithms, such as cryptographic transforms,  
        // each of which may be associated with parameters.  
        AlgorithmId algorithmid = signer.getAlgorithmId();  
  
        // This class defines the AlgorithmId for the Certificate.  
        x509certinfo  
                .set("algorithmID", new CertificateAlgorithmId(algorithmid));  
  
        // 开始时间  
        Date bdate = new Date();  
  
        // 结束时间  
        Date edate = new Date();  
  
        // 天 小时 分 秒 毫秒  
        edate.setTime(bdate.getTime() + 3650 * 24L * 60L * 60L * 1000L);  
  
        // validity为有效时间长度 单位为秒,This class defines the interval for which the  
        // certificate is valid.证书的有效时间  
        CertificateValidity certificatevalidity = new CertificateValidity(  
                bdate, edate);  
  
        x509certinfo.set("validity", certificatevalidity);  
  
        // This class defines the SerialNumber attribute for the Certificate.  
        // 设置有效期域(包含开始时间和到期时间)域名等同与x509certinfo.VALIDITY  
        x509certinfo.set("serialNumber", new CertificateSerialNumber(  
                (int) (new Date().getTime() / 1000L)));  
  
        // 设置序列号域,This class defines the version of the X509 Certificate.  
        CertificateVersion cv = new CertificateVersion(CertificateVersion.V3);  
  
        x509certinfo.set(X509CertInfo.VERSION, cv);  
  
        // 设置版本号 只有v1 ,v2,v3这几个合法值  
        /** 
         * 以上是证书的基本信息 如果要添加用户扩展信息 则比较麻烦 首先要确定version必须是v3否则不行 然后按照以下步骤 
         */  
        ObjectIdentifier oid = new ObjectIdentifier(new int[] { 2, 5, 29, 15 });  
  
        // 生成扩展域的id 是个int数组 第1位最大2 第2位最大39 最多可以几位不明....  
        String userData = "Digital Signature, Non-Repudiation, Key Encipherment, Data Encipherment (f0)";  
  
        byte l = (byte) userData.length();// 数据总长17位  
  
        byte f = 0x04;  
  
        byte[] bs = new byte[userData.length() + 2];  
  
        bs[0] = f;  
  
        bs[1] = l;  
  
        for (int i = 2; i < bs.length; i++) {  
            bs[i] = (byte) userData.charAt(i - 2);  
        }  
  
        Extension ext = new Extension(oid, true, bs);  
  
        // 生成一个extension对象 参数分别为 oid,是否关键扩展,byte[]型的内容值  
        // 其中内容的格式比较怪异 第一位是flag 这里取4暂时没出错 估计用来说明数据的用处的 第2位是后面的实际数据的长度,然后就是数据  
        // 密钥用法  
        KeyUsageExtension keyUsage = new KeyUsageExtension();  
  
        keyUsage.set(KeyUsageExtension.DIGITAL_SIGNATURE, true);  
  
        keyUsage.set(KeyUsageExtension.NON_REPUDIATION, true);  
  
        keyUsage.set(KeyUsageExtension.KEY_ENCIPHERMENT, true);  
  
        keyUsage.set(KeyUsageExtension.DATA_ENCIPHERMENT, true);  
  
        // 增强密钥用法  
        ObjectIdentifier ekeyOid = new ObjectIdentifier(new int[] { 1, 3, 6, 1,  
                5, 5, 7, 3, 3 });  
  
        Vector<ObjectIdentifier> vkeyOid = new Vector<ObjectIdentifier>();  
  
        vkeyOid.add(ekeyOid);  
  
        ExtendedKeyUsageExtension exKeyUsage = new ExtendedKeyUsageExtension(  
                vkeyOid);  
  
        CertificateExtensions exts = new CertificateExtensions();  
  
        exts.set("keyUsage", keyUsage);  
  
        exts.set("extendedKeyUsage", exKeyUsage);  
  
        // 如果有多个extension则都放入CertificateExtensions 类中,  
        x509certinfo.set(X509CertInfo.EXTENSIONS, exts);  
        // 设置extensions域  
  
        X509CertImpl x509certimpl1 = new X509CertImpl(x509certinfo);  
  
        x509certimpl1.sign(rootPrivKey, "MD5WithRSA");  
        // 使用另一个证书的私钥来签名此证书 这里使用 md5散列 用rsa来加密  
  
        BASE64Encoder base64 = new BASE64Encoder();  
  
        FileOutputStream fos = new FileOutputStream(new File("f:\\ScriptX.crt"));  
  
        base64.encodeBuffer(x509certimpl1.getEncoded(), fos);  
  
        try {  
            Certificate[] certChain = { x509certimpl1 };  
  
            savePfx("scriptx", kp.getPrivate(), "123456", certChain,  
                    "f:\\ScriptX.pfx");  
  
            FileInputStream in = new FileInputStream("F:\\ScriptX.pfx");  
  
            KeyStore inputKeyStore = KeyStore.getInstance("pkcs12");  
  
            inputKeyStore.load(in, "123456".toCharArray());  
  
            Certificate cert = inputKeyStore.getCertificate("scriptx");  
  
            System.out.print(cert.getPublicKey());  
  
            PrivateKey privk = (PrivateKey) inputKeyStore.getKey("scriptx",  
                    "123456".toCharArray());  
  
            FileOutputStream privKfos = new FileOutputStream(new File(  
                    "f:\\ScriptX.pvk"));  
  
            privKfos.write(privk.getEncoded());  
  
            System.out.print(privk);  
            // base64.encode(key.getEncoded(), privKfos);  
  
            in.close();  
  
        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
  
        // 生成文件  
        x509certimpl1.verify(certificate.getPublicKey(), null);  
  
    }  
  
    /** 
     * 保存此根证书信息KeyStore Personal Information Exchange 
     *  
     * @param alias 
     * @param privKey 
     * @param pwd 
     * @param certChain 
     * @param filepath 
     * @throws Exception 
     */  
    public void savePfx(String alias, PrivateKey privKey, String pwd,  
            Certificate[] certChain, String filepath) throws Exception {  
        // 此类表示密钥和证书的存储设施。  
        // 返回指定类型的 keystore 对象。此方法从首选 Provider 开始遍历已注册安全提供者列表。返回一个封装 KeyStoreSpi  
        // 实现的新 KeyStore 对象,该实现取自第一个支持指定类型的 Provider。  
        KeyStore outputKeyStore = KeyStore.getInstance("pkcs12");  
  
        System.out.println("KeyStore类型:" + outputKeyStore.getType());  
  
        // 从给定输入流中加载此 KeyStore。可以给定一个密码来解锁 keystore(例如,驻留在硬件标记设备上的 keystore)或检验  
        // keystore 数据的完整性。如果没有指定用于完整性检验的密码,则不会执行完整性检验。如果要创建空  
        // keystore,或者不能从流中初始化 keystore,则传递 null 作为 stream 的参数。注意,如果此 keystore  
        // 已经被加载,那么它将被重新初始化,并再次从给定输入流中加载。  
        outputKeyStore.load(null, pwd.toCharArray());  
  
        // 将给定密钥(已经被保护)分配给给定别名。如果受保护密钥的类型为  
        // java.security.PrivateKey,则它必须附带证明相应公钥的证书链。如果底层 keystore 实现的类型为  
        // jks,则必须根据 PKCS #8 标准中的定义将 key 编码为  
        // EncryptedPrivateKeyInfo。如果给定别名已经存在,则与别名关联的 keystore  
        // 信息将被给定密钥(还可能包括证书链)重写。  
        outputKeyStore  
                .setKeyEntry(alias, privKey, pwd.toCharArray(), certChain);  
  
        // KeyStore.PrivateKeyEntry pke=new  
        // KeyStore.PrivateKeyEntry(kp.getPrivate(),certChain);  
        // KeyStore.PasswordProtection password=new  
        // KeyStore.PasswordProtection("123456".toCharArray());  
        // outputKeyStore.setEntry("scriptx", pke, password);  
  
        FileOutputStream out = new FileOutputStream(filepath);  
  
        // 将此 keystore 存储到给定输出流,并用给定密码保护其完整性。  
        outputKeyStore.store(out, pwd.toCharArray());  
  
        out.close();  
    }  
  
    public void saveJks(String alias, PrivateKey privKey, String pwd,  
            Certificate[] certChain, String filepath) throws Exception {  
  
        KeyStore outputKeyStore = KeyStore.getInstance("jks");  
  
        System.out.println(outputKeyStore.getType());  
  
        outputKeyStore.load(null, pwd.toCharArray());  
  
        outputKeyStore  
                .setKeyEntry(alias, privKey, pwd.toCharArray(), certChain);  
  
        // KeyStore.PrivateKeyEntry pke=new  
        // KeyStore.PrivateKeyEntry(kp.getPrivate(),certChain);  
        // KeyStore.PasswordProtection password=new  
        // KeyStore.PasswordProtection("123456".toCharArray());  
        // outputKeyStore.setEntry("scriptx", pke, password);  
  
        FileOutputStream out = new FileOutputStream(filepath);  
  
        outputKeyStore.store(out, pwd.toCharArray());  
  
        out.close();  
    }  
  
    /** 
     * 颁布根证书,自己作为CA 
     *  
     * @throws NoSuchAlgorithmException 
     * @throws NoSuchProviderException 
     * @throws InvalidKeyException 
     * @throws IOException 
     * @throws CertificateException 
     * @throws SignatureException 
     * @throws UnrecoverableKeyException 
     */  
    public void createRootCA() throws NoSuchAlgorithmException,  
            NoSuchProviderException, InvalidKeyException, IOException,  
            CertificateException, SignatureException, UnrecoverableKeyException {  
  
        // 参数分别为公钥算法、签名算法 providername(因为不知道确切的 只好使用null 既使用默认的provider)  
        // Generate a pair of keys, and provide access to them.  
        CertAndKeyGen cak = new CertAndKeyGen("RSA", "MD5WithRSA", null);  
  
        // Sets the source of random numbers used when generating keys.  
        cak.setRandom(sr);  
  
        // Generates a random public/private key pair, with a given key size.  
        cak.generate(1024);  
  
        // Constructs a name from a conventionally formatted string, such as  
        // "CN=Dave, OU=JavaSoft, O=Sun Microsystems, C=US". (RFC 1779 or RFC  
        // 2253 style)  
        X500Name subject = new X500Name(  
                "CN=RootCA,OU=hackwp,O=wp,L=BJ,S=BJ,C=CN");  
  
        // Returns a self-signed X.509v3 certificate for the public key. The  
        // certificate is immediately valid. No extensions.  
        // Such certificates normally are used to identify a "Certificate  
        // Authority" (CA). Accordingly, they will not always be accepted by  
        // other parties. However, such certificates are also useful when you  
        // are bootstrapping your security infrastructure, or deploying system  
        // prototypes.自签名的根证书  
        X509Certificate certificate = cak.getSelfCertificate(subject,  
                new Date(), 3650 * 24L * 60L * 60L);  
  
        X509Certificate[] certs = { certificate };  
  
        try {  
  
            savePfx("RootCA", cak.getPrivateKey(), "123456", certs,  
                    "f:\\RootCa.pfx");  
  
        } catch (Exception e) {  
  
            e.printStackTrace();  
  
        }  
  
        // 后一个long型参数代表从现在开始的有效期 单位为秒(如果不想从现在开始算 可以在后面改这个域)  
        BASE64Encoder base64 = new BASE64Encoder();  
  
        FileOutputStream fos = new FileOutputStream(new File("f:\\RootCa.crt"));  
  
        // fos.write(certificate.getEncoded());  
  
        // 生成(保存)cert文件 base64加密 当然也可以不加密  
        base64.encodeBuffer(certificate.getEncoded(), fos);  
  
        fos.close();  
  
    }  
  
    public void signCert() throws NoSuchAlgorithmException,  
            CertificateException, IOException, UnrecoverableKeyException,  
            InvalidKeyException, NoSuchProviderException, SignatureException {  
  
        try {  
  
            KeyStore ks = KeyStore.getInstance("pkcs12");  
  
            FileInputStream ksfis = new FileInputStream("f:\\RootCa.pfx");  
  
            char[] storePwd = "123456".toCharArray();  
  
            char[] keyPwd = "123456".toCharArray();  
  
            // 从给定输入流中加载此 KeyStore。  
            ks.load(ksfis, storePwd);  
  
            ksfis.close();  
  
            // 返回与给定别名关联的密钥(私钥),并用给定密码来恢复它。必须已经通过调用 setKeyEntry,或者以  
            // PrivateKeyEntry  
            // 或 SecretKeyEntry 为参数的 setEntry 关联密钥与别名。  
            PrivateKey privK = (PrivateKey) ks.getKey("RootCA", keyPwd);  
  
            // 返回与给定别名关联的证书。如果给定的别名标识通过调用 setCertificateEntry 创建的条目,或者通过调用以  
            // TrustedCertificateEntry 为参数的 setEntry  
            // 创建的条目,则返回包含在该条目中的可信证书。如果给定的别名标识通过调用 setKeyEntry 创建的条目,或者通过调用以  
            // PrivateKeyEntry 为参数的 setEntry 创建的条目,则返回该条目中证书链的第一个元素。  
            X509Certificate certificate = (X509Certificate) ks  
                    .getCertificate("RootCA");  
  
            createCert(certificate, privK, genKey());  
  
        } catch (KeyStoreException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
    }  
  
    public KeyPair genKey() throws NoSuchAlgorithmException {  
  
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");  
  
        kpg.initialize(1024, sr);  
  
        System.out.print(kpg.getAlgorithm());  
  
        KeyPair kp = kpg.generateKeyPair();  
  
        return kp;  
    }  
  
    public static void main(String[] args) {  
  
        try {  
  
            GenX509Cert gcert = new GenX509Cert();  
  
            gcert.createRootCA();  
  
            gcert.signCert();  
  
        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
    }  
}  

 

分享到:
评论

相关推荐

    纯Java实现数字证书生成签名的简单实例

    在本文中,我们将深入探讨如何使用Java来实现数字证书生成签名的简单实例。数字签名证书在信息安全领域扮演着至关重要的角色,它确保了数据的完整性和发送者的身份验证。Java平台提供了一套丰富的API,使得开发者...

    java代码生成数字证书

    Java代码生成数字证书涉及到几个关键概念和技术,包括Java的密钥和证书管理、RSA加密算法以及非交互式证书创建。在此,我们将深入探讨这些主题,以便理解如何在Java环境中生成和使用数字证书。 1. **数字证书**:...

    Java 数字签名、数字证书生成源码.zip

    这份"Java 数字签名、数字证书生成源码"的压缩包提供了实现这些功能的代码示例,对于理解和应用Java安全机制非常有帮助。 数字签名是一种用于验证电子信息完整性和发送者身份的技术。它结合了非对称加密算法(如RSA...

    Java实现浏览器CA证书的签名和验证

    在Java中,可以使用keytool工具来生成自签名证书,或者生成CSR(证书签名请求)提交给CA机构获得正规的数字证书。在实现数字证书的签名和验证过程中,Java提供了一系列用于操作X.509证书的API,如java.security.cert...

    java 国密算法实现包含SM2 SM3 SM4和数字签名、数字证书的验证

    下面将详细介绍这些算法以及它们在Java中的实现,以及如何进行数字签名和数字证书的验证。 1. **SM2算法**:SM2是一种基于椭圆曲线密码学(ECC)的公钥加密算法,用于非对称加密。它提供了密钥交换、签名和验证的...

    Java 数字签名、数字证书生成源码.rar

    本资源包含的Java代码工具包提供了生成数字签名和数字证书的源码,这有助于开发者快速理解和实现相关功能。 首先,让我们了解一下数字签名。数字签名是一种用于验证电子文档完整性和发送者身份的技术。它利用非对称...

    java 实现数字证书的操作实现网络安全

    下面将详细阐述如何在Java中实现数字证书的创建、查看、PIN码修改、导入导出以及删除,并探讨服务器端验证用户权限的过程。 1. **数字证书创建(初始化)**: 创建数字证书通常涉及生成一对密钥——公钥和私钥。...

    Java 数字签名、数字证书生成源码.7z

    在这个"Java 数字签名、数字证书生成源码"压缩包中,包含了实现这些功能的源代码,对于理解Java安全编程和实际应用具有很高的价值。 1. **数字签名** 数字签名是一种用于验证电子文档完整性和发送者身份的技术。在...

    Java实现RSA加密解密,数字证书生成与验证

    Java实现RSA加密解密,数字证书生成与验证,模拟两个端通信,AB双方通信,客户端A把需要传输的文件MD5值用自己的私钥生成数字签名,连同明文用服务端B的公钥加密后传送给服务端B,服务端B用私钥解密验证数字签名,并计算...

    Certificate_java_java数字签名_java签名证书_数字证书_

    总之,Java数字证书和数字签名是构建安全网络应用的核心技术,这个源码模块提供了一种实际的实现方式,可以帮助开发者更好地理解和应用这些概念。通过深入学习和实践,你可以提升在网络安全领域的专业技能,为构建更...

    Java 数字签名、数字证书生成源码

    在这个Java源码包中,我们可能找到了用于生成数字签名和数字证书的相关代码,这对于理解和实践Java的安全编程至关重要。 数字签名是一种用于验证电子信息完整性的方法,它结合了非对称加密技术。在Java中,我们可以...

    java获取数字证书信息

    ### Java 获取数字证书信息 在本篇文章中,我们将深入探讨如何使用Java来获取数字证书的信息,包括使用TOMCAT和JDK搭建SSL服务的过程、如何用OpenSSL签发证书以及如何支持第三方CA等内容。 #### 一、使用TOMCAT和...

    JAVA源码Java数字签名,数字证书生成源码

    JAVA源码Java数字签名,数字证书生成源码

    java数字签名(签名生成,用证书验证签名)[汇编].pdf

    java数字签名(签名生成,用证书验证签名)[汇编].pdf

    java源码资源Java 数字签名、数字证书生成源码

    java源码资源Java 数字签名、数字证书生成源码提取方式是百度网盘分享地址

    java生成及验证android签名文件源码及生成签名文件

    本文将深入探讨Java如何生成及验证Android签名文件,并解析源码中的相关概念。 首先,让我们理解Android签名文件的核心作用。Android签名文件(通常为`.keystore`格式)是一个包含了应用开发者私钥的加密文件,用于...

    java源码:Java 数字签名、数字证书生成源码.rar

    在实际应用中,这些源码示例可能包括了生成和验证数字签名以及数字证书的具体代码,对于学习和理解Java安全机制非常有帮助。通过阅读和运行这些源码,开发者可以更好地掌握如何在实际项目中应用这些安全功能。 总之...

Global site tag (gtag.js) - Google Analytics