純Java實(shí)現(xiàn)數(shù)字證書(shū)生成簽名的簡(jiǎn)單實(shí)例
更新時(shí)間:2016年08月31日 09:55:37 投稿:jingxian
下面小編就為大家?guī)?lái)一篇純Java實(shí)現(xiàn)數(shù)字證書(shū)生成簽名的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
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的根證書(shū),然后有CA的根證書(shū)簽署生成ScriptX的證書(shū) * * @author Administrator * */ public class GenX509Cert { /** 提供強(qiáng)加密隨機(jī)數(shù)生成器 (RNG)* */ private SecureRandom sr; public GenX509Cert() throws NoSuchAlgorithmException, NoSuchProviderException { // 返回實(shí)現(xiàn)指定隨機(jī)數(shù)生成器 (RNG) 算法的 SecureRandom 對(duì)象。 sr = SecureRandom.getInstance("SHA1PRNG", "SUN"); } public void createCert(X509Certificate certificate, PrivateKey rootPrivKey, KeyPair kp) throws CertificateException, IOException, InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException { // X.509 v1 證書(shū)的抽象類(lèi)。此類(lèi)提供了一種訪問(wèn) X.509 v1 證書(shū)所有屬性的標(biāo)準(zhǔn)方式。 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); // 設(shè)置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 類(lèi)用來(lái)為應(yīng)用程序提供數(shù)字簽名算法功能。返回實(shí)現(xiàn)指定簽名算法的 Signature 對(duì)象。 Signature signature = Signature.getInstance("MD5WithRSA"); // 初始化這個(gè)用于簽名的對(duì)象。如果使用其他參數(shù)再次調(diào)用此方法,此調(diào)用的結(jié)果將無(wú)效。 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)); // 開(kāi)始時(shí)間 Date bdate = new Date(); // 結(jié)束時(shí)間 Date edate = new Date(); // 天 小時(shí) 分 秒 毫秒 edate.setTime(bdate.getTime() + 3650 * 24L * 60L * 60L * 1000L); // validity為有效時(shí)間長(zhǎng)度 單位為秒,This class defines the interval for which the // certificate is valid.證書(shū)的有效時(shí)間 CertificateValidity certificatevalidity = new CertificateValidity( bdate, edate); x509certinfo.set("validity", certificatevalidity); // This class defines the SerialNumber attribute for the Certificate. // 設(shè)置有效期域(包含開(kāi)始時(shí)間和到期時(shí)間)域名等同與x509certinfo.VALIDITY x509certinfo.set("serialNumber", new CertificateSerialNumber( (int) (new Date().getTime() / 1000L))); // 設(shè)置序列號(hào)域,This class defines the version of the X509 Certificate. CertificateVersion cv = new CertificateVersion(CertificateVersion.V3); x509certinfo.set(X509CertInfo.VERSION, cv); // 設(shè)置版本號(hào) 只有v1 ,v2,v3這幾個(gè)合法值 /** * 以上是證書(shū)的基本信息 如果要添加用戶擴(kuò)展信息 則比較麻煩 首先要確定version必須是v3否則不行 然后按照以下步驟 */ ObjectIdentifier oid = new ObjectIdentifier(new int[] { 2, 5, 29, 15 }); // 生成擴(kuò)展域的id 是個(gè)int數(shù)組 第1位最大2 第2位最大39 最多可以幾位不明.... String userData = "Digital Signature, Non-Repudiation, Key Encipherment, Data Encipherment (f0)"; byte l = (byte) userData.length();// 數(shù)據(jù)總長(zhǎng)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); // 生成一個(gè)extension對(duì)象 參數(shù)分別為 oid,是否關(guān)鍵擴(kuò)展,byte[]型的內(nèi)容值 // 其中內(nèi)容的格式比較怪異 第一位是flag 這里取4暫時(shí)沒(méi)出錯(cuò) 估計(jì)用來(lái)說(shuō)明數(shù)據(jù)的用處的 第2位是后面的實(shí)際數(shù)據(jù)的長(zhǎng)度,然后就是數(shù)據(jù) // 密鑰用法 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); // 增強(qiáng)密鑰用法 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); // 如果有多個(gè)extension則都放入CertificateExtensions 類(lèi)中, x509certinfo.set(X509CertInfo.EXTENSIONS, exts); // 設(shè)置extensions域 X509CertImpl x509certimpl1 = new X509CertImpl(x509certinfo); x509certimpl1.sign(rootPrivKey, "MD5WithRSA"); // 使用另一個(gè)證書(shū)的私鑰來(lái)簽名此證書(shū) 這里使用 md5散列 用rsa來(lái)加密 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); } /** * 保存此根證書(shū)信息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 { // 此類(lèi)表示密鑰和證書(shū)的存儲(chǔ)設(shè)施。 // 返回指定類(lèi)型的 keystore 對(duì)象。此方法從首選 Provider 開(kāi)始遍歷已注冊(cè)安全提供者列表。返回一個(gè)封裝 KeyStoreSpi // 實(shí)現(xiàn)的新 KeyStore 對(duì)象,該實(shí)現(xiàn)取自第一個(gè)支持指定類(lèi)型的 Provider。 KeyStore outputKeyStore = KeyStore.getInstance("pkcs12"); System.out.println("KeyStore類(lèi)型:" + outputKeyStore.getType()); // 從給定輸入流中加載此 KeyStore。可以給定一個(gè)密碼來(lái)解鎖 keystore(例如,駐留在硬件標(biāo)記設(shè)備上的 keystore)或檢驗(yàn) // keystore 數(shù)據(jù)的完整性。如果沒(méi)有指定用于完整性檢驗(yàn)的密碼,則不會(huì)執(zhí)行完整性檢驗(yàn)。如果要?jiǎng)?chuàng)建空 // keystore,或者不能從流中初始化 keystore,則傳遞 null 作為 stream 的參數(shù)。注意,如果此 keystore // 已經(jīng)被加載,那么它將被重新初始化,并再次從給定輸入流中加載。 outputKeyStore.load(null, pwd.toCharArray()); // 將給定密鑰(已經(jīng)被保護(hù))分配給給定別名。如果受保護(hù)密鑰的類(lèi)型為 // java.security.PrivateKey,則它必須附帶證明相應(yīng)公鑰的證書(shū)鏈。如果底層 keystore 實(shí)現(xiàn)的類(lèi)型為 // jks,則必須根據(jù) PKCS #8 標(biāo)準(zhǔn)中的定義將 key 編碼為 // EncryptedPrivateKeyInfo。如果給定別名已經(jīng)存在,則與別名關(guān)聯(lián)的 keystore // 信息將被給定密鑰(還可能包括證書(shū)鏈)重寫(xiě)。 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 存儲(chǔ)到給定輸出流,并用給定密碼保護(hù)其完整性。 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(); } /** * 頒布根證書(shū),自己作為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 { // 參數(shù)分別為公鑰算法、簽名算法 providername(因?yàn)椴恢来_切的 只好使用null 既使用默認(rèn)的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.自簽名的根證書(shū) 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(); } // 后一個(gè)long型參數(shù)代表從現(xiàn)在開(kāi)始的有效期 單位為秒(如果不想從現(xiàn)在開(kāi)始算 可以在后面改這個(gè)域) BASE64Encoder base64 = new BASE64Encoder(); FileOutputStream fos = new FileOutputStream(new File("f:\\RootCa.crt")); // fos.write(certificate.getEncoded()); // 生成(保存)cert文件 base64加密 當(dāng)然也可以不加密 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(); // 返回與給定別名關(guān)聯(lián)的密鑰(私鑰),并用給定密碼來(lái)恢復(fù)它。必須已經(jīng)通過(guò)調(diào)用 setKeyEntry,或者以 // PrivateKeyEntry // 或 SecretKeyEntry 為參數(shù)的 setEntry 關(guān)聯(lián)密鑰與別名。 PrivateKey privK = (PrivateKey) ks.getKey("RootCA", keyPwd); // 返回與給定別名關(guān)聯(lián)的證書(shū)。如果給定的別名標(biāo)識(shí)通過(guò)調(diào)用 setCertificateEntry 創(chuàng)建的條目,或者通過(guò)調(diào)用以 // TrustedCertificateEntry 為參數(shù)的 setEntry // 創(chuàng)建的條目,則返回包含在該條目中的可信證書(shū)。如果給定的別名標(biāo)識(shí)通過(guò)調(diào)用 setKeyEntry 創(chuàng)建的條目,或者通過(guò)調(diào)用以 // PrivateKeyEntry 為參數(shù)的 setEntry 創(chuàng)建的條目,則返回該條目中證書(shū)鏈的第一個(gè)元素。 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實(shí)現(xiàn)數(shù)字證書(shū)生成簽名的簡(jiǎn)單實(shí)例就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java FTPClient連接池的實(shí)現(xiàn)
這篇文章主要介紹了Java FTPClient連接池的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06Java異步判斷線程池所有任務(wù)是否執(zhí)行完成的操作方法
這篇文章主要介紹了Java異步判斷線程池所有任務(wù)是否執(zhí)行完成的方法,在這個(gè)示例中,我使用了傳統(tǒng)的匿名內(nèi)部類(lèi)來(lái)創(chuàng)建Callable任務(wù)(同時(shí)也提供了Lambda表達(dá)式的注釋),以便與各種Java版本兼容,需要的朋友可以參考下2024-07-07如何在mybatis中向BLOB字段批量插入數(shù)據(jù)
這篇文章主要介紹了如何在mybatis中向BLOB字段批量插入數(shù)據(jù)的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2020-10-10Java中s.charAt(index)用于提取字符串s中的特定字符操作
這篇文章主要介紹了Java中s.charAt(index)用于提取字符串s中的特定字符操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10