單鑰密碼體制是一種傳統(tǒng)的加密算法,是指信息的發(fā)送方和接收方共同使用同一把密鑰進(jìn)行加解密。
通常,使用的加密算法比較簡便高效,密鑰簡短,加解密速度快,破譯極其困難。但是加密的安全性依靠密鑰保管的安全性,在公開的計算機(jī)網(wǎng)絡(luò)上安全地傳送和保管密鑰是一個嚴(yán)峻的問題,并且如果在多用戶的情況下密鑰的保管安全性也是一個問題。
單鑰密碼體制的代表是美國的DES
一個消息摘要就是一個數(shù)據(jù)塊的數(shù)字指紋。即對一個任意長度的一個數(shù)據(jù)塊進(jìn)行計算,產(chǎn)生一個唯一指印(對于SHA1是產(chǎn)生一個20字節(jié)的二進(jìn)制數(shù)組)。
消息摘要有兩個基本屬性:
- 兩個不同的報文難以生成相同的摘要
- 難以對指定的摘要生成一個報文,而由該報文反推算出該指定的摘要
代表:美國國家標(biāo)準(zhǔn)技術(shù)研究所的SHA1和麻省理工學(xué)院Ronald Rivest提出的MD5
1.3. Diffie-Hellman密鑰一致協(xié)議
密鑰一致協(xié)議是由公開密鑰密碼體制的奠基人Diffie和Hellman所提出的一種思想。
先決條件,允許兩名用戶在公開媒體上交換信息以生成"一致"的,可以共享的密鑰
代表:指數(shù)密鑰一致協(xié)議(Exponential Key Agreement Protocol)
1976年,Dittie和Hellman為解決密鑰管理問題,在他們的奠基性的工作"密碼學(xué)的新方向"一文中,提出一種密鑰交換協(xié)議,允許在不安全的媒體上通過通訊雙方交換信息,安全地傳送秘密密鑰。在此新思想的基礎(chǔ)上,很快出現(xiàn)了非對稱密鑰密碼體制,即公鑰密碼體制。在公鑰體制中,加密密鑰不同于解密密鑰,加密密鑰公之于眾,誰都可以使用;解密密鑰只有解密人自己知道。它們分別稱為公開密鑰(Public key)和秘密密鑰(Private key)。
迄今為止的所有公鑰密碼體系中,RSA系統(tǒng)是最著名、最多使用的一種。RSA公開密鑰密碼系統(tǒng)是由R.Rivest、A.Shamir和L.Adleman俊教授于1977年提出的。RSA的取名就是來自于這三位發(fā)明者的姓的第一個字母
所謂數(shù)字簽名就是信息發(fā)送者用其私鑰對從所傳報文中提取出的特征數(shù)據(jù)(或稱數(shù)字指紋)進(jìn)行RSA算法操作,以保證發(fā)信人無法抵賴曾發(fā)過該信息(即不可抵賴性),同時也確保信息報文在經(jīng)簽名后末被篡改(即完整性)。當(dāng)信息接收者收到報文后,就可以用發(fā)送者的公鑰對數(shù)字簽名進(jìn)行驗(yàn)證。
在數(shù)字簽名中有重要作用的數(shù)字指紋是通過一類特殊的散列函數(shù)(HASH函數(shù))生成的,對這些HASH函數(shù)的特殊要求是:
- 接受的輸入報文數(shù)據(jù)沒有長度限制;
- 對任何輸入報文數(shù)據(jù)生成固定長度的摘要(數(shù)字指紋)輸出
- 從報文能方便地算出摘要;
- 難以對指定的摘要生成一個報文,而由該報文反推算出該指定的摘要;
- 兩個不同的報文難以生成相同的摘要
代表:DSA
![]() ![]() |
![]()
|
Diffie-Hellman密鑰一致協(xié)議和DES程序需要JCE工具庫的支持,可以到 http://java.sun.com/security/index.html 或是www.bt285.cn 下載JCE,并進(jìn)行安裝。簡易安裝把 jce1.2.1\lib 下的所有內(nèi)容復(fù)制到 %java_home%\lib\ext下,如果沒有ext目錄自行建立,再把jce1_2_1.jar和sunjce_provider.jar添加到CLASSPATH內(nèi),更詳細(xì)說明請看相應(yīng)用戶手冊
使用方法:
首先用生成一個MessageDigest類,確定計算方法
java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1");
添加要進(jìn)行計算摘要的信息
alga.update(myinfo.getBytes());
計算出摘要
byte[] digesta=alga.digest();
發(fā)送給其他人你的信息和摘要
其他人用相同的方法初始化,添加信息,最后進(jìn)行比較摘要是否相同
algb.isEqual(digesta,algb.digest())
相關(guān)AIP
java.security.MessageDigest 類
static getInstance(String algorithm)
返回一個MessageDigest對象,它實(shí)現(xiàn)指定的算法
參數(shù):算法名,如 SHA-1 或MD5
void update (byte input)
void update (byte[] input)
void update(byte[] input, int offset, int len)
添加要進(jìn)行計算摘要的信息
byte[] digest()
完成計算,返回計算得到的摘要(對于MD5是16位,SHA是20位)
void reset()
復(fù)位
static boolean isEqual(byte[] digesta, byte[] digestb)
比效兩個摘要是否相同
代碼:
import java.security.*; public class myDigest { public static void main(String[] args) { myDigest my=new myDigest(); my.testDigest(); } public void testDigest() { try { String myinfo="我的測試信息"; //java.security.MessageDigest alg=java.security.MessageDigest.getInstance("MD5"); java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1"); alga.update(myinfo.getBytes()); byte[] digesta=alga.digest(); System.out.println("本信息摘要是:"+byte2hex(digesta)); //通過某中方式傳給其他人你的信息(myinfo)和摘要(digesta) 對方可以判斷是否更改或傳輸正常 java.security.MessageDigest algb=java.security.MessageDigest.getInstance("SHA-1"); algb.update(myinfo.getBytes()); if (algb.isEqual(digesta,algb.digest())) { System.out.println("信息檢查正常"); } else { System.out.println("摘要不相同"); } } catch (java.security.NoSuchAlgorithmException ex) { System.out.println("非法摘要算法"); } } public String byte2hex(byte[] b) //二行制轉(zhuǎn)字符串 { String hs=""; String stmp=""; for (int n=0;n<b.length;n++) { stmp=(java.lang.Integer.toHexString(b[n] & 0XFF)); if (stmp.length()==1) hs=hs+"0"+stmp; else hs=hs+stmp; if (n<b.length-1) hs=hs+":"; } return hs.toUpperCase(); } } |
- 對于一個用戶來講首先要生成他的密鑰對,并且分別保存
生成一個KeyPairGenerator實(shí)例
java.security.KeyPairGenerator keygen=java.security.KeyPairGenerator.getInstance("DSA"); 如果設(shè)定隨機(jī)產(chǎn)生器就用如相代碼初始化 SecureRandom secrand=new SecureRandom(); secrand.setSeed("tttt".getBytes()); //初始化隨機(jī)產(chǎn)生器 keygen.initialize(512,secrand); //初始化密鑰生成器 否則 keygen.initialize(512); 生成密鑰公鑰pubkey和私鑰prikey KeyPair keys=keygen.generateKeyPair(); //生成密鑰組 PublicKey pubkey=keys.getPublic(); PrivateKey prikey=keys.getPrivate(); 分別保存在myprikey.dat和mypubkey.dat中,以便下次不在生成 (生成密鑰對的時間比較長 java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myprikey.dat")); out.writeObject(prikey); out.close(); out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("mypubkey.dat")); out.writeObject(pubkey); out.close();
- 用他私人密鑰(prikey)對他所確認(rèn)的信息(info)進(jìn)行數(shù)字簽名產(chǎn)生一個簽名數(shù)組
從文件中讀入私人密鑰(prikey)
java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("myprikey.dat")); PrivateKey myprikey=(PrivateKey)in.readObject(); in.close(); 初始一個Signature對象,并用私鑰對信息簽名 java.security.Signature signet=java.security.Signature.getInstance("DSA"); signet.initSign(myprikey); signet.update(myinfo.getBytes()); byte[] signed=signet.sign(); 把信息和簽名保存在一個文件中(myinfo.dat) java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myinfo.dat")); out.writeObject(myinfo); out.writeObject(signed); out.close(); 把他的公鑰的信息及簽名發(fā)給其它用戶
- 其他用戶用他的公共密鑰(pubkey)和簽名(signed)和信息(info)進(jìn)行驗(yàn)證是否由他簽名的信息
讀入公鑰
java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("mypubkey.dat"));
PublicKey pubkey=(PublicKey)in.readObject();
in.close();讀入簽名和信息
in=new java.io.ObjectInputStream(new java.io.FileInputStream("myinfo.dat"));
String info=(String)in.readObject();
byte[] signed=(byte[])in.readObject();
in.close();初始一個Signature對象,并用公鑰和簽名進(jìn)行驗(yàn)證
java.security.Signature signetcheck=java.security.Signature.getInstance("DSA");
signetcheck.initVerify(pubkey);
signetcheck.update(info.getBytes());
if (signetcheck.verify(signed)) { System.out.println("簽名正常");}對于密鑰的保存本文是用對象流的方式保存和傳送的,也可可以用編碼的方式保存.注意要
import java.security.spec.*
import java.security.*具休說明如下
- public key是用X.509編碼的,例碼如下:
byte[] bobEncodedPubKey=mypublic.getEncoded(); //生成編碼 //傳送二進(jìn)制編碼 //以下代碼轉(zhuǎn)換編碼為相應(yīng)key對象 X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey); KeyFactory keyFactory = KeyFactory.getInstance("DSA"); PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);
- 對于Private key是用PKCS#8編碼,例碼如下:
byte[] bPKCS=myprikey.getEncoded(); //傳送二進(jìn)制編碼 //以下代碼轉(zhuǎn)換編碼為相應(yīng)key對象 PKCS8EncodedKeySpec priPKCS8=new PKCS8EncodedKeySpec(bPKCS); KeyFactory keyf=KeyFactory.getInstance("DSA"); PrivateKey otherprikey=keyf.generatePrivate(priPKCS8);
- public key是用X.509編碼的,例碼如下:
- 常用API
java.security.KeyPairGenerator 密鑰生成器類
public static KeyPairGenerator getInstance(String algorithm) throws NoSuchAlgorithmException
以指定的算法返回一個KeyPairGenerator 對象
參數(shù): algorithm 算法名.如:"DSA","RSA"public void initialize(int keysize)
以指定的長度初始化KeyPairGenerator對象,如果沒有初始化系統(tǒng)以1024長度默認(rèn)設(shè)置
參數(shù):keysize 算法位長.其范圍必須在 512 到 1024 之間,且必須為 64 的倍數(shù)
public void initialize(int keysize, SecureRandom random)
以指定的長度初始化和隨機(jī)發(fā)生器初始化KeyPairGenerator對象
參數(shù):keysize 算法位長.其范圍必須在 512 到 1024 之間,且必須為 64 的倍數(shù)
random 一個隨機(jī)位的來源(對于initialize(int keysize)使用了默認(rèn)隨機(jī)器public abstract KeyPair generateKeyPair()
產(chǎn)生新密鑰對java.security.KeyPair 密鑰對類
public PrivateKey getPrivate()
返回私鑰public PublicKey getPublic()
返回公鑰java.security.Signature 簽名類
public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException
返回一個指定算法的Signature對象
參數(shù) algorithm 如:"DSA"public final void initSign(PrivateKey privateKey)
throws InvalidKeyException
用指定的私鑰初始化
參數(shù):privateKey 所進(jìn)行簽名時用的私鑰public final void update(byte data)
throws SignatureException
public final void update(byte[] data)
throws SignatureException
public final void update(byte[] data, int off, int len)
throws SignatureException
添加要簽名的信息public final byte[] sign()
throws SignatureException
返回簽名的數(shù)組,前提是initSign和updatepublic final void initVerify(PublicKey publicKey)
throws InvalidKeyException
用指定的公鑰初始化
參數(shù):publicKey 驗(yàn)證時用的公鑰public final boolean verify(byte[] signature)
throws SignatureException
驗(yàn)證簽名是否有效,前提是已經(jīng)initVerify初始化
參數(shù): signature 簽名數(shù)組*/ import java.security.*; import java.security.spec.*; public class testdsa { public static void main(String[] args) throws java.security.NoSuchAlgorithmException,java.lang.Exception { testdsa my=new testdsa(); my.run(); } public void run() { //數(shù)字簽名生成密鑰 //第一步生成密鑰對,如果已經(jīng)生成過,本過程就可以跳過,對用戶來講myprikey.dat要保存在本地 //而mypubkey.dat給發(fā)布給其它用戶 if ((new java.io.File("myprikey.dat")).exists()==false) { if (generatekey()==false) { System.out.println("生成密鑰對敗"); return; }; } //第二步,此用戶 //從文件中讀入私鑰,對一個字符串進(jìn)行簽名后保存在一個文件(myinfo.dat)中 //并且再把myinfo.dat發(fā)送出去 //為了方便數(shù)字簽名也放進(jìn)了myifno.dat文件中,當(dāng)然也可分別發(fā)送 try { java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("myprikey.dat")); PrivateKey myprikey=(PrivateKey)in.readObject(); in.close(); // java.security.spec.X509EncodedKeySpec pubX509=new java.security.spec.X509EncodedKeySpec(bX509); //java.security.spec.X509EncodedKeySpec pubkeyEncode=java.security.spec.X509EncodedKeySpec String myinfo="這是我的信息"; //要簽名的信息 //用私鑰對信息生成數(shù)字簽名 java.security.Signature signet=java.security.Signature.getInstance("DSA"); signet.initSign(myprikey); signet.update(myinfo.getBytes()); byte[] signed=signet.sign(); //對信息的數(shù)字簽名 System.out.println("signed(簽名內(nèi)容)="+byte2hex(signed)); //把信息和數(shù)字簽名保存在一個文件中 java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myinfo.dat")); out.writeObject(myinfo); out.writeObject(signed); out.close(); System.out.println("簽名并生成文件成功"); } catch (java.lang.Exception e) { e.printStackTrace(); System.out.println("簽名并生成文件失敗"); }; //第三步 //其他人通過公共方式得到此戶的公鑰和文件 //其他人用此戶的公鑰,對文件進(jìn)行檢查,如果成功說明是此用戶發(fā)布的信息. // try { java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("mypubkey.dat")); PublicKey pubkey=(PublicKey)in.readObject(); in.close(); System.out.println(pubkey.getFormat()); in=new java.io.ObjectInputStream(new java.io.FileInputStream("myinfo.dat")); String info=(String)in.readObject(); byte[] signed=(byte[])in.readObject(); in.close(); java.security.Signature signetcheck=java.security.Signature.getInstance("DSA"); signetcheck.initVerify(pubkey); signetcheck.update(info.getBytes()); if (signetcheck.verify(signed)) { System.out.println("info="+info); System.out.println("簽名正常"); } else System.out.println("非簽名正常"); } catch (java.lang.Exception e) {e.printStackTrace();}; } //生成一對文件myprikey.dat和mypubkey.dat---私鑰和公鑰, //公鑰要用戶發(fā)送(文件,網(wǎng)絡(luò)等方法)給其它用戶,私鑰保存在本地 public boolean generatekey() { try { java.security.KeyPairGenerator keygen=java.security.KeyPairGenerator.getInstance("DSA"); // SecureRandom secrand=new SecureRandom(); // secrand.setSeed("tttt".getBytes()); //初始化隨機(jī)產(chǎn)生器 // keygen.initialize(576,secrand); //初始化密鑰生成器 keygen.initialize(512); KeyPair keys=keygen.genKeyPair(); // KeyPair keys=keygen.generateKeyPair(); //生成密鑰組 PublicKey pubkey=keys.getPublic(); PrivateKey prikey=keys.getPrivate(); java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myprikey.dat")); out.writeObject(prikey); out.close(); System.out.println("寫入對象 prikeys ok"); out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("mypubkey.dat")); out.writeObject(pubkey); out.close(); System.out.println("寫入對象 pubkeys ok"); System.out.println("生成密鑰對成功"); return true; } catch (java.lang.Exception e) { e.printStackTrace(); System.out.println("生成密鑰對失敗"); return false; }; } public String byte2hex(byte[] b) { String hs=""; String stmp=""; for (int n=0;n<b.length;n++) { stmp=(java.lang.Integer.toHexString(b[n] & 0XFF)); if (stmp.length()==1) hs=hs+"0"+stmp; else hs=hs+stmp; if (n<b.length-1) hs=hs+":"; } return hs.toUpperCase(); } }
首先生成密鑰,并保存(這里并沒的保存的代碼,可參考DSA中的方法)
KeyGenerator keygen = KeyGenerator.getInstance(Algorithm);
SecretKey deskey = keygen.generateKey();
用密鑰加密明文(myinfo),生成密文(cipherByte)
Cipher c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.ENCRYPT_MODE,deskey);
byte[] cipherByte=c1.doFinal(myinfo.getBytes());
傳送密文和密鑰,本文沒有相應(yīng)代碼可參考DSA
.............
用密鑰解密密文
c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.DECRYPT_MODE,deskey);
byte[] clearByte=c1.doFinal(cipherByte);
相對來說對稱密鑰的使用是很簡單的,對于JCE來講支技DES,DESede,Blowfish三種加密術(shù)
對于密鑰的保存各傳送可使用對象流或者用二進(jìn)制編碼,相關(guān)參考代碼如下
SecretKey deskey = keygen.generateKey(); byte[] desEncode=deskey.getEncoded(); javax.crypto.spec.SecretKeySpec destmp=new javax.crypto.spec.SecretKeySpec(desEncode,Algorithm); SecretKey mydeskey=destmp; |
相關(guān)API
KeyGenerator 在DSA中已經(jīng)說明,在添加JCE后在instance進(jìn)可以如下參數(shù)
DES,DESede,Blowfish,HmacMD5,HmacSHA1
javax.crypto.Cipher 加/解密器
public static final Cipher getInstance(java.lang.String transformation) throws java.security.NoSuchAlgorithmException, NoSuchPaddingException |
返回一個指定方法的Cipher對象
參數(shù):transformation 方法名(可用 DES,DESede,Blowfish)
public final void init(int opmode, java.security.Key key)
throws java.security.InvalidKeyException
用指定的密鑰和模式初始化Cipher對象
參數(shù):opmode 方式(ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE,UNWRAP_MODE)
key 密鑰
public final byte[] doFinal(byte[] input) throws java.lang.IllegalStateException, IllegalBlockSizeException, BadPaddingException |
對input內(nèi)的串,進(jìn)行編碼處理,返回處理后二進(jìn)制串,是返回解密文還是加解文由init時的opmode決定
注意:本方法的執(zhí)行前如果有update,是對updat和本次input全部處理,否則是本inout的內(nèi)容
/* 安全程序 DESede/DES測試 */ import java.security.*; import javax.crypto.*; public class testdes { public static void main(String[] args){ testdes my=new testdes(); my.run(); } public void run() { //添加新安全算法,如果用JCE就要把它添加進(jìn)去 Security.addProvider(new com.sun.crypto.provider.SunJCE()); String Algorithm="DES"; //定義 加密算法,可用 DES,DESede,Blowfish String myinfo="要加密的信息"; try { //生成密鑰 KeyGenerator keygen = KeyGenerator.getInstance(Algorithm); SecretKey deskey = keygen.generateKey(); //加密 System.out.println("加密前的二進(jìn)串:"+byte2hex(myinfo.getBytes())); System.out.println("加密前的信息:"+myinfo); Cipher c1 = Cipher.getInstance(Algorithm); c1.init(Cipher.ENCRYPT_MODE,deskey); byte[] cipherByte=c1.doFinal(myinfo.getBytes()); System.out.println("加密后的二進(jìn)串:"+byte2hex(cipherByte)); //解密 c1 = Cipher.getInstance(Algorithm); c1.init(Cipher.DECRYPT_MODE,deskey); byte[] clearByte=c1.doFinal(cipherByte); System.out.println("解密后的二進(jìn)串:"+byte2hex(clearByte)); System.out.println("解密后的信息:"+(new String(clearByte))); } catch (java.security.NoSuchAlgorithmException e1) {e1.printStackTrace();} catch (javax.crypto.NoSuchPaddingException e2) {e2.printStackTrace();} catch (java.lang.Exception e3) {e3.printStackTrace();} } public String byte2hex(byte[] b) //二行制轉(zhuǎn)字符串 { String hs=""; String stmp=""; for (int n=0;n<b.length;n++) { stmp=(java.lang.Integer.toHexString(b[n] & 0XFF)); if (stmp.length()==1) hs=hs+"0"+stmp; else hs=hs+stmp; if (n<b.length-1) hs=hs+":"; } return hs.toUpperCase(); } } |
2.5. Diffie-Hellman密鑰一致協(xié)議
公開密鑰密碼體制的奠基人Diffie和Hellman所提出的 "指數(shù)密鑰一致協(xié)議"(Exponential Key Agreement Protocol),該協(xié)議不要求別的安全性先決條件,允許兩名用戶在公開媒體上交換信息以生成"一致"的,可以共享的密鑰。在JCE的中實(shí)現(xiàn)用戶alice生成DH類型的密鑰對,如果長度用1024生成的時間請,推薦第一次生成后保存DHParameterSpec,以便下次使用直接初始化.使其速度加快
System.out.println("ALICE: 產(chǎn)生 DH 對 ..."); KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH"); aliceKpairGen.initialize(512); KeyPair aliceKpair = aliceKpairGen.generateKeyPair(); |
alice生成公鑰發(fā)送組bob
byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded(); |
bob從alice發(fā)送來的公鑰中讀出DH密鑰對的初始參數(shù)生成bob的DH密鑰對
注意這一步一定要做,要保證每個用戶用相同的初始參數(shù)生成的
DHParameterSpec dhParamSpec = ((DHPublicKey)alicePubKey).getParams(); KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH"); bobKpairGen.initialize(dhParamSpec); KeyPair bobKpair = bobKpairGen.generateKeyPair(); |
bob根據(jù)alice的公鑰生成本地的DES密鑰
KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH"); bobKeyAgree.init(bobKpair.getPrivate()); bobKeyAgree.doPhase(alicePubKey, true); SecretKey bobDesKey = bobKeyAgree.generateSecret("DES"); |
bob已經(jīng)生成了他的DES密鑰,他現(xiàn)把他的公鑰發(fā)給alice,
byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded(); |
alice根據(jù)bob的公鑰生成本地的DES密鑰
,,,,,,解碼 KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH"); aliceKeyAgree.init(aliceKpair.getPrivate()); aliceKeyAgree.doPhase(bobPubKey, true); SecretKey aliceDesKey = aliceKeyAgree.generateSecret("DES"); |
bob和alice能過這個過程就生成了相同的DES密鑰,在這種基礎(chǔ)就可進(jìn)行安全能信
常用API
java.security.KeyPairGenerator 密鑰生成器類
public static KeyPairGenerator getInstance(String algorithm)
throws NoSuchAlgorithmException
以指定的算法返回一個KeyPairGenerator 對象
參數(shù): algorithm 算法名.如:原來是DSA,現(xiàn)在添加了 DiffieHellman(DH)
public void initialize(int keysize)
以指定的長度初始化KeyPairGenerator對象,如果沒有初始化系統(tǒng)以1024長度默認(rèn)設(shè)置
參數(shù):keysize 算法位長.其范圍必須在 512 到 1024 之間,且必須為 64 的倍數(shù)
注意:如果用1024生長的時間很長,最好生成一次后就保存,下次就不用生成了
public void initialize(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException
以指定參數(shù)初始化
javax.crypto.interfaces.DHPublicKey
public DHParameterSpec getParams()
返回
java.security.KeyFactory
public static KeyFactory getInstance(String algorithm)
throws NoSuchAlgorithmException
以指定的算法返回一個KeyFactory
參數(shù): algorithm 算法名:DSH,DH
public final PublicKey generatePublic(KeySpec keySpec)
throws InvalidKeySpecException
根據(jù)指定的key說明,返回一個PublicKey對象
java.security.spec.X509EncodedKeySpec
public X509EncodedKeySpec(byte[] encodedKey)
根據(jù)指定的二進(jìn)制編碼的字串生成一個key的說明
參數(shù):encodedKey 二進(jìn)制編碼的字串(一般能過PublicKey.getEncoded()生成)
javax.crypto.KeyAgreement 密碼一至類
public static final KeyAgreement getInstance(java.lang.String algorithm)
throws java.security.NoSuchAlgorithmException
返回一個指定算法的KeyAgreement對象
參數(shù):algorithm 算法名,現(xiàn)在只能是DiffieHellman(DH)
public final void init(java.security.Key key)
throws java.security.InvalidKeyException
用指定的私鑰初始化
參數(shù):key 一個私鑰
public final java.security.Key doPhase(java.security.Key key,
boolean lastPhase)
throws java.security.InvalidKeyException,
java.lang.IllegalStateException
用指定的公鑰進(jìn)行定位,lastPhase確定這是否是最后一個公鑰,對于兩個用戶的
情況下就可以多次定次,最后確定
參數(shù):key 公鑰
lastPhase 是否最后公鑰
public final SecretKey generateSecret(java.lang.String algorithm)
throws java.lang.IllegalStateException,
java.security.NoSuchAlgorithmException,
java.security.InvalidKeyException
根據(jù)指定的算法生成密鑰
參數(shù):algorithm 加密算法(可用 DES,DESede,Blowfish)
*/ import java.io.*; import java.math.BigInteger; import java.security.*; import java.security.spec.*; import java.security.interfaces.*; import javax.crypto.*; import javax.crypto.spec.*; import javax.crypto.interfaces.*; import com.sun.crypto.provider.SunJCE; public class testDHKey { public static void main(String argv[]) { try { testDHKey my= new testDHKey(); my.run(); } catch (Exception e) { System.err.println(e); } } private void run() throws Exception { Security.addProvider(new com.sun.crypto.provider.SunJCE()); System.out.println("ALICE: 產(chǎn)生 DH 對 ..."); KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH"); aliceKpairGen.initialize(512); KeyPair aliceKpair = aliceKpairGen.generateKeyPair(); //生成時間長 // 張三(Alice)生成公共密鑰 alicePubKeyEnc 并發(fā)送給李四(Bob) , //比如用文件方式,socket..... byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded(); //bob接收到alice的編碼后的公鑰,將其解碼 KeyFactory bobKeyFac = KeyFactory.getInstance("DH"); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec (alicePubKeyEnc); PublicKey alicePubKey = bobKeyFac.generatePublic(x509KeySpec); System.out.println("alice公鑰bob解碼成功"); // bob必須用相同的參數(shù)初始化的他的DH KEY對,所以要從Alice發(fā)給他的公開密鑰, //中讀出參數(shù),再用這個參數(shù)初始化他的 DH key對 //從alicePubKye中取alice初始化時用的參數(shù) DHParameterSpec dhParamSpec = ((DHPublicKey)alicePubKey).getParams(); KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH"); bobKpairGen.initialize(dhParamSpec); KeyPair bobKpair = bobKpairGen.generateKeyPair(); System.out.println("BOB: 生成 DH key 對成功"); KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH"); bobKeyAgree.init(bobKpair.getPrivate()); System.out.println("BOB: 初始化本地key成功"); //李四(bob) 生成本地的密鑰 bobDesKey bobKeyAgree.doPhase(alicePubKey, true); SecretKey bobDesKey = bobKeyAgree.generateSecret("DES"); System.out.println("BOB: 用alice的公鑰定位本地key,生成本地DES密鑰成功"); // Bob生成公共密鑰 bobPubKeyEnc 并發(fā)送給Alice, //比如用文件方式,socket.....,使其生成本地密鑰 byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded(); System.out.println("BOB向ALICE發(fā)送公鑰"); // alice接收到 bobPubKeyEnc后生成bobPubKey // 再進(jìn)行定位,使aliceKeyAgree定位在bobPubKey KeyFactory aliceKeyFac = KeyFactory.getInstance("DH"); x509KeySpec = new X509EncodedKeySpec(bobPubKeyEnc); PublicKey bobPubKey = aliceKeyFac.generatePublic(x509KeySpec); System.out.println("ALICE接收BOB公鑰并解碼成功"); ; KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH"); aliceKeyAgree.init(aliceKpair.getPrivate()); System.out.println("ALICE: 初始化本地key成功"); aliceKeyAgree.doPhase(bobPubKey, true); // 張三(alice) 生成本地的密鑰 aliceDesKey SecretKey aliceDesKey = aliceKeyAgree.generateSecret("DES"); System.out.println("ALICE: 用bob的公鑰定位本地key,并生成本地DES密鑰"); if (aliceDesKey.equals(bobDesKey)) System.out.println("張三和李四的密鑰相同"); //現(xiàn)在張三和李四的本地的deskey是相同的所以,完全可以進(jìn)行發(fā)送加密,接收后解密,達(dá)到 //安全通道的的目的 /* * bob用bobDesKey密鑰加密信息 */ Cipher bobCipher = Cipher.getInstance("DES"); bobCipher.init(Cipher.ENCRYPT_MODE, bobDesKey); String bobinfo= "這是李四的機(jī)密信息"; System.out.println("李四加密前原文:"+bobinfo); byte[] cleartext =bobinfo.getBytes(); byte[] ciphertext = bobCipher.doFinal(cleartext); /* * alice用aliceDesKey密鑰解密 */ Cipher aliceCipher = Cipher.getInstance("DES"); aliceCipher.init(Cipher.DECRYPT_MODE, aliceDesKey); byte[] recovered = aliceCipher.doFinal(ciphertext); System.out.println("alice解密bob的信息:"+(new String(recovered))); if (!java.util.Arrays.equals(cleartext, recovered)) throw new Exception("解密后與原文信息不同"); System.out.println("解密后相同"); } } |