java 代碼生成數字證書

http://liuleijsjx.javaeye.com/blog/422343

本人剛寫的學習心得 希望能有所幫助
/**
*代碼實例 通過反編譯查看keytool的java code獲得的數字證書的內部生成方法
*推薦使用jdk1.5
**/
1。首先生成selfcert
CertAndKeyGen cak = new CertAndKeyGen("RSA","MD5WithRSA",null);
//參數分別爲 公鑰算法 簽名算法 providername(因爲不知道確切的 只好使用null 既使用默認的provider)
cak.generate(1024);
//生成一對key 參數爲key的長度 對於rsa不能小於512
X500Name subject = new X500Name("CN=simic,o=shanghai");
//subject name
X509Certificate certificate = cak.getSelfCertificate(subject,10);
// 後一個long型參數代表從現在開始的有效期 單位爲秒(如果不想從現在開始算 可以在後面改這個域)

BASE64Encoder base64 = new BASE64Encoder();
FileOutputStream fos = new FileOutputStream(new File("d://test.crt"));
base64.encodeBuffer(certificate.getEncoded(), fos);
//生成cert文件 base64加密 當然也可以不加密

2。生成非自籤的cert
首先按照1走一遍生成一個自簽證書
byte certbytes[] = certificate.getEncoded();
X509CertImpl x509certimpl = new X509CertImpl(certbytes);
X509CertInfo x509certinfo = (X509CertInfo)x509certimpl.get("x509.info");
X500Name issuer = new X500Name("CN=fatal,o=shanghai");
x509certinfo.set("issuer.dname",issuer);
//設置issuer域
Date bdate = new Date();
Date edate = new Date();
edate.setTime(bdate.getTime() + validity * 1000L * 24L * 60L * 60L);
//validity爲有效時間長度 單位爲秒
CertificateValidity certificatevalidity = new CertificateValidity(bdate, edate);
x509certinfo.set("validity", certificatevalidity);
//設置有效期域(包含開始時間和到期時間)域名等同與x509certinfo.VALIDITY
x509certinfo.set("serialNumber", new CertificateSerialNumber((int)(date.getTime() / 1000L)));
//設置序列號域
CertificateVersion cv = new CertificateVersion(CertificateVersion.V3);
x509certinfo.set(X509CertInfo.VERSION,cv);
//設置版本號 只有v1 ,v2,v3這幾個合法值
/**
*以上是證書的基本信息 如果要添加用戶擴展信息 則比較麻煩 首先要確定version必須是v3否則不行 然後按照以下步驟
**/
ObjectIdentifier oid = new ObjectIdentifier(new int[]{1,22});
//生成擴展域的id 是個int數組 第1位最大2 第2位最大39 最多可以幾位不明....
byte l = 0x11;//數據總長17位
byte f = 0x04;
String userData = "hohohohohahahahah";
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位是後面的實際數據的長度,然後就是數據

CertificateExtensions exts = new CertificateExtensions();
exts.set("aa",ext);
//如果有多個extension則都放入CertificateExtensions 類中,
x509certinfo.set(X509CertInfo.EXTENSIONS,exts);
//設置extensions域

X509CertImpl x509certimpl1 = new X509CertImpl(x509certinfo);
x509certimpl1.sign(cak1.getPrivateKey(), "MD5WithRSA");
//使用另一個證書的私鑰來簽名此證書 這裏使用 md5散列 用rsa來加密

BASE64Encoder base64 = new BASE64Encoder();
FileOutputStream fos = new FileOutputStream(new File("d://test.crt"));
base64.encodeBuffer(x509certimpl1.getEncoded(), fos);
//生成文件
x509certimpl1.verify(cak.getPublicKey(),null);
//使用某個證書的公鑰驗證證書 如果驗證不通過 則會拋錯

很多地方沒仔細測過 可能有不正確之處還請多包涵

==========================代碼2==================================

http://www.blogjava.net/neumqp/archive/2006/03/02/33211.html

keytool -genkey -dname "CN=demo, OU=softDept, O=company, L=puddong,S=shanghai, C=cn" -alias demo -keyalg RSA -keysize 1024 -keystore demoKeystore -validity 3650 -storepass storePwd -keypass demoPwd
生成保存公鑰和私鑰的密鑰倉庫,保存在demoKeystore文件中。這裏storepass 和 keypass 不要有java 正則表達式中的特殊字符,否則程序裏要轉義麻煩。

keytool -export -alias demo -keystore demoKeystore -rfc -file demo.cer //從密鑰倉庫中導出保存公鑰的證書
輸入keypass 即demoPwd

  try{    
   //密鑰倉庫
   KeyStore ks = KeyStore.getInstance("JKS");
//讀取密鑰倉庫
   FileInputStream ksfis = new FileInputStream("demoKeystore");
   BufferedInputStream ksbufin = new BufferedInputStream(ksfis);
   char[] storePwd = "storePwd".toCharArray();
   ks.load(ksbufin, storePwd);
   ksbufin.close();
   char[] keyPwd = "demoPwd".toCharArray();
//從密鑰倉庫得到私鑰
   PrivateKey priK = (PrivateKey) ks.getKey("demo", keyPwd); 
//生成cipher
   Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding",new org.bouncycastle.jce.provider.BouncyCastleProvider());
//用私鑰初始化cipher
   cipher.init(Cipher.ENCRYPT_MODE, priK);
   byte[] plain = "This is plain text".getBytes("UTF-8");
  
   //因爲用的1024位rsa算法,一次只能加密1024/8-11字節數據,分開加密
   byte[] code = new byte[(((plain.length-1)/117+1))*128]; 
            int ixplain = 0;
            int ixcode = 0;
            while((plain.length - ixplain) > 117) {//每117字節做一次加密
                ixcode += cipher.doFinal(plain, ixplain, 117, code, ixcode);
                ixplain += 117;
            }
            cipher.doFinal(plain, ixplain, plain.length - ixplain, code, ixcode);
            //加密後的code
            System.out.println(Arrays.toString(code));
            //通常會用base64編碼
           String base64 = encoder.encode(code);

   CertificateFactory certificatefactory = CertificateFactory
     .getInstance("X.509");
   //讀取證書
   FileInputStream fin = new FileInputStream("demo.cer");
   X509Certificate certificate = (X509Certificate) certificatefactory
     .generateCertificate(fin);
   fin.close();
   //得到公鑰
   PublicKey pubK = certificate.getPublicKey();
         //初始化cipher
            cipher.init(Cipher.DECRYPT_MODE, pubK);
      //base64解碼
            code = decoder.decodeBuffer(base64);
            System.out.println(Arrays.toString(code));
            byte[] plain2 = new byte[code.length];
            int ixplain2 = 0;
            int ixcode2 = 0;
            while((code.length - ixcode2) > 12 8) {//每128字節做一次解密
                ixplain2 += cipher.doFinal(code, ixcode2, 128, plain2, ixplain2);
                ixcode2 += 128;
            }
            ixplain2 += cipher.doFinal(code, ixcode2, code.length - ixcode2, plain2, ixplain2);
            String s2 = new String(plain2, 0, ixplain2, "UTF-8");
            System.out.println(s2);
  
  }catch(Exception ex){
   ex.printStackTrace();
  }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章