<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-17  評論-6  文章-1  trackbacks-0
     
    問:我源文件為main.c, x.c, y.c, z.c,頭文件為x.h,y.h,z.h
    如何編譯成.so動態庫?
    編譯器用gcc
    最好能給出詳細參數解釋,謝謝

    答:
    # 聲稱動代連接庫,假設名稱為libtest.so
    gcc x.c y.c z.c -fPIC -shared -o libtest.so

    # 將main.c和動態連接庫進行連接生成可執行文件
    gcc main.c -L. -ltest -o main

    # 輸出LD_LIBRARY_PATH環境變量,一邊動態庫裝載器能夠找到需要的動態庫
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.

    # 測試是否動態連接,如果列出libtest.so,那么應該是連接正常了
    ldd main

    # 執行就不用說了吧

    -fPIC:表示編譯為位置獨立的代碼,不用此選項的話編譯后的代碼是位置相關的所以動態載入時是通過代碼拷貝的方式來滿足不同進程的需要,而不能達到真正代碼段共享的目的。

    -L.:表示要連接的庫在當前目錄中

    -ltest:編譯器查找動態連接庫時有隱含的命名規則,即在給出的名字前面加上lib,后面加上.so來確定庫的名稱

    LD_LIBRARY_PATH:這個環境變量指示動態連接器可以裝載動態庫的路徑。
    當然如果有root權限的話,可以修改/etc/ld.so.conf文件,然后調用
    /sbin/ldconfig來達到同樣的目的,不過如果沒有root權限,那么只能采用輸出LD_LIBRARY_PATH的方法了。
    posted @ 2006-03-03 16:20 小鐵匠 閱讀(5131) | 評論 (0)編輯 收藏

    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) > 128) {//每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();
      }

    keytool使用方法可以參考jdk文檔
    Java keytool工具的作用及使用方法

    posted @ 2006-03-02 14:32 小鐵匠 閱讀(3430) | 評論 (0)編輯 收藏
    在c++中new的對象,如果不返回java,必須用release掉,否則內存泄露。包括NewStringUTF,NewObject
    。如果返回java不必release,java會自己回收。

     jstring jstr = env->NewStringUTF((*p).sess_id);
       ...
     env->DeleteLocalRef( jstr);

    jobject jobj = env->NewObject(clazz,midInit);
    return jobj;

    內存泄露可以先從windows資源管理器中,看到隨程序運行,內存不斷增長的趨勢,具體可以用hp jmeter檢測在運行程序時,加jvm參數 -Xrunhprof:heap=all,cutoff=0 ,生成java.hprof.txt,用jmeter打開,Metric -> Residual Objects (Count),可以看到未回收的對象,選中要查看的對象,點Mark記錄下要查看的對象,Window -> New Window 打開新窗口,用Metric -> Reference Graph Tree,然后點Find Immediately可以看到對象被哪里引用。


    找出內存泄漏另一方法

    程序有內存泄漏的第一個跡象通常是它拋出一個 OutOfMemoryError,或者因為頻繁的垃圾收集而表現出糟糕的性能。幸運的是,垃圾收集可以提供能夠用來診斷內存泄漏的大量信息。如果以 -verbose:gc 或者 -Xloggc 選項調用 JVM,那么每次 GC 運行時在控制臺上或者日志文件中會打印出一個診斷信息,包括它所花費的時間、當前堆使用情況以及恢復了多少內存。記錄 GC 使用情況并不具有干擾性,因此如果需要分析內存問題或者調優垃圾收集器,在生產環境中默認啟用 GC 日志是值得的。

    有工具可以利用 GC 日志輸出并以圖形方式將它顯示出來,JTune 就是這樣的一種工具(請參閱 參考資料)。觀察 GC 之后堆大小的圖,可以看到程序內存使用的趨勢。對于大多數程序來說,可以將內存使用分為兩部分:baseline 使用和 current load 使用。對于服務器應用程序,baseline 使用就是應用程序在沒有任何負荷、但是已經準備好接受請求時的內存使用,current load 使用是在處理請求過程中使用的、但是在請求處理完成后會釋放的內存。只要負荷大體上是恒定的,應用程序通常會很快達到一個穩定的內存使用水平。如果在應用程序已經完成了其初始化并且負荷沒有增加的情況下,內存使用持續增加,那么程序就可能在處理前面的請求時保留了生成的對象。


    圖 1 顯示  GC 之后應用程序堆大小隨著時間的變化圖。上升趨勢是存在內存泄漏的警示信號。(在真實的應用程序中,坡度不會這么大,但是在收集了足夠長時間的 GC 數據后,上升趨勢通常會表現得很明顯。)


    圖 1. 持續上升的內存使用趨勢

    確信有了內存泄漏后,下一步就是找出哪種對象造成了這個問題。所有內存分析器都可以生成按照對象類進行分解的堆快照。有一些很好的商業堆分析工具,但是找出內存泄漏不一定要花錢買這些工具 —— 內置的 hprof 工具也可完成這項工作。要使用 hprof 并讓它跟蹤內存使用,需要以 -Xrunhprof:heap=sites 選項調用 JVM。

    清單 3 顯示分解了應用程序內存使用的 hprof 輸出的相關部分。(hprof 工具在應用程序退出時,或者用 kill -3 或在 Windows 中按 Ctrl+Break 時生成使用分解。)注意兩次快照相比,Map.EntryTaskint[] 對象有了顯著增加。

    請參閱 清單 3

    清單 4 展示了 hprof 輸出的另一部分,給出了 Map.Entry 對象的分配點的調用堆棧信息。這個輸出告訴我們哪些調用鏈生成了 Map.Entry 對象,并帶有一些程序分析,找出內存泄漏來源一般來說是相當容易的。


    清單 4. HPROF 輸出,顯示 Map.Entry 對象的分配點
    
    
    TRACE 300446:
    	java.util.HashMap$Entry.<init>(<Unknown Source>:Unknown line)
    	java.util.HashMap.addEntry(<Unknown Source>:Unknown line)
    	java.util.HashMap.put(<Unknown Source>:Unknown line)
    	java.util.Collections$SynchronizedMap.put(<Unknown Source>:Unknown line)
    	com.quiotix.dummy.MapLeaker.newTask(MapLeaker.java:48)
    	com.quiotix.dummy.MapLeaker.main(MapLeaker.java:64)
    




    另外
    jstring jstr = (jstring)env->CallObjectMethod(authenRequest, mid_authenReq_getSdId_S);
     env->GetStringUTFRegion(jstr,0,env->GetStringLength(jstr),authenReq.sd_id);
    當jstr是null時,env->GetStringLength(jstr)會出錯,導致jvm崩潰
    posted @ 2006-03-02 11:23 小鐵匠 閱讀(4241) | 評論 (0)編輯 收藏
    HP-UX下使用JNI訪問標準C++程序

    問題的關鍵在于用aCC編譯時的參數
    根據HP網站上的兩篇文章可以很容易的使用JNI訪問傳統C++(Classical C++)程序
    http://www.hp.com/products1/unix/java/infolibrary/prog_guide/JNI_java2.html 
    http://forums1.itrc.hp.com/service/forums/questionanswer.do?admit=716493758+1092296929165+28353475&threadId=245738 
    但是,如果代碼中使用到了標準C++,也就是用到了STL,就會出現莫名其妙的JVM crash. 而且一般的現象是使用string的時候出錯

    最后發現是JVM的多線程機制和aCC編譯的缺省的多線程機制不一樣.所以編譯時需要加參數指定
    總的說來,編譯參數為
    OPTS=-AA +z +u4 -D_RWSTD_MULTI_THREAD -D_REENTRANT -D_HPUX -D_HPUX_SOURCE -D_POSIX_C_SOURCE=199506L -D_XOPEN_SOURCE_EXTENDED 

    其中,-D_RWSTD_MULTI_THREAD -D_REENTRANT 是指定多線程機制;同時必須添加-D_HPUX_SOURCE 參數,否則,編譯時會出現奇怪的錯誤
    連接參數為
    -AA -b -lCsup_v2 -lstd_v2 
    值得注意的是根據上面所說的第二篇文章可知使用-AA編譯連接時,要連的庫是libCsup_v2.sllibstd_v2.sl(這兩個庫是支持標準C++的庫),而不是第一篇文章中提到的libCsup.sllibstd.sl(這兩個庫是支持傳統C++的庫). 

    另外,有幾個碰到的問題
    1. 
    如果編譯參數沒有指定多線程機制,禁用JIT(啟動JVM加參數:-Djava.compiler=none -Xint )可以使簡單的例子通過,但是有些情況下還是會出錯

    2. 
    null作為String傳入JNI native接口代碼中是,使用env->GetStringUTFChars(jstring)會出現如下錯誤導致虛擬機崩潰
    Function=verify_instance_jfieldID__18jfieldIDWorkaroundSFP12klassOopDescP9_jfieldID 

    3. 
    在使用String作為JNI的傳入傳出參數,使用GetStringUTFChars解決不了中文問題,還是會有亂碼正確的解決方法是使用以下兩個函數
    void JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg) 

        jclass cls = env->FindClass(name); 
        /* if cls is NULL, an exception has already been thrown */ 
        if (cls != NULL) { 
            env->ThrowNew(cls, msg); 
        } 
        /* free the local ref */ 
        env->DeleteLocalRef(cls); 


    jstring JNU_NewStringNative(JNIEnv *env, const char *str) 

      if (str==NULL) 
      { 
       return NULL; 
      } 
      jclass jcls_str = env->FindClass("java/lang/String"); 
      jmethodID jmethod_str = env->GetMethodID(jcls_str, "", "([B)V"); 

      jstring result; 
      jbyteArray bytes = 0; 
      int len; 

      if (env->EnsureLocalCapacity(2) < 0) { 
        return NULL; /* out of memory error */ 
      } 
      len = strlen(str); 
      bytes = env->NewByteArray(len); 
      if (bytes != NULL) { 
        env->SetByteArrayRegion(bytes, 0, len,(jbyte *)str); 
        result = (jstring)env->NewObject(jcls_str, jmethod_str, bytes); 
        env->DeleteLocalRef(bytes); 
        return result; 
      } /* else fall through */ 
      return NULL; 



    char *JNU_GetStringNativeChars(JNIEnv *env, jstring jstr) 

        jbyteArray bytes = 0; 
        jthrowable exc; 
        char *result = 0; 
        if (env->EnsureLocalCapacity(2) < 0) { 
            return 0; /* out of memory error */ 
        } 
    jclass jcls_str = env->FindClass("java/lang/String"); 
    jmethodID MID_String_getBytes = env->GetMethodID(jcls_str, "getBytes", "()[B"]; 

        bytes = (jbyteArray)env->CallObjectMethod(jstr, MID_String_getBytes); 
        exc = env->ExceptionOccurred(); 
        if (!exc) { 
            jint len = env->GetArrayLength( bytes); 
            result = (char *)malloc(len + 1); 
            if (result == 0) { 
                JNU_ThrowByName(env, "java/lang/OutOfMemoryError", 
                                0); 
                env->DeleteLocalRef(bytes); 
                return 0; 
            } 
            env->GetByteArrayRegion(bytes, 0, len, (jbyte *)result); 
            result[len] = 0; /* NULL-terminate */ 
        } else { 
            env->DeleteLocalRef(exc); 
        } 
        env->DeleteLocalRef(bytes); 
        return (char*)result; 


    ★注意:使用char *JNU_GetStringNativeChars()獲得的指針用完后要顯式的free().

    posted @ 2006-02-27 15:54 小鐵匠 閱讀(978) | 評論 (0)編輯 收藏

    使用Axis傳送附件有兩種方式:

    1. 將你要傳送的文件封裝在DataHandler中,然后將DataHandler對象或DataHandler數組(多個文件傳送的時候)作為客戶端調用函數的參數(從客戶端上傳文件到服務器)Axis服務的返回類型(從服務器端下載文件到客戶端)進行傳輸。

    2. 還有一種方式是直接修改soap信封的內容,將附件信息加到soap信封中發送。

    這里我們只討論第一種方法,因為它實現起來非常簡單。關于第二種方法在Axis包的webapps/attachments/TestRf.java中有詳細的原碼可以參考。

    下面的例子是把文件從服務器端下載到客戶端:

    1.服務端程序:

    假設傳輸多個文件:在服務器端將文件取出來,并將文件封裝在DataHandler數組中。
    代碼如下:

     DataHandler[] ret = new DataHandler[totalFileNum];
     ... ...
     java.io.File myFile = new java.io.File(filePath);
     if(myFile.isFile() && myFile.canRead())
     {
      String fname = myFile.getAbsoluteFile().getCanonicalPath();
      DataHandler[0] = new DataHandler(new FileDataSource(fname));
     }
     ... ...

     return ret;

    上面的代碼將所有的文件封裝在了DataHandler數組中,并返回。

    2. 客戶端的訪問:

    代碼如下:
     Service service = new Service();
     Call call = (Call) service.createCall();

     URL myURL = new URL(" call.setTargetEndpointAddress(myURL); //設定服務的主機和位置
     call.setOperationName(new QName("urn:MyAttachServer","echoDir")); //設置要調用的服務的方法
     QName qnameAttachment = new QName("urn:MyAttachServer","DataHandler");

     call.registerTypeMapping(DataHandler.class, qnameAttachment, JAFDataHandlerSerializerFactory.class,JAFDataHandlerDeserializerFactory.class); //為附件(即DataHandler類)創建序列化生成器

     call.addParameter("source", XMLType.XSD_STRING ,ParameterMode.IN); //設置服務調用方法的傳入參數類型
     call.setReturnType(XMLType.SOAP_ARRAY); //設置調用服務方法的返回類型,由于返回的是DataHandler數組,所以設置為SOAP_ARRAY類型
     javax.activation.DataHandler[] ret = (javax.activation.DataHandler[])call.invoke(new Object[]{null}); //調用方法

     for (i = 0; i < ret.length; ++i)
            {
                DataHandler recDH = ret[i];
                java.io.File receivedFile = new java.io.File(recDH.getName()); //文件生成
            }

    3. 服務的部署:

    注意:你要在部署的時候,定義DataHandler的序列化生成器。

      編寫deploy.wsdd文件:

     <deployment xmlns="  <service name="urn:att_STC_Server" provider="java:RPC" >
        <parameter name="className" value="samples.att_STC.att_STC_Server"/>
        <parameter name="allowedMethods" value="echoDir"/>

     <typeMapping deserializer="org.apache.axis.encoding.ser.JAFDataHandlerDeserializerFactory"
       languageSpecificType="java:javax.activation.DataHandler" qname="ns1:DataHandler"
        serializer="org.apache.axis.encoding.ser.JAFDataHandlerSerializerFactory"
        encodingStyle="
    http://schemas.xmlsoap.org/soap/encoding/"/>
      </service>

    </deployment>

    運行java org.apache.axis.client.AdminClient %* deploy.wsdd,部署服務。

    posted @ 2006-02-20 16:28 小鐵匠 閱讀(1035) | 評論 (1)編輯 收藏

    2004-05-29 17:39:53

    主題: 使用Java實現CA(四)

        前面幾篇文章已經把如何用Java實現一個CA基本上講完了.但是他們都有一個特點,就是用戶的信息都是在現場獲取的,不能做申請和簽發相分離.今天我們要講述的是PKCS#10證書請求文件.它的作用就是可以使申請和簽發相分離.

        PKCS#10證書請求結構中的主要信息包含了被簽發者(證書申請者)的主體名稱(DN)和他的公鑰.因此一個CA在獲取到一個PKCS#10證書請求后,就可以從中獲取到任何和簽發證書有關的信息,然后用它自己的私鑰簽發證書.

        使用BC Provider在Java中構造一個證書請求格式的對象調用其構造函數即可,這個函數如下:

        PKCS10CertificationRequest(java.lang.String signatureAlgorithm, X509Name subject, java.security.PublicKey key, ASN1Set attributes, java.security.PrivateKey signingKey)

        它的參數是自簽名算法,證書申請者的DN,證書申請者的公鑰,額外的屬性集(就是要申請的證書的擴展信息),申請證書者的私鑰.申請證書者的私鑰僅僅是用來進行一下自簽名,并不出現在證書請求中,需要自簽名的目的是保證該公鑰確實為申請者所有.

        調用該對象的getEncoded()方法可以將其進行DER編碼,然后儲存起來,該對象還有另一個構造函數:
        PKCS10CertificationRequest(byte[] bytes)
        這個構造函數的作用就是直接從儲存的DER編碼中把這個對象還原出來.

        利用證書請求結構進行證書簽發的代碼如下,這里假設CSR是一個已經獲取出來的PKCS10CertificationRequest結構:

        PublicKey SubjectPublicKey = CSR.getPublicKey();
        CertificationRequestInfo CSRInfo = CSR.getCertificationRequestInfo();
        X509Name SubjectDN = CSRInfo.getSubject();
        ASN1Set Attributes = CSRInfo.getAttributes();

        這樣,申請者的主體DN,申請者的公鑰,申請者希望在證書擴展信息中填寫的屬性都得到了,剩下的事情就和用戶在現場輸入時一樣了,其它的信息一般是申請者不能決定的.另外證書請求格式中有一樣信息沒有明確給出來,那就是證書的有效期,這個應該單獨詢問用戶,或者用其它的方法保存起來.



    [返回頂部]


    2004-05-28 16:46:12

    主題: 使用Java實現CA(三)

        前幾次我已經基本上把如何做CA所需要的基礎知識講得差不多了,今天直接講如何用Java程序來實現一個CA應該就不是什么太困難的事情了.

        要做CA,第一步要準備好自己的證書和私鑰.私鑰如何從文件里面讀取出來前面已經講過了.從文件系統中讀出證書的代碼如下:

        CertificateFactory certCF = CertificateFactory.getInstance("X.509");
        X509Certificate caCert = certCF.generateCertificate(certBIS);

        這里cerBIS是一個InputStream類型的對象.例如一個標準的X509v3格式的證書文件所形成的輸入流.

        第二步就是從用戶那里獲取輸入,然后構造主體名稱結構DN,如何構造DN上次已經說過了,如何從用戶那里獲取輸入,這個不在本文討論范圍之內.

        下一步就是獲取用戶的公鑰,好和他所需要的證書對應起來.也有不少CA的做法就是在這里替用戶現場生成一對密鑰對,然后把公鑰放到證書中簽發給用戶.這個應該看實際需要選擇合適的方式.

        現在一切信息都已經準備好了,可以簽發證書了,下面的代碼說明了這個過程:

        //構造一個證書生成器對象

        X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();

        // 從CA的證書中獲取簽發者的主體名稱(DN)
        // 這里有一點小技巧,我們要把JCE中定義的
        // 用來表示DN的對象X500Principal轉化成在
        // BC Provider中的相應的對象X509Name
        // 先從CA的證書中讀取出CA的DN進行DER編碼
        DERInputStream dnStream =
                     new DERInputStream(
          new ByteArrayInputStream(
           caCert.getSubjectX500Principal().
            getEncoded()));
        // 馬上又從編碼后的字節流中讀取DER編碼對象
        DERConstructedSequence  dnSequence =
         (DERConstructedSequence)dnStream.readObject();
        // 利用讀取出來的DER編碼對象創建X509Name
        // 對象,并設置為證書生成器中的"簽發者DN"
        certGen.setIssuerDN(new X509Name(dnSequence));
        // 設置好證書生成器中的"接收方DN"
        certGen.setSubjectDN(subjectDN);
        // 設置好一些擴展字段,包括簽發者和
        // 接收者的公鑰標識
        certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
        createSubjectKeyId(keyToCertify));
        certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
        createAuthorityKeyId(caCert.getPublicKey()));
        // 設置證書的有效期和序列號
        certGen.setNotBefore(startDate);
        certGen.setNotAfter(endDate);
        certGen.setSerialNumber(serialNumber);
        // 設置簽名算法,本例中使用MD5hash后RSA
        // 簽名,并且設置好主體的公鑰
        certGen.setSignatureAlgorithm("MD5withRSA");
        certGen.setPublicKey(keyToCertify);

        // 如果以上一切都正常地話,就可以生成證書了
        X509Certificate cert = null;
        cert = certGen.generateX509Certificate(caPrivateKey);

        這里是上面用到的生成簽發者公鑰標識的函數: 

        protected AuthorityKeyIdentifier createAuthorityKeyId(PublicKey pubKey)
        {
        AuthorityKeyIdentifier authKeyId = null;

        try
        {
        ByteArrayInputStream bIn = new ByteArrayInputStream(pubKey.getEncoded());
        SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
            (DERConstructedSequence)new DERInputStream(bIn).readObject());
        authKeyId = new AuthorityKeyIdentifier(info);
        }
        catch (IOException e)
        {
        System.err.println("Error generating SubjectKeyIdentifier:  " +
            e.toString());
        System.exit(1);
        }

        return authKeyId;
        }

        生成主體公鑰標識的函數和上面的類似,把AuthorityKeyIdentifier替換成SubjectKeyIdentifier就可以了.

        這里要注意的是,CA的公鑰也是在一份證書里,這種證書的特點是簽發者DN和接收者DN一樣,也就是說,這種證書是CA自己給自己頒發的證書,也就是"自簽名證書",它上面的公鑰是CA自身的公鑰,用來簽名的私鑰就是該公鑰對應的私鑰.一般每個CA都要有這么一份證書,除非該CA不是根CA,即它的權威性不是由它自己證明,而是由它的上級CA證明.但是,最后總歸要有一個根CA,它為各個安全應用程序的用戶所信賴.

        到這里我們已經把CA最基本的功能如何用Java實現講完了,下一次講如何從PKCS#10格式證書請求文件中讀取出用戶信息,然后直接簽發公鑰.



    [返回頂部]


    2004-05-27 15:34:59

    主題: 使用Java實現CA(二)

        昨天本來快寫完了,結果不小心按了"tab"鍵,然后向按退格鍵,結果退到前一個頁面了,然后全部都白寫了,不爽.只好今天重新寫了.

        上次我們講到如何生成密鑰對,以及如何將諸如公鑰,私鑰,證書等這一類安全對象在文件系統和內存之間來回轉換.這些是準備開CA的基本功,今天我們講一下CA的基本原理以及如何使用主體名稱結構DN(Distinguish Name)來表示每一個證書中的主體.

        一份證書就是一個權威機構對一個主體的身份的確認的證明.即一份證書表示一個權威機構確認了一個主體就是它自己,而不是其它的冒名頂替者.主體可以是一個個人,也可以不是,例如,在需要安全服務的時候,需要為一臺網站的服務器頒發證書,這種證書的主體就是一臺服務器.簽署證書的權威機構就叫做CA,該權威機構本身也是一個主體.權威機構通過對包含有待認證的主體的一系列信息的待簽名證書"(TBS,to be signed)進行數字簽名來表示該機構對它的認可.一份包含了待認證的主體的相關信息的TBS再加上CA使用自己的私鑰進行簽名產生的字節流放在一起,就構成了一份標準的X509證書.

        一個TBS中包含了以下這些主要信息:

        證書的版本,通常是3(X509v3)

        證書的序列號,RFC3280中規定,每個CA必須確保它頒發的每一份證書的序列號都是唯一的,并且序列號只能使用非負整數.

        簽發者(CA)的主體名稱,一個DN對象.

        證書的有效期,表示方法是兩個時間值,表示了該證書從何時開始生效,何時開始作廢.

        待認證的主體的主體名稱,也是一個DN對象.

        待認證的主體的公鑰,任何安全應用在確認完證書的有效性后,就可以開始使用該主體的公鑰與之進行安全通信.

        如果是X509v3證書,即版本號是3的話,后面還有一個證書擴展信息字段,可以在證書里面添加一些其它的信息.

        下面我們來看一下表示主體的主體名稱結構:DN.這個結就構是一個屬性的集合.每個屬性有屬性名稱和屬性值.它的作用就是用來表示"我是誰",也就是說,這個證書到底是誰頒發給誰的,這個證書對應的公鑰是誰擁有的.

        通常使用一個字符串來表示DN結構,這種字符串說明了這種結構中的各個屬性的類型和值:

        C=CN;S=BeiJing;L=BeiJing;O=PKU;OU=ICST;CN=wolfenstein

        這里C是國家和地區代碼,S和L都是地區代碼,S相當于省或者州這樣的級別,L相當于城市級別,O是組織機構名稱,OU是次級組織機構名稱,CN是主體的通用名(common name).在這里,C,S,L等等屬性的類型都是相對固定的,例如C一般就是用來表示國家和地區代碼,在DN結構中還可以添加一些其它類型的信息,一般也都是以"xxx=xxx"這樣來表示的.

        下面我們來說明如何在Java語言中構造出一個主體名稱對象.

        BC Provider中使用X509Name對象來表示DN,構造一個X509Name的步驟大體如下:

        先構造兩個vector對象,用來表示屬性名稱和屬性值:

        Vector oids = new Vector();
        Vector attributes = new Vector();

        然后在oids這個用來表示屬性名稱的vector對象中將屬性名稱一個一個添加進去:

        oids.addElement(X509Name.C);

        ......

        oids.addElement(X509Name.CN);

        X509Name對象里面有若干常量,例如上面的X509Name.C.還有X509Name.ST等等,都可以和上面舉的例子對應起來.

        然后將屬性值添加到attributes對象中:

        attributes.addElement("CN");

        ......

        attributes.addElement("Wolfenstein");

        最后就可以構造出一個X509Name對象:

        X509Name SubjectDN = new X509Name(oids, attributes);

        這樣,我們的主體名稱結構就確立起來了.

        下次我們就可以講關鍵的部分了,那就是如何用Java程序完成CA最重要的功能,簽署證書.



    [返回頂部]


    2004-05-25 21:23:52

    主題: 使用Java實現CA(一)

        通過我昨天的文章大家應該已經清楚了,用Java寫信息安全方面的程序需要做的準備工作.好了,現在假設你已經是一個對Java語言本身比較熟悉,能夠用Java寫一些程序的人,并且這些該下載的jar包已經下載好了,可以正式開工了.

        在所有的此類程序的開頭(無論是在類的構造函數中也好,在初始化函數中也好),都要先來上這么一句:Security.addProvider(new BouncyCastleProvider());將BouncyCaslte的Provider添加到系統中,這樣以后系統在運行相關程序的時候調用的就是這個Provider中的加密算法.

        然后我們就可以開始開CA了.首先,作為一個CA要有自己的一對公鑰和私鑰,我們先要生成這么一對.使用KeyPairGenerator對象就可以了,調用KeyPairGenerator.getInstance方法可以根據要生成的密鑰類型來產生一個合適的實例,例如常用的RSA,DSA等.然后調用該對象的initialize方法和generateKeyPair方法就可以產生一個KeyPair對象了.然后調用KeyPair對象中的相應方法就可以獲取生成的密鑰對中的公鑰和私鑰了.

        有了公鑰和私鑰對以后,下面的一個很現實問題就是如何把它們儲存起來.通常我們要對這些安全對象,如公鑰,私鑰,證書等先進行編碼.編碼的目的是為了把結構復雜的安全對象變成字節流以便存儲和讀取,如DER編碼.另外,通常還把DER編碼后的字節流再次進行base64編碼,以便使字節流中所有的字節都變成可打印的字節.

        在Java語言中,這些安全對象基本上都有getEncoded()方法.例如:

        byte[] keyBytes = privateKey.getEncoded();

        這樣就把一個私鑰進行了DER編碼后的結果保存到一個byte數組中了.然后就可以把這個byte數組保存到任何介質中.如果有必要的話,可以使用BC Provider中的Base64編碼解碼器類進行編碼,就像這樣:

        byte data[] = Base64.encode(keyBytes);

        要從文件中讀取私鑰則應該這樣:

        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyData);
        KeyFactory kfac = KeyFactory.getInstance("RSA");
        privateKey = kfac.generatePrivate(spec);

        這里說明一下,對RSA私鑰進行編碼就會自動地按照PKCS8進行.因此讀取的時候將包含編碼的字節數組作為PKCS8EncodedKeySpec對象的構造函數的參數就可以生成一個該類型的對象.然后創建一個密鑰工廠對象就可以按照要求生成一個RSA私鑰了.很顯然這里的keyData應該是和上面的keyBytes內容相同.

        為了提高系統的安全性,通常私鑰在經過DER編碼后,還會使用一個口令進行加密,然后再儲存在文件系統中.在使用私鑰的時候,如果沒有正確的口令,是無法把私鑰還原出來的.

        保存證書和保存私鑰類似.Certificate對象中也有一個getEncoded的方法.

        這次就講這些.大家應該可以把這些安全對象很熟練地從文件系統和內存之間來回地折騰了吧.這對以后實現CA是很重要的.下次我會講一下證書中表示主體的方法:DN.



    [返回頂部]


    2004-05-24 17:23:06

    主題: 使用Java開發和信息安全相關的程序

        這里說的信息安全是相對于系統安全而言的,它更側重于加密,解密,數字簽名,驗證,證書等等.而系統安全主要側重于系統本身是否有安全漏洞,如常見的由于軟件設計的不完善而導致的滿天飛的緩沖區溢出等等.

        Java語言中負責加密功能的部件是JCE(Java Crypto Extenstion),它使用開放式的思想,可以允許用戶自己編寫加密算法的具體實現的模塊等.這些東西被稱為JCE Provider,JCE的提供者.SUN公司本身提供了一些Provider.不過我推薦使用Bouncy Castle的Provider.原因是它實現的加密算法多,連比較新的橢圓曲線(ECC)算法都有了.去http://www.bouncycastle.org/可以找到你所希望的.Bouncy Castle除了提供Provider本身以外,還包括了一個S/MIME和一個open pgp 的jar包只有Provider本身是必要的,后兩個包是方便你編程而提供的.例如有了S/MIME包后,你就不再需要為諸如"加密一個字符串或者一片文章然后簽名"之類的很現實的應用程序寫上一大堆代碼了,只要引用S/MIME包中的某幾個類,很快就可以搞定.而open pgp的存在,使你在用Java編寫和PGP/GPG交互的程序時方便多了.

        這次先寫這么多了,下次開始具體講把這些東西搞下來后怎么開始干活吧.我以我現在手頭上正在做的事情告訴大家,如何做一個CA.

        有了BC Provider,開CA,真的就是這么簡單!

    posted @ 2006-02-20 11:07 小鐵匠 閱讀(6110) | 評論 (0)編輯 收藏
    jdbc url:jdbc:oracle:thin:@(DESCRIPTION=(LOAD_BALANCE=on)(ADDRESS=(PROTOCOL=TCP)(HOST=10.0.0.1)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=10.0.0.2)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=sa)))
    其他照常
    posted @ 2005-12-14 10:12 小鐵匠 閱讀(502) | 評論 (0)編輯 收藏
    僅列出標題
    共2頁: 上一頁 1 2 
    主站蜘蛛池模板: 久久www免费人成看片| 一级黄色免费网站| 国产成人综合亚洲亚洲国产第一页 | 亚洲国产精品专区| 国产精品亚洲美女久久久| 99久久久国产精品免费蜜臀| 香蕉视频在线观看免费| 亚洲色成人网一二三区| 青青青国产免费一夜七次郎| 精品无码国产污污污免费网站国产| 亚洲毛片基地4455ww| 亚洲一卡2卡4卡5卡6卡残暴在线| 亚洲色大成网站WWW久久九九 | 久久国产色AV免费看| 久久国产乱子伦精品免费午夜| 亚洲区日韩精品中文字幕| 国产成人精品免费午夜app| 无码国产精品一区二区免费3p | 亚洲AV永久无码区成人网站| 久久青青草原亚洲av无码| 亚洲中文字幕日产乱码高清app| 亚洲av极品无码专区在线观看| 久久亚洲国产成人精品性色| 最好看的中文字幕2019免费| 免费无码中文字幕A级毛片| 秋霞人成在线观看免费视频| 免费一级毛片无毒不卡| 88av免费观看入口在线| 在线视频观看免费视频18| 日韩免费高清视频| 亚洲国产成人精品女人久久久| 亚洲精品无码久久久影院相关影片| 亚洲爆乳精品无码一区二区三区 | 亚洲男人天堂2020| 久久亚洲一区二区| 亚洲av永久无码精品秋霞电影秋| 日本一区二区在线免费观看 | 亚洲精品黄色视频在线观看免费资源 | 亚洲国产综合在线| 黄页免费视频播放在线播放| 久久午夜免费视频|