模拟CA系统
實現(xiàn)一個ca系統(tǒng),可以接受用戶的認證請求,安全儲存用戶信息,記錄儲存對用戶的一些認證信息,給用戶頒發(fā)證書,可以吊銷。
(1)接受用戶的提交申請,提交時候讓用戶自己產(chǎn)生公鑰對;
(2)接受用戶的申請,包括用戶信息的表單提交,公鑰的提交;
(3)在對用戶實施認證的過程中,儲存相應的電子文檔,比如證書、營業(yè)執(zhí)照的掃描文檔;
(4)通過驗證的給予頒發(fā)證書;
(5)用戶密鑰丟失時,可以吊銷證書,密鑰作廢。
1.前言
1.1實驗目的
實現(xiàn)一個ca系統(tǒng),可以接受用戶的認證請求,安全儲存用戶信息,記錄儲存對用戶的一些認證信息,給用戶頒發(fā)證書,可以吊銷。
(1)接受用戶的提交申請,提交時候讓用戶自己產(chǎn)生公鑰對;
(2)接受用戶的申請,包括用戶信息的表單提交,公鑰的提交;
(3)在對用戶實施認證的過程中,儲存相應的電子文檔,比如證書、營業(yè)執(zhí)照的掃描文檔;
(4)通過驗證的給予頒發(fā)證書;
(5)用戶密鑰丟失時,可以吊銷證書,密鑰作廢。
1.2實驗環(huán)境
運行系統(tǒng):win10
開發(fā)環(huán)境:mysql、navicat、java,eclipse
1.3安裝說明
1.3.1使用mysql(見附錄)
1.3.2數(shù)據(jù)庫連接(使用navicat)
1.3.3建立數(shù)據(jù)表
1.4準備工作
1.4.1 mysql連接eclipse
(1)關鍵步驟是下載mysql-connector-java-8.0.18.jar
這步非常關鍵,否則連接不上數(shù)據(jù)庫
1-1建立成功
1.4.2新建jdbcutil.java
用于實現(xiàn)數(shù)據(jù)庫和程序的連接
其關鍵代碼如下:
driverClass=“com.mysql.jdbc.Driver”;
url=“jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC”;
user=“root”;
password="";
Driver是個實現(xiàn)類,它由具體的數(shù)據(jù)庫廠商來實現(xiàn)。
它的connect方法可以獲取數(shù)據(jù)庫連接
1.4.3申請證書(詳見附錄)
(1)設置密鑰庫的口令,并填寫信息申請證書,這里密碼為111111
(2)將證書導出,存入文件中
(3)更改密碼(不是必要步驟)設置密碼為Changeit
2.系統(tǒng)分析
2.1系統(tǒng)需求概述
本次課程設計是實現(xiàn)一個簡單的CA頒發(fā)系統(tǒng),該系統(tǒng)主要實現(xiàn)以下幾個需求:
(1) CA頒發(fā)機構(服務器)接受用戶(客戶機)的認證請求,(服務器)通過用戶提交的信息,判斷申請用戶是否合法,包括用戶的公鑰是否已經(jīng)申請注冊過,是否注銷過,是否接受用戶的請求。
(2) 用戶認證信息通過后,將認證信息存儲,接下來可以接收用戶信息和用戶自己產(chǎn)生的公鑰;
(3) 接受完成后,先通過獲取CA證書獲得CA頒發(fā)機構的信息以及CA的私鑰,然后對接收到的用戶信息和公鑰進行數(shù)字簽名,生成數(shù)字證書并頒發(fā)給用戶,同時需要存儲用戶信息,證書
(4) 數(shù)字證書吊銷:掛失操作具體為將用戶需要掛失的公鑰存入到不信任的公鑰數(shù)據(jù)庫中,這樣,這個公鑰就會被作廢,但是在掛失前需要對用戶進行身份驗證,防止惡意掛失行為,驗證通過后還要訪問不信任公鑰數(shù)據(jù)庫中這個公鑰是否已經(jīng)存在,如果存在,彈出錯誤提示,如果不存在,則將公鑰進行掛失。
(5) 客戶機能夠接收到服務器對自己請求的回復,如果證書申請成功,能將證書在
本地找到。
2.2系統(tǒng)體系結構設計
2.2.1系統(tǒng)實現(xiàn)流程圖
首先從bytes[8]中提取判斷符,判斷用戶的請求(a代表申請,b代表注銷)
申請證書調用函數(shù)camain(bytes,apub),將用戶提供的用戶信息和公鑰傳給函數(shù)。
將處理結果用i保存。
注銷證書調用函數(shù)cancel(bytes[6], bytes[7]);將用戶提供的認證信息和公鑰傳給函數(shù)。將處理結果用i保存。
判斷bytes[8]和i,判斷給用戶返回什么信息。
2-1總體功能流程圖
2.2.2網(wǎng)絡通信流程圖
serverSocket = new ServerSocket(10086);
創(chuàng)建一個socket對象,監(jiān)聽10086接口。
in = new ObjectInputStream(socket.getInputStream());
將客戶機傳來的信息用in接收
然后將in中的內容用數(shù)組bytes[]存儲
os = socket.getOutputStream();
將服務器要傳給客戶機的內容存在pw和newcert中,其中pw是系統(tǒng)消息,newcert是證書和簽名。
圖2-2socket流程圖
3.功能設計
3.1判斷用戶
設計三個變量,ss,id,s1,分別用于判斷申請人是否合法,用戶信息表是否注冊,是否掛失過,并對于結果存在i中,由i得到系統(tǒng)提示。
這三個功能分別調用函數(shù)
if_id_exists(userID) ,
userinfo_id_exist(userID)
if_pkey_exsit(apub);
判斷過程如下:
3.2證書生成
函數(shù)Mycertificate(String []Personinfo,String Apub),用于證書生成,
我們傳遞了用戶信息和公鑰兩個變量。
getSignCertInfo();
//獲取簽名證書信息
signCertificate(Personinfo,Apub);
這個函數(shù)用來用簽名證書信息簽發(fā)代簽名證書,我們傳遞給它用戶信息和公鑰
boolean test=createNewCertificate(Personinfo) ;
創(chuàng)建并保存簽發(fā)后的新證書,這時我們只需要將用戶信息發(fā)給它。并用布爾型變量表示,證書是否申請成功。
用函數(shù)createNewCertificate(String []info) 取得并保存證書,用變量nerwcert保存證書,sig保存簽名。
newcert=new X509CertImpl(ClientInfo);
newcert.sign(CAPrivateKey, “sha256WithRSA”);
取得這些信息后我們用文件保存函數(shù)將證書保存,用返回函數(shù),將證書信息交給socket類,由它發(fā)給客戶機。
3.4界面詳細設計
程序的界面設計主要是顯示數(shù)字簽名、保存的結果,以及用戶信息的設置輸入等功能。申請證書之前,該程序要求用戶輸入信息,然后才能單擊申請證書按鈕,既可以進行證書申請,最后要在文本框中顯示申請數(shù)字簽名最后的結果,簽名完成之后用戶可以繼續(xù)進行掛失申請或者是直接退出界面。
我們覺得采用Swing常用組件之文本區(qū):JTextArea、按鈕:button、、標簽組:JLabel以及文本字段:JTextFileld來實現(xiàn)。
(1) 文本顯示框:
具體位置:main2.java121行
private JButton getC2ConnJButton() {
if (canceljbutton==null) {
canceljbutton=new JButton();
canceljbutton.setBounds(new Rectangle(300,145,97,26));
canceljbutton.setText(“掛失”);
canceljbutton.addActionListener(this);
}
return canceljbutton;
}
(2) 名字編輯框
具體位置:main2.java35行
jusertextfield=new JTextField(“root”);
jusertextfield.setBounds(new Rectangle(70,10,70,26));
}
(3) 文本區(qū)域信息添加函數(shù)
具體位置:main2.java200行
jtextarea.append("\n"+s+"\n");
(4) 掛失按鈕
具體位置:main2.java110行
canceljbutton=new JButton();
canceljbutton.setBounds(new Rectangle(300,145,97,26));
canceljbutton.setText(“掛失”);
canceljbutton.addActionListener(this);
3.5socket通信設計
上圖體現(xiàn)的是,利用socket通信時,一段數(shù)據(jù)流的標準開銷,也成為我們通信的報文頭,其中id用來做身份認證,公鑰作為客戶簽發(fā)自定義的公鑰,請求類型用于我們判斷對方的數(shù)據(jù)流的函數(shù)流向。
4.解決系統(tǒng)特色及關鍵技術
4.1將字符串轉化為公鑰
具體位置:myc.java220行
X509EncodedKeySpec apubkeyspec=new X509EncodedKeySpec(new BASE64Decoder().decodeBuffer(pubkey));
//RSA對稱加密算法
KeyFactory keyFactory;
keyFactory= KeyFactory.getInstance(“RSA”);
//取公鑰匙對象
publicKey=keyFactory.generatePublic(apubkeyspec);
在接收用戶信息的時候,都是字符串,所以不能直接數(shù)字簽用于數(shù)字簽名,否則數(shù)字簽名會失敗,所以需要將字符串先轉化為公鑰,再將公鑰返回才可以用
4.2驗證簽名
具體位置:main2.java246行
//獲得簽名實例
signature=Signature.getInstance(certificate.getSigAlgName());
//用證書公鑰進行初始化
signature.initVerify(certificate.getPublicKey());
//更新資源
signature.update(original);
//驗證數(shù)字簽名
return signature.verify(sign);
首先,先獲得簽名實例,用證書公鑰進行初始化,之后需要更新元數(shù)據(jù),然后驗證數(shù)字簽名,并返回數(shù)字簽名驗證結果,驗證時需要知道CA證書數(shù)字簽名的算法,必須根據(jù)CA證書的算法采用相同的算法來確定驗證數(shù)字簽名的算法才能夠保證驗證簽名成功。
4.3進入數(shù)據(jù)庫
Myc.java L.152
KeyStore ks=KeyStore.getInstance(“JKS”);
ks.load(in,storePwd);//得到路徑和密碼,可進入
我們想要進入數(shù)據(jù)庫,必須得到數(shù)據(jù)庫路徑,以及數(shù)據(jù)庫密碼,用函數(shù)load()就可以進入數(shù)據(jù)庫了。
5.所遇到的問題及分析解決
5.1警告:SerialVersionUid
The serializable class main2 does not declare a static final serialVersionUID field of type long
5.1.1問題出現(xiàn)的原因:
只要任何類別實作了Serializable這個介面,如果沒有加入serialVersionUID,Eclipse都會給你warning提示,這個serialVersionUID為了讓該類別Serializable後兼容.(其實有這個功能是好的.)
5.1.2分析問題:
如果不顯式設置SerialVersionUid,有什么后果?
jdk文檔中有解釋,建議我們顯式聲明,因為如果不聲明,JVM會為我們自動產(chǎn)生一個值,但這個值和編譯器的實現(xiàn)相關,并不穩(wěn)定,這樣就可能在不同JVM環(huán)境下出現(xiàn)反序列化時報InvalidClassException異常。
①兩種SerialVersionUid有什么區(qū)別?
一種就是1L,一種是生成一個很大的數(shù),這兩種有什么區(qū)別呢?
看上去,好像每個類的這個類不同,似乎這個SerialVersionUid在類之間有某種關聯(lián)。其實不然,兩種都可以,從JDK文檔也看不出這一點。我們只要保證在同一個類中,不同版本根據(jù)兼容需要,是否更改SerialVersionUid即可。
對于第一種,需要了解哪些情況是可兼容的,哪些根本就不兼容。
在可兼容的前提下,可以保留舊版本號,如果不兼容,或者想讓它不兼容,就手工遞增版本號。
1->2->3…
第二種方式,是根據(jù)類的結構產(chǎn)生的hash值。增減一個屬性、方法等,都可能導致這個值產(chǎn)生變化。我想這種方式適用于這樣的場景:
開發(fā)者認為每次修改類后就需要生成新的版本號,不想向下兼容,操作就是刪除原有serialVesionUid聲明語句,再自動生成一下。
個人認為,一般采用第一種就行了,簡單。第二種能夠保證每次更改類結構后改變版本號,但還是要手工去生成,并不是修改了類,會提示你要去更新這個SerialVersionUid
, 所以,實際上讓人很迷惑。
5.2 警告:靜態(tài)方法
This method has a constructor name :
第一:main方法是個靜態(tài)方法如果你想調用本類中的其他方法要么將其他方法設置為靜態(tài)的
要么創(chuàng)建一個該類的對象,調用之;
第二:盡量不要將你的方法的名字和類的名字相同。
5.3錯誤:驅動
5-2錯誤界面
5.3.1No suitable driver found for jdbc:mysql://localhost:3306/mydb
出現(xiàn)這樣的情況,一般有四種原因:
①連接URL格式出現(xiàn)了問題(Connection conn=DriverManager.getConnection(“jdbc:mysql://localhost:3306/XX”,“root”,“XXXX”)
②驅動字符串出錯(com.mysql.jdbc.Driver)
③Classpath中沒有加入合適的mysql_jdbc驅動(驅動要和你的數(shù)據(jù)庫版本一致)
④驅動jar包放的位置不對
首先,解決版本不一致的問題,因為我的mysql為mysql server 8.0 而我用的connector 為5.0 必須重新下載
5-3解決錯誤
然后,我的驅動復制錯了,不應復制壓縮包,應該復制以.jar結尾的connector
再然后,系統(tǒng)提示,應該將驅動字符串改為:driverClass=“com.mysql.cj.jdbc.Driver”;
5.3.2問題三解決了之后,出現(xiàn)了新的問題
The server time zone value ‘?й???’ is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
為URL添加參數(shù)serverTimezone=UTC即可,這里的時區(qū)可以根據(jù)自己數(shù)據(jù)庫的設定來設置(GMT/UTC )。
jdbc:mysql://localhost:3306/dbname?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
5.3.3新的問題又出現(xiàn)了:Parameter index out of range (1 > number of parameters, which is 0).
String sql=“select pkey form mypub where pkey=?”;原來是?是中文的?,改成英文的就好了
5.4 錯誤:keystore入口
Keytool存儲keystore位置不對
通過CMD命令創(chuàng)建的keystore存儲在c:\user下
而我們的程序執(zhí)行命令時,是在iava下,必須指定好具體詳細的位置要不然找不到
5.5 錯誤:Premature EOF
屬于IOException異常中,在解決這個問題中查閱了很多資料,甚至源碼。目前在網(wǎng)絡里的說法是:EOF是end of file的縮寫,premature eof指的是讀取文件時非正常的提前進入EOF狀態(tài)
問題解決:用戶輸入的密鑰不符合算法規(guī)定
6.測試
6.1 首次申請
6.1.1服務器接受用戶的提交申請,提交時候讓用戶自己產(chǎn)生公鑰對. 該界面提供了用戶輸入的界面,其中認證信息用于驗證用戶的合法性,公鑰為用戶自己的公鑰,其他信息根據(jù)用戶情況進行填寫。
6-1服務器接收申請界面
6.1.2系統(tǒng)提示:申請成功
6-2申請成功
圖6-3 用戶證書文檔
6.1.3以下為用戶得到的證書與簽名(圖6-3)
6.1.4保存成功
此時我們可以看到數(shù)據(jù)庫中保存了用戶信息
6-4數(shù)據(jù)庫成功保存信息
6.2重復申請
該用戶已經(jīng)得到證書后,再次申請
此時,系統(tǒng)則會提示,該用戶已經(jīng)注冊過
6-4再次申請
6.3掛失
該用戶密鑰丟失需要掛失
系統(tǒng)提示,掛失成功
6-5掛失成功
6.4掛失后重復申請
此時如果我們再用掛失過的公鑰,再次申請
系統(tǒng)則會顯示失敗
6-6掛失失敗
最后,附上源碼鏈接:客戶端 https://download.csdn.net/download/luckism/12652274
主機端 https://download.csdn.net/download/luckism/12652278
大概地給大家展示一下證書
總結
- 上一篇: CImage类 from http://
- 下一篇: 1251: 字母图形 [水题]