對像 參數 algorithm 如:"DSA"
public final void initSign(PrivateKey privateKey) throws InvalidKeyException 用指定的私鑰初始化 參數:privateKey 所進行簽名時用的私鑰
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 返回簽名的數組,前提是initSign和update
public final void initVerify(PublicKey publicKey) throws InvalidKeyException 用指定的公鑰初始化 參數:publicKey 驗證時用的公鑰
public final boolean verify(byte[] signature) throws SignatureException 驗證簽名是否有效,前提是已經initVerify初始化 參數: signature 簽名數組
*/ 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() {
//數字簽名生成密鑰 //第一步生成密鑰對,如果已經生成過,本過程就可以跳過,對用戶來講myprikey.dat要保存在本地 //而mypubkey.dat給發佈給其它用戶 if ((new java.io.File("myprikey.dat")).exists()==false) { if (generatekey()==false) { System.out.println("生成密鑰對敗"); return; }; } //第二步,此用戶 //從文件中讀入私鑰,對一個字符串進行簽名後保存在一個文件(myinfo.dat)中 //並且再把myinfo.dat發送出去 //為了方便數字簽名也放進了myifno.dat文件中,當然也可分別發送 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="這是我的信息"; //要簽名的信息 //用私鑰對信息生成數字簽名 java.security.Signature signet=java.security.Signature.getInstance("DSA"); signet.initSign(myprikey); signet.update(myinfo.getBytes()); byte[] signed=signet.sign(); //對信息的數字簽名 System.out.println("signed(簽名內容)="+byte2hex(signed)); //把信息和數字簽名保存在一個文件中 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("簽名並生成文件失敗"); };
//第三步 //其他人通過公共方式得到此戶的公鑰和文件 //其他人用此戶的公鑰,對文件進行檢查,如果成功說明是此用戶發佈的信息. // 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---私鑰和公鑰, //公鑰要用戶發送(文件,網絡等方法)給其它用戶,私鑰保存在本地 public boolean generatekey() { try { java.security.KeyPairGenerator keygen=java.security.KeyPairGenerator.getInstance("DSA"); // SecureRandom secrand=new SecureRandom(); // secrand.setSeed("tttt".getBytes()); //初始化隨機產生器 // 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(); }
}
2.4. DESede/DES對稱算法 首先生成密鑰,並保存(這裡並沒的保存的代碼,可參考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());
傳送密文和密鑰,本文沒有相應代碼可參考DSA
.............
用密鑰解密密文
c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.DECRYPT_MODE,deskey);
byte[] clearByte=c1.doFinal(cipherByte);
相對來說對稱密鑰的使用是很簡單的,對於JCE來講支技DES,DESede,Blowfish三種加密術
對於密鑰的保存各傳送可使用對像流或者用二進制編碼,相關參考代碼如下
SecretKey deskey = keygen.generateKey(); byte[] desEncode=deskey.getEncoded(); javax.crypto.spec.SecretKeySpec destmp=new javax.crypto.spec.SecretKeySpec(desEncode,Algorithm); SecretKey mydeskey=destmp;
相關API
KeyGenerator 在DSA中已經說明,在添加JCE後在instance進可以如下參數
DES,DESede,Blowfish,HmacMD5,HmacSHA1
javax.crypto.Cipher 加/解密器
public static final Cipher getInstance(java.lang.String transformation) throws java.security.NoSuchAlgorithmException, NoSuchPaddingException
返回一個指定方法的Cipher對像
參數:transformation 方法名(可用 DES,DESede,Blowfish)
public final void init(int opmode, java.security.Key key) throws java.security.InvalidKeyException
用指定的密鑰和模式初始化Cipher對像
參數:opmode 方式(ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE,UNWRAP_MODE)
key 密鑰
public final byte[] doFinal(byte[] input) throws java.lang.IllegalStateException, IllegalBlockSizeException, BadPaddingException
對input內的串,進行編碼處理,返回處理後二進制串,是返回解密文還是加解文由init時的opmode決定
注意:本方法的執行前如果有update,是對updat和本次input全部處理,否則是本inout的內容
/* 安全程序 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就要把它添加進去 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("加密前的二進串:"+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("加密後的二進串:"+byte2hex(cipherByte)); //解密 c1 = Cipher.getInstance(Algorithm); c1.init(Cipher.DECRYPT_MODE,deskey); byte[] clearByte=c1.doFinal(cipherByte); System.out.println("解密後的二進串:"+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) //二行制轉字符串 { 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密鑰一致協議 公開密鑰密碼體制的奠基人Diffie和Hellman所提出的 "指數密鑰一致協議"(Exponential Key Agreement Protocol),該協議不要求別的安全性先決條件,允許兩名用戶在公開媒體上交換信息以生成"一致"的,可以共享的密鑰。在JCE的中實現用戶alice生成DH類型的密鑰對,如果長度用1024生成的時間請,推薦第一次生成後保存DHParameterSpec,以便下次使用直接初始化.使其速度加快
System.out.println("ALICE: 產生 DH 對 ..."); KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH"); aliceKpairGen.initialize(512); KeyPair aliceKpair = aliceKpairGen.generateKeyPair();
alice生成公鑰發送組bob
byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();
bob從alice發送來的公鑰中讀出DH密鑰對的初始參數生成bob的DH密鑰對
注意這一步一定要做,要保證每個用戶用相同的初始參數生成的
DHParameterSpec dhParamSpec = ((DHPublicKey)alicePubKey).getParams(); KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH"); bobKpairGen.initialize(dhParamSpec); KeyPair bobKpair = bobKpairGen.generateKeyPair();
bob根據alice的公鑰生成本地的DES密鑰
KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH"); bobKeyAgree.init(bobKpair.getPrivate()); bobKeyAgree.doPhase(alicePubKey, true); SecretKey bobDesKey = bobKeyAgree.generateSecret("DES");
bob已經生成了他的DES密鑰,他現把他的公鑰發給alice,
byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();
alice根據bob的公鑰生成本地的DES密鑰
,,,,,,解碼 KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH"); aliceKeyAgree.init(aliceKpair.getPrivate()); aliceKeyAgree.doPhase(bobPubKey, true); SecretKey aliceDesKey = aliceKeyAgree.generateSecret("DES");
bob和alice能過這個過程就生成了相同的DES密鑰,在這種基礎就可進行安全能信
常用API
java.security.KeyPairGenerator 密鑰生成器類 public static KeyPairGenerator getInstance(String algorithm) throws NoSuchAlgorithmException 以指定的算法返回一個KeyPairGenerator 對像 參數: algorithm 算法名.如:原來是DSA,現在添加了 DiffieHellman(DH)
public void initialize(int keysize) 以指定的長度初始化KeyPairGenerator對像,如果沒有初始化系統以1024長度默認設置 參數:keysize 算法位長.其範圍必須在 512 到 1024 之間,且必須為 64 的倍數 注意:如果用1024生長的時間很長,最好生成一次後就保存,下次就不用生成了
public void initialize(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException 以指定參數初始化
javax.crypto.interfaces.DHPublicKey public DHParameterSpec getParams() 返回 java.security.KeyFactory
public static KeyFactory getInstance(String algorithm) throws NoSuchAlgorithmException 以指定的算法返回一個KeyFactory 參數: algorithm 算法名:DSH,DH
public final PublicKey generatePublic(KeySpec keySpec) throws InvalidKeySpecException 根據指定的key說明,返回一個PublicKey對像
java.security.spec.X509EncodedKeySpec public X509EncodedKeySpec(byte[] encodedKey) 根據指定的二進制編碼的字串生成一個key的說明 參數:encodedKey 二進制編碼的字串(一般能過PublicKey.getEncoded()生成) javax.crypto.KeyAgreement 密碼一至類
public static final KeyAgreement getInstance(java.lang.String algorithm) throws java.security.NoSuchAlgorithmException 返回一個指定算法的KeyAgreement對像 參數:algorithm 算法名,現在只能是DiffieHellman(DH)
public final void init(java.security.Key key) throws java.security.InvalidKeyException 用指定的私鑰初始化 參數:key 一個私鑰
public final java.security.Key doPhase(java.security.Key key, boolean lastPhase) throws java.security.InvalidKeyException, java.lang.IllegalStateException 用指定的公鑰進行定位,lastPhase確定這是否是最後一個公鑰,對於兩個用戶的 情況下就可以多次定次,最後確定 參數:key 公鑰 lastPhase 是否最後公鑰
public final SecretKey generateSecret(java.lang.String algorithm) throws java.lang.IllegalStateException, java.security.NoSuchAlgorithmException, java.security.InvalidKeyException 根據指定的算法生成密鑰 參數: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: 產生 DH 對 ..."); KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH"); aliceKpairGen.initialize(512); KeyPair aliceKpair = aliceKpairGen.generateKeyPair(); //生成時間長
// 張三(Alice)生成公共密鑰 alicePubKeyEnc 並發送給李四(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必須用相同的參數初始化的他的DH KEY對,所以要從Alice發給他的公開密鑰, //中讀出參數,再用這個參數初始化他的 DH key對
//從alicePubKye中取alice初始化時用的參數 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 並發送給Alice, //比如用文件方式,socket.....,使其生成本地密鑰 byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded(); System.out.println("BOB向ALICE發送公鑰");
// alice接收到 bobPubKeyEnc後生成bobPubKey // 再進行定位,使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("張三和李四的密鑰相同"); //現在張三和李四的本地的deskey是相同的所以,完全可以進行發送加密,接收後解密,達到 //安全通道的的目的
/* * bob用bobDesKey密鑰加密信息 */ Cipher bobCipher = Cipher.getInstance("DES"); bobCipher.init(Cipher.ENCRYPT_MODE, bobDesKey); String bobinfo= "這是李四的機密信息"; 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("解密後相同");
}
}
第3章小結 在加密術中生成密鑰對時,密鑰對的當然是越長越好,但費時也越多,請從中從實際出發選取合適的長度,大部分例碼中的密鑰是每次運行就從新生成,在實際的情況中是生成後在一段時間保存在文件中,再次運行直接從文件中讀入,從而加快速度。當然定時更新和加強密鑰保管的安全性也是必須的。
|
|