Rijndacel基于口令的对称加密

来源:互联网 发布:python开发聊天机器人 编辑:程序博客网 时间:2024/05/21 01:57

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.Key;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/*
 *采用ASE加密算法(也就是Rijndacel)加密文件,对文件解密需要同样的密钥
 *通过用口令对密钥进行加密,并把加密后的密钥存储在文件中
 * CipherStream文件加密器,基与口令的密钥加密,加密的密钥存储在
 * 一个二进制文件中,一般的软件无法打开.这儿首次通过判段数组中是
 *第一个数据判断是进行创建密钥还是其他,注意基于口令的加密口令必须
 *是字符数组。
 *
 */
/* 注意:最后一个导入的包从www.bouncycastle.org中下载,完整版crypto-147
 *       需要文件crypto-147\jars\jce-jdk13-147.jar放到jre\lib\ext不过我是
 *       直接放到创建文件夹的lib下面
 *       配置java.security文件使提供者可以使用
 *       步骤jre\lib\security下打开java.security文件
 *       security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider
*/       貌似也没什么效果
public class FileEncrytor {
  private int iteration = 100;
  private String Key_Filename = "RijndaelKey.bin";//二进制文件,必须用特殊软件才

能打开
   public void ManageCipherStream(String  arg[]) throws Exception{
   
    char psd[]=arg[1].toCharArray();
    Security.addProvider( new BouncyCastleProvider());
   
   
    if(arg.length < 2 || arg.length > 4){
     System.out.println("Usage:-c|-e|-d psd [inputFile] [outputFile]");
     System.exit(1);
    }
    if("-c".equals(arg[0])){
     generateKey(psd);
   
    }
    else if ("-e".equals(arg[0])){
     encryt(psd, arg[2], arg[3]);
    
    }
    else if("-d".equals(arg[0])){
     decryt(psd,arg[2], arg[3]);
    
    }
    else{
     System.out.println("Usage:-c|-e|-d psd [inputFile] [outputFile]");
    }
   
   
   }
   /*采用ASE加密算法产生密钥,create a 256-bit Rijndael key and stores it to
    * the filesystem as a KeyStore
    */
   private  void generateKey(char psd[]) throws Exception{
    KeyGenerator keyGenerator =KeyGenerator.getInstance("Rijndael");
    keyGenerator.init(256);//java.security.InvalidParameterException: Wrong

keysize: must be equal to 128, 192 or 256
    Key key = keyGenerator.generateKey(); 
    byte [] salt =new byte[8];
    SecureRandom random= new  SecureRandom();
    random.nextBytes(salt);
   
    PBEKeySpec pbeKeySpec = new PBEKeySpec(psd);
    SecretKeyFactory keyFortory = SecretKeyFactory.getInstance

("PBEWithSHAAndTwofish-CBC");
    SecretKey pbeKey=keyFortory.generateSecret(pbeKeySpec);
    PBEParameterSpec pbeParaSpec= new PBEParameterSpec(salt, iteration);
    Cipher cipher =  Cipher.getInstance("PBEWithSHAAndTwofish-CBC");  
    cipher .init(Cipher.ENCRYPT_MODE, pbeKey, pbeParaSpec);??????????

??
    byte [] encryptedKeyBytes = cipher.doFinal(key.getEncoded());   
    File keyFileName = new File(Key_Filename);
    if(!keyFileName.exists()){
     keyFileName.createNewFile();
    }
    FileOutputStream fos = new FileOutputStream(keyFileName);
    fos.write(salt);
    fos.write(encryptedKeyBytes);
    fos.flush();
    fos.close();
   
   
   
   }
   //从文件系统中加载key.使用口令解密后返回密钥明文
   private  Key loadKey(char psd[]) throws Exception{
   
    FileInputStream in = new FileInputStream(Key_Filename);
    ByteArrayOutputStream baos =new ByteArrayOutputStream();
    int i=0;
    while((i=in.read())!=-1){
     baos.write(i);  
    }
    in.close();
    byte[] saltAndKeyBytes =baos.toByteArray();
    baos.close();
   
    byte [] salt = new byte[8];
    System.arraycopy(saltAndKeyBytes, 0, salt, 0, 8);
    int keyByteLength = saltAndKeyBytes.length-8;
    byte [] encrytedKeyBytes = new byte[keyByteLength];
    System.arraycopy(saltAndKeyBytes, 8, encrytedKeyBytes, 0,

encrytedKeyBytes.length);
   
    PBEKeySpec pbeKeySpec = new PBEKeySpec(psd);
    SecretKeyFactory keyFortory = SecretKeyFactory.getInstance

("PBEWithSHAAndTwofish-CBC");
    SecretKey pbeKey=keyFortory.generateSecret(pbeKeySpec);
    PBEParameterSpec pbeParaSpec= new PBEParameterSpec(salt, iteration); 
    Cipher cipher =  Cipher.getInstance("PBEWithSHAAndTwofish-CBC");
    cipher .init(Cipher.DECRYPT_MODE, pbeKey, pbeParaSpec);
   
    byte decrytedKeyBytes[]=cipher.doFinal(encrytedKeyBytes);
  
    SecretKeySpec key = new SecretKeySpec(decrytedKeyBytes, "Rijndael");
    return key;//向上转型
   
   }
  
   private  void encryt(char psd[],String FileInput,String FileOutput)throws Exception{
   
    Key key=loadKey(psd);
    Cipher cipher =  Cipher.getInstance("Rijndael/CBC/PKCS5Padding");
    SecureRandom random= new  SecureRandom();//安全随机数会花一点时间
    byte [] iv =new byte[16];
    random.nextBytes(iv);
   
    IvParameterSpec  ivSpec= new  IvParameterSpec(iv);
    cipher.init(Cipher.ENCRYPT_MODE, key,ivSpec);
   
    FileInputStream in = new  FileInputStream(FileInput);
    FileOutputStream out = new FileOutputStream(FileOutput);
    out.write(iv);//把iv作为最开始的16个字节写在文件中
    CipherOutputStream cops = new CipherOutputStream(out, cipher);
    int encrytWriteByte = 0;
    while((encrytWriteByte =in.read())!=-1){
     cops.write(encrytWriteByte);
    
    }
    in.close();
    out.close();
    cops.flush();
    cops.close();
   
   
   
   }
   private  void decryt(char psd[],String FileInput,String FileOutput)throws Exception{
    Key key=loadKey(psd);
    Cipher cipher =  Cipher.getInstance("Rijndael/CBC/PKCS5-Padding");
   
    FileInputStream in = new  FileInputStream(FileInput);
    FileOutputStream out = new FileOutputStream(FileOutput);
    byte [] iv =new byte[16];
    in.read(iv);//把字节数组分配的内存读满后不产生异常
   
    IvParameterSpec  ivSpec= new  IvParameterSpec(iv);
    cipher.init(Cipher.DECRYPT_MODE, key,ivSpec);
    CipherInputStream cips = new CipherInputStream(in, cipher);
   
    int decryteWriteByte = 0;
    while((decryteWriteByte= cips.read())!=-1){
     out.write(decryteWriteByte);
    
    }
    in.close();
    out.close();
    cips.close();
   
   
   
   }
 
 
}

调用FileEncrytor.java
/*问题1:为什么密钥的长度不能超过7
 *
 *问题2:为什么密要长度时256bit时,无法对文件进行对称加密
 *
 *问题3:当把Rijndael/CBC/PKCS5Padding换成RC4流加密解密算法时
 *密钥生成使用DESede算法,提示:
 *java.security.InvalidKeyException: Not an ARCFOUR key: DESede
 */
import java.io.File;
public class ExecFileEncrytor {
 
 public static void main(String[] args) {
  
         String psd = "12345678";
  String inputFile = "D:"+File.separator+"inputFile.txt" ;
  String outputFile = "D:"+File.separator+"outputFile.txt";
  
  String arg[]={"-c",psd,inputFile,outputFile};
  
  FileEncrytor fileE = new FileEncrytor();
  try {
   
   fileE.ManageCipherStream(arg);
  } catch (Exception e) {
   e.printStackTrace();
  }
   
  

 }

}

原创粉丝点击