天天看點

Java中建立對稱密鑰的步驟

★ 執行個體說明

本執行個體給出Java中建立對稱密鑰的步驟,并通過對象序列化方式儲存在檔案中。

★ 程式設計思路:

(1)       擷取密鑰生成器

KeyGenerator kg=KeyGenerator.getInstance("DESede");

分析:Java中KeyGenerator類中提供了建立對稱密鑰的方法。Java中的類一般使用new操作符通過構造器建立對象,但KeyGenerator類不是這樣,它預定義了一個靜态方法getInstance(),通過它獲得KeyGenerator類型的對象。這種類成為工廠類或工廠。

方法getInstance( )的參數為字元串類型,指定加密算法的名稱。可以是 “Blowfish”、“DES”、“DESede”、“HmacMD5”或“HmacSHA1”等。這些算法都可以實作加密,這裡我們不關心這些算法的細節,隻要知道其使用上的特點即可。其中“DES”是目前最常用的對稱加密算法,但安全性較差。針對DES安全性的改進産生了能滿足目前安全需要的TripleDES算法,即“DESede”。“Blowfish”的密鑰長度可達448位,安全性很好。“AES”是一種替代DES算法的新算法,可提供很好的安全性。

(2)       初始化密鑰生成器

kg.init(168);

分析:該步驟一般指定密鑰的長度。如果該步驟省略的話,會根據算法自動使用預設的密鑰長度。指定長度時,若第一步密鑰生成器使用的是“DES”算法,則密鑰長度必須是56位;若是“DESede”,則可以是112或168位,其中112位有效;若是“AES”,可以是128, 192或256位;若是“Blowfish”,則可以是32至448之間可以被8整除的數;“HmacMD5”和“HmacSHA1”預設的密鑰長度都是64個位元組。

(3)       生成密鑰

         SecretKey k=kg.generateKey( );

分析:使用第一步獲得的KeyGenerator類型的對象中generateKey( )方法可以獲得密鑰。其類型為SecretKey類型,可用于以後的加密和解密。

(4)       通過對象序列化方式将密鑰儲存在檔案中

            FileOutputStream  f=new FileOutputStream("key1.dat");

               ObjectOutputStream b=new  ObjectOutputStream(f);

               b.writeObject(k);

分析:ObjectOutputStream類中提供的writeObject方法可以将對象序列化,以流的方式進行處理。這裡将檔案輸出流作為參數傳遞給ObjectOutputStream類的構造器,這樣建立好的密鑰将儲存在檔案key1.data中。

★代碼與分析:

import java.io.*;

import javax.crypto.*;

public class Skey_DES{

 public static void main(String args[])

 throws Exception{

KeyGenerator kg=KeyGenerator.getInstance("DESede");

            kg.init(168);

            SecretKey k=kg.generateKey( );

            FileOutputStream  f=new FileOutputStream("key1.dat");

            ObjectOutputStream b=new  ObjectOutputStream(f);

            b.writeObject(k);

         }

}

運作java  Skey_DES,在目前目錄下将生成檔案key1.dat,其中包含的密鑰可以用于使用Triple DES算法的加密和解密。

以位元組儲存對稱密鑰

★ 執行個體說明

2.2.1小節的執行個體将密鑰通過對象序列化方式儲存在檔案中,在檔案中儲存的是對象,本執行個體以另一種方式儲存在檔案中,即以位元組儲存在檔案中。

★ 程式設計思路:

Java中所有的密鑰類都有一個getEncoded( )方法,通過它可以從密鑰對象中擷取主要編碼格式,其傳回值是位元組數組。其主要步驟為:

(1)       擷取密鑰

FileInputStream f=new FileInputStream("key1.dat");

ObjectInputStream b=new ObjectInputStream(f);

Key k=(Key)b.readObject( );

分析:該步驟與2.2.1小節的第4步是相對應的,2.2.1小節的第4步将密鑰對象以對象流的方式存入檔案,而這一步則将檔案中儲存的對象讀取出來以便使用。首先建立檔案輸入流,然後将其作為參數傳遞給對象輸入流,最後執行對象輸入流的readObject( )方法讀取密鑰對象。由于readObject( )傳回的是Object類型,是以需要強制轉換成Key類型。

這裡使用的是已有的密鑰,也可以不使用這裡的三行代碼,而使用2.1.1小節中的前三步的代碼生成新的密鑰再繼續下面的步驟。

(2)       擷取主要編碼格式

byte[ ] kb=k.getEncoded( );

分析:執行SecretKey類型的對象k的getEncoded( )方法,傳回的編碼放在byte類型的數組中。

(3)       儲存密鑰編碼格式

FileOutputStream  f2=new FileOutputStream("keykb1.dat");

    f2.write(kb);

分析:先建立檔案輸出流對象,在其參數中指定檔案名,如keykb1.dat。然後執行檔案輸出流的write( )方法将第2步中得到的位元組數組中的内容寫入檔案。

★代碼與分析:

import java.io.*;

import java.security.*;

public class Skey_kb{

   public static void main(String args[]) throws Exception{

FileInputStream f=new FileInputStream("key1.dat");

ObjectInputStream b=new ObjectInputStream(f);

Key k=(Key)b.readObject( );

        byte[ ] kb=k.getEncoded( );

        FileOutputStream  f2=new FileOutputStream("keykb1.dat");

       f2.write(kb);

        // 列印密鑰編碼中的内容

        for(int i=0;i<kb.length;i++){

             System.out.print(kb[i]+",");

        }

   }

}

程式中在儲存了密鑰編碼後,又使用循環語句将位元組數組中的内容列印出來。這樣可以較為直覺地看到密鑰編碼的内容。

★運作程式

輸入java  Skey_kb 運作程式,在程式的目前目錄中将産生檔案名為keykb1.dat的檔案,螢幕輸出如下:

11,-105,-119,50,4,-105,16,38,-14,-111,21,-95,70,-15,76,-74,67,-88,59,-71,55,-125,104,42,

此即程式中建立的密鑰的編碼内容,如果用文本編輯器打開keykb1.dat,看到的不是上面的數字而是類似下面的字元:

棄2 ?&驊馤禖??僪*

?&

這是因為keykb1.dat是一個二進制檔案,存放的是任意二進制數。

讀者運作時肯定結果和上面會有所不同,實際上2.2.1小節的程式每次運作時生成的密鑰都不會相同,這就保證了密鑰的唯一性。作為對稱密鑰,隻要保證若加密某段文字用的是某個密鑰,則解密這段密文時用同樣的密鑰即可。