java实现签名和解签
?
http://www.ibm.com/developerworks/cn/java/l-security/
?
? ??用他私人密鑰 (prikey) 對他所確認的信息 (info) 進行數字簽名產生一個簽名數組
從文件中讀入私人密鑰 (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();?
把他的公鑰的信息及簽名發給其它用戶
?
2. 使用公鑰驗證簽名是否正確:
其他用戶用他的公共密鑰 (pubkey) 和簽名 (signed) 和信息 (info) 進行驗證是否由他簽名的信息
讀入公鑰?
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 對象 , 并用公鑰和簽名進行驗證?
java.security.Signature signetcheck=java.security.Signature.getInstance("DSA");?
signetcheck.initVerify(pubkey);?
signetcheck.update(info.getBytes());?
if (signetcheck.verify(signed)) { System.out.println("簽名正常");}
// 使用公鑰將signed進行解簽,然后與info比較是否相等,相等則簽名正確。即保證是指定人發送,也保證信息傳輸中沒有被修改。如果被修改,那么修改后的info肯定與解簽后的值不相等,驗證簽名失敗。
對于密鑰的保存本文是用對象流的方式保存和傳送的 , 也可可以用編碼的方式保存 . 注意要?
import java.security.spec.*?
import java.security.*
=以下為學習網址中的內容==========================================================================
?
第 1 章基礎知識
1.1. 單鑰密碼體制
?
單鑰密碼體制是一種傳統的加密算法,是指信息的發送方和接收方共同使用同一把密鑰進行加解密。
通常 , 使用的加密算法 比較簡便高效 , 密鑰簡短,加解密速度快,破譯極其困難。但是加密的安全性依靠密鑰保管的安全性 , 在公開的計算機網絡上安全地傳送和保管密鑰是一個嚴峻的問題,并且如果在多用戶的情況下密鑰的保管安全性也是一個問題。
單鑰密碼體制的代表是美國的 DES
1.2. 消息摘要
一個消息摘要就是一個數據塊的數字指紋。即對一個任意長度的一個數據塊進行計算,產生一個唯一指印(對于 SHA1 是產生一個 20 字節的二進制數組)。
消息摘要有兩個基本屬性:
- 兩個不同的報文難以生成相同的摘要
- 難以對指定的摘要生成一個報文,而由該報文反推算出該指定的摘要
代表:美國國家標準技術研究所的 SHA1 和麻省理工學院 Ronald Rivest 提出的 MD5
1.3. Diffie-Hellman 密鑰一致協議
密鑰一致協議是由公開密鑰密碼體制的奠基人 Diffie 和 Hellman 所提出的一種思想。
先決條件 , 允許兩名用戶在公開媒體上交換信息以生成"一致"的 , 可以共享的密鑰
代表:指數密鑰一致協議 (Exponential Key Agreement Protocol)
1.4. 非對稱算法與公鑰體系
1976 年,Dittie 和 Hellman 為解決密鑰管理問題,在他們的奠基性的工作"密碼學的新方向"一文中,提出一種密鑰交換協議,允許在不安全的媒體上通過通訊雙方交換信息,安全地傳送秘密密鑰。在此新思想的基礎上,很快出現了非對稱密鑰密碼體制,即公鑰密碼體制。在公鑰體制中,加密密鑰不同于解密密鑰,加密密鑰公之于眾,誰都可以使用;解密密鑰只有解密人自己知道。它們分別稱為公開密鑰(Public key)和秘密密鑰(Private key)。
迄今為止的所有公鑰密碼體系中,RSA 系統是最著名、最多使用的一種。RSA 公開密鑰密碼系統是由 R.Rivest、A.Shamir 和 L.Adleman 俊教授于 1977 年提出的。RSA 的取名就是來自于這三位發明者的姓的第一個字母
1.5. 數字簽名
所謂數字簽名就是信息發送者用其私鑰對從所傳報文中提取出的特征數據(或稱數字指紋)進行 RSA 算法操作,以保證發信人無法抵賴曾發過該信息(即不可抵賴性),同時也確保信息報文在經簽名后末被篡改(即完整性)。當信息接收者收到報文后,就可以用發送者的公鑰對數字簽名進行驗證。
在數字簽名中有重要作用的數字指紋是通過一類特殊的散列函數(HASH 函數)生成的,對這些 HASH 函數的特殊要求是:
代表:DSA
回頁首
第 2 章在 JAVA 中的實現
2.1. 相關
Diffie-Hellman 密鑰一致協議和 DES 程序需要 JCE 工具庫的支持 , 可以到?http://java.sun.com/security/index.html?下載 JCE, 并進行安裝。簡易安裝把 jce1.2.1\lib 下的所有內容復制到 %java_home%\lib\ext 下 , 如果沒有 ext 目錄自行建立 , 再把 jce1_2_1.jar 和 sunjce_provider.jar 添加到 CLASSPATH 內 , 更詳細說明請看相應用戶手冊
2.2. 消息摘要 MD5 和 SHA 的使用
使用方法 :
首先用生成一個 MessageDigest 類 , 確定計算方法
java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1");
添加要進行計算摘要的信息
alga.update(myinfo.getBytes());
計算出摘要
byte[] digesta=alga.digest();
發送給其他人你的信息和摘要
其他人用相同的方法初始化 , 添加信息 , 最后進行比較摘要是否相同
algb.isEqual(digesta,algb.digest())
相關 AIP
java.security.MessageDigest 類
static getInstance(String algorithm)
返回一個 MessageDigest 對象 , 它實現指定的算法
參數 : 算法名 , 如 SHA-1 或 MD5
void update (byte input)
void update (byte[] input)
void update(byte[] input, int offset, int len)
添加要進行計算摘要的信息
byte[] digest()
完成計算 , 返回計算得到的摘要 ( 對于 MD5 是 16 位 ,SHA 是 20 位 )
void reset()
復位
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) // 二行制轉字符串{ 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.3. 數字簽名 DSA
生成一個 KeyPairGenerator 實例
java.security.KeyPairGenerator keygen=java.security.KeyPairGenerator.getInstance("DSA");//如果設定隨機產生器就用如相代碼初始化 SecureRandom secrand=new SecureRandom(); secrand.setSeed("tttt".getBytes()); // 初始化隨機產生器 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)
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(); 把他的公鑰的信息及簽名發給其它用戶讀入公鑰?
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 對象 , 并用公鑰和簽名進行驗證?
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(); // 生成編碼// 傳送二進制編碼// 以下代碼轉換編碼為相應 key 對象X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey); KeyFactory keyFactory = KeyFactory.getInstance("DSA"); PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);
- 對于 Private key 是用 PKCS#8 編碼 , 例碼如下 : byte[] bPKCS=myprikey.getEncoded(); // 傳送二進制編碼// 以下代碼轉換編碼為相應 key 對象PKCS8EncodedKeySpec priPKCS8=new PKCS8EncodedKeySpec(bPKCS); KeyFactory keyf=KeyFactory.getInstance("DSA"); PrivateKey otherprikey=keyf.generatePrivate(priPKCS8);
java.security.KeyPairGenerator 密鑰生成器類?
public static KeyPairGenerator getInstance(String algorithm) throws NoSuchAlgorithmException?
以指定的算法返回一個 KeyPairGenerator 對象?
參數 : algorithm 算法名 . 如 :"DSA","RSA"
public void initialize(int keysize)
以指定的長度初始化 KeyPairGenerator 對象 , 如果沒有初始化系統以 1024 長度默認設置
參數 :keysize 算法位長 . 其范圍必須在 512 到 1024 之間,且必須為 64 的倍數
public void initialize(int keysize, SecureRandom random)?
以指定的長度初始化和隨機發生器初始化 KeyPairGenerator 對象?
參數 :keysize 算法位長 . 其范圍必須在 512 到 1024 之間,且必須為 64 的倍數?
random 一個隨機位的來源 ( 對于 initialize(int keysize) 使用了默認隨機器
public abstract KeyPair generateKeyPair()?
產生新密鑰對
java.security.KeyPair 密鑰對類?
public PrivateKey getPrivate()?
返回私鑰
public PublicKey getPublic()?
返回公鑰
java.security.Signature 簽名類?
public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException?
返回一個指定算法的 Signature 對象?
參數 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 簽名數組
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)
?
第 3 章小結
在加密術中生成密鑰對時,密鑰對的當然是越長越好,但費時也越多,請從中從實際出發選取合適的長度,大部分例碼中的密鑰是每次運行就從新生成,在實際的情況中是生成后在一段時間保存在文件中,再次運行直接從文件中讀入,從而加快速度。當然定時更新和加強密鑰保管的安全性也是必須的。
總結
以上是生活随笔為你收集整理的java实现签名和解签的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: _attribute_((packed)
- 下一篇: 【系统知识点】linux入门基础命令