程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 純Java完成數字證墨客成簽名的簡略實例

純Java完成數字證墨客成簽名的簡略實例

編輯:關於JAVA

純Java完成數字證墨客成簽名的簡略實例。本站提示廣大學習愛好者:(純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完成數字證墨客成簽名的簡略實例就是小編分享給年夜家的全體內容了,願望能給年夜家一個參考,也願望年夜家多多支撐。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved