使用JCE进行DES加密

时间:2024-02-21 08:13:57

1、 

引言

随着科技的日益发达,人们在对方便性要求逐渐提高的同时,对安全性的要求也日益提高。而使用加密的方法保护文件已成为计算机安全应用中重要的组成部分。DES加密方法作为一种世界标准的加密形式, 已经15 年历史了,虽然有些老, 可还算是比较可靠的算法,因此在加密应用中还是有一定的市场。

2、  DES算法简介

DES是一个分组加密算法,他以64位为分组对数据加密。同时DES也是一个对称算法:加密和解密用的是同一个密钥。它的密钥长度是56位(因为每8位的最后一位都用作奇偶校验),密钥可以是任意的56位的数,而且可以任意时候改变。其中有极少量的数被认为是弱密钥,但是很容易避开他们,所以保密性依赖于密匙。虽然DES算法实现起来比较简单,加解密速度也比较快,但是因为密钥过短,比较容易被破解,地位就逐渐被其他的加密算法取代。

3、  JCE简介及配置
虽然JDK1.4将java安全包包含在核心库中,但如果不对jce进行配置,也没办法使用jce进行开发。

        首先从sun网上下载jce1.2.2(我在网上看到的都是下载一个包,没用sun默认的),然后把解压得到的lib里面的所有jar文件拷到your_jdk/jre/lib/ext(your_jdk为你的jdk安装目录),编辑your_jdk/jre/lib/security/java.policy文件,在最后加上

grant codeBase "file:${java.home}/lib/ext/sunjce_provider.jar" {
   permission java.io.FilePermission
      
"file:${java.home}/lib/ext/sunjce_provider.jar""read";
   permission java.lang.RuntimePermission
      
"getProtectionDomain";
   permission java.security.SecurityPermission
      
"putProviderProperty.SunJCE";
}
;

给sunjce_provider授予访问权限

        your_jdk/jre/lib/security/java.security里面配置了可选的provider类型,这里用默认配置就行了

4、  DES加密程序

     这个加密程序的密钥采取自动生成的方式,并把生成的密钥保存在文件中。这样只要拥有密钥文件就可以加解密从而避免了用户忘记密钥的问题,同时,由于每次加密使用的密钥都不相同,提高了安全性。

在设计这个加密程序的时候,考虑到以后这个程序的复用性,我将程序分为三个类:

BytesCipher:提供了对byte型数组进行加解密的功能,同时还可以生成DES密钥。

FileCipher:提供了对文件加解密的功能(先将文件转换成byte型数组),同时可以保存、读取密钥。

DESCipher:主程序类。我将整个程序设计成命令行形式,仿照dos命令,用户输入命令和相应的参数就可以执行程序,同时可以查看帮助。

在异常处理方面,我把程序执行过程中抛出的异常进行了二次处理,加上了自己赋予的异常信息,再发送到主函数中统一处理。

BytesCipher类代码:

import java.security.*;
import javax.crypto.spec.*;
import javax.crypto.*;

public class BytesCipher {

    
//默认使用des加密
    private static String algorithm = "DES";

    
/**
     * 使用JDK中的JCE生成密钥
     
*/

    
public static byte[] generateKey() throws Exception {
        
try {
            
//生成一个可信任的随机数源
            SecureRandom sr = new SecureRandom();
            
//为我们选择的DES算法生成一个KeyGenerator对象
            KeyGenerator kg = KeyGenerator.getInstance(algorithm);
            kg.init(sr);
            
//生成密钥
            SecretKey key = kg.generateKey();
            
//返回密钥的二进制形式
            return key.getEncoded();
        }
 catch (Exception e) {
            
throw new Exception("没有这种加密算法");
        }

    }


    
/**
     * 根据密钥对明文进行加密,返回密文
     
*/

    
public static byte[] encrypt(byte[] plaintext, byte[] key) throws Exception {
        
try {
            
//产生一个可信任的随机数源
            SecureRandom sr = new SecureRandom();
            
//从原始密钥数据创建DESKeySpec对象
            DESKeySpec dks = new DESKeySpec(key);
            
//创建一个密钥工厂,然后用它把DESKeySpec转换成Secret Key对象
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
            SecretKey keySpec 
= keyFactory.generateSecret(dks);
            
//Cipher对象实际完成加密操作
            Cipher cipher = Cipher.getInstance(algorithm);
            
//用密钥初始化Cipher对象
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, sr);
            
//执行加密操作
            byte[] cryptotext= cipher.doFinal(plaintext);
            
return cryptotext;
        }
 catch (InvalidKeyException e) {
            
throw new Exception("密钥非法");
        }
 catch (NoSuchAlgorithmException e) {
            
throw new Exception("没有这种加密算法");
        }
 catch (BadPaddingException e) {
            
throw new Exception("加密失败");
        }

    }


    
/**
     * 根据密钥对密文进行加密,返回明文
     
*/

    
public static byte[] decrypt(byte[] cryptotext, byte[] key) throws Exception {
//上面与加密代码相同
            cipher.init(Cipher.DECRYPT_MODE, keySpec, sr);
            
//执行解密操作,下面与加密代码基本相同
}


 

FileCipher类代码:

 

import java.io.*;
import java.nio.*
;
import java.nio.channels.*
;

public class FileCipher 
{

    
//明文

    private static byte[] plaintext=null;
    
//密文

    private static byte[] cryptotext=null;
    
//密钥

    private static byte[] key;

    
/**
     * 从文件中读数据,返回byte型数组
     
*/

    
private static byte[] readFile(String filename) throws Exception {
        
try 
{
        File f 
= new
 File(filename);
        FileInputStream fs 
= new
 FileInputStream(f);
        FileChannel fc 
=
 fs.getChannel();
        
//只要文件大小不超过2G(int的范围)即可加密

        int size = (int) fc.size();
        
//采用DirectBuffer的方式读文件数据,属于JDK1.4的API,处理大容量数据更快

        ByteBuffer buffer=ByteBuffer.allocateDirect(size);
        
//通过文件通道将文件内容读入ByteBuffer

        fc.read(buffer);
        
//buffer操作完一次必须flip回到最初位置,才能再进行操作

        buffer.flip();
        
byte[] byteArray=new byte
[size];
        
//将缓冲区内容存入数组

        buffer.get(byteArray);
        buffer.clear();
        fc.close();
        fs.close();
        
return
 byteArray;
        }
 catch (FileNotFoundException e) {
            
throw new Exception("文件未找到"
);
        }
 catch (IOException e) {
            
throw new Exception("文件操作错误"
);
        }

    }


    
/**
     * 将byte型数组内容写入文件
     
*/

    
private static void writeFile(String filename,byte[] byteArray) throws Exception {
            
//与读文件类似、省略

    }


    
/**
     * 根据密钥对制定文件加密
     
*/

    
public static void fileEncrypt(String filename,byte[] key) throws Exception {
        plaintext
=
readFile(filename);
        cryptotext
=
BytesCipher.encrypt(plaintext,key);
        writeFile(filename,cryptotext);
    }


    
/**
     * 根据密钥对指定文件解密
     
*/

    
public static void fileDecrypt(String filename,byte[] key) throws Exception {
        cryptotext
=
readFile(filename);
        plaintext
=
BytesCipher.decrypt(cryptotext,key);
        writeFile(filename,plaintext);
    }


    
/**
     * 将得到的密钥保存到文件
     
*/

    
public static void saveKey(String filename,byte[] key) throws Exception  {
        writeFile(filename,key);
    }


    
/**
     * 从文件中读出密钥,返回byte数组形式
     
*/

    
public static byte[] loadKey(String filename) throws Exception  {
        key
=
readFile(filename);
        
return
 key;
    }

}

DESCipher类代码:

 

import java.io.*;

public class DESCipher{

        
/**
         * 打印命令的帮助信息
         
*/

        
public static void printHelp() {
            
//都是输出函数、省略
    }


    
public static void main(String[] args) {
        
try{
            
//用户没有输入参数,则打印帮助
            if(args.length==0{
                printHelp();
                
return;
            }

            
//用户输入参数个数不够,则提示用户,并打印帮助
            if(args.length<3{
                System.out.println(
"参数不够,参数必须有三个");
                printHelp();
                
return;
            }

            
//用户选择加密
            if(args[0].equalsIgnoreCase("-e")) {
                
//生成随机密钥
                byte[] key=BytesCipher.generateKey();
                
//存入密钥文件
                FileCipher.saveKey(args[2],key);

                
//根据待加密文件,密钥加密
                FileCipher.fileEncrypt(args[1],key);
                System.out.println(
"用DES对"+args[1]+"加密成功,密钥放在"+args[2]);
            }
 //用户选择解密
             else if(args[0].equalsIgnoreCase("-d")) {
                
//从文件中读入密钥
                byte[] key2=FileCipher.loadKey(args[2]);

                
//用密钥对该文件解密
                FileCipher.fileDecrypt(args[1],key2);
                System.out.println(
""+args[2]+"里的密钥对"+args[1]+"使用DES解密成功");
            }
 else {
                System.out.println(
"参数输入错误");
                printHelp();
            }

        }
 catch (Exception e) {
            
//所有的异常都放在DESCipher里集中处理
            System.out.println(e.getMessage());
        }

    }

}

 

 例如对c:/1.txt进行des加密,将密钥保存在c:/key.txt。在命令提示符下进入JCE/classes,输入:java DESCipher –e c:/1.txt c:/key.txt。要解密时,只需把-e换成-d就行了。在程序运行的时候,我感到速度比较慢,而且待加解密文件的大小对速度的影响不是很大,这可能是因为jvm本身的性能问题,或是动态加载Provider时比较慢。