java加密解密演算法__演算法

來源:互聯網
上載者:User
通常,使用的密碼編譯演算法 比較簡便高效,密鑰簡短,加解密速度快,破譯極其困難。本文介紹了 MD5/SHA1,DSA,DESede/DES,Diffie-Hellman的使用。

第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函數的特殊要求是: 接受的輸入報文資料沒有長度限制; 對任何輸入報文資料產生固定長度的摘要(數位指紋)輸出 從報文能方便地算出摘要; 難以對指定的摘要產生一個報文,而由該報文反推算出該指定的摘要; 兩個不同的報文難以產生相同的摘要

 

第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)對他所確認的資訊(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();
把他的公開金鑰的資訊及簽名發給其它使用者
其他使用者用他的公用密鑰(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("簽名正常");}

對於密鑰的儲存本文是用物件流程的方式儲存和傳送的,也可可以用編碼的方式儲存.注意要
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);
常用API

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 簽名數組

*/
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();
}
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.