JAVA加密解密之PBE(Password Based Encryption)算法

x33g5p2x  于2021-12-25 转载在 其他  
字(7.2k)|赞(0)|评价(0)|浏览(308)

PBE算法简介

PBE(Password Based Encryption,基于口令加密)是一种基于口令的加密算法,其特点是使用口令代替了密钥,而口令由用户自己掌管,采用随机数杂凑多重加密等方法保证数据的安全性。PBE算法在加密过程中并不是直接使用口令来加密,而是加密的密钥由口令生成,这个功能由PBE算法中的KDF函数完成。KDF函数的实现过程为:将用户输入的口令首先通过“盐”(salt)的扰乱产生准密钥,再将准密钥经过散列函数多次迭代后生成最终加密密钥,密钥生成后,PBE算法再选用对称加密算法对数据进行加密,可以选择DES、3DES、RC5等对称加密算法。

PBE算法实现

package com.jianggujin.codec;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import com.jianggujin.codec.util.JCipherInputStream;
import com.jianggujin.codec.util.JCipherOutputStream;
import com.jianggujin.codec.util.JCodecException;

/** * Password-based encryption(基于密码加密) * * @author jianggujin * */
public class JPBE {
   /** * 默认迭代次数 */
   public static final int DEFAULT_ITERATION_COUNT = 100;

   /** * PBE算法 * * @author jianggujin * */
   public static enum JPBEAlgorithm {
      PBEWithMD5AndDES, PBEWithSHA1AndDESede, PBEWithSHA1AndRC2_40;

      public String getName() {
         return this.name();
      }
   }

   /** * 初始化盐 * * @return */
   public static byte[] initSalt() {
      byte[] salt = new byte[8];
      Random random = new Random();
      random.nextBytes(salt);
      return salt;
   }

   /** * 加密 * * @param data * @param password * @param salt * @param algorithm * @return */
   public static byte[] encrypt(byte[] data, char[] password, byte[] salt, String algorithm) {
      return encrypt(data, password, salt, DEFAULT_ITERATION_COUNT, algorithm);
   }

   /** * 加密 * * @param data * @param password * @param salt * @param iterationCount * @param algorithm * @return */
   public static byte[] encrypt(byte[] data, char[] password, byte[] salt, int iterationCount, String algorithm) {
      // 数据加密
      Cipher cipher = getEncryptCipher(password, salt, iterationCount, algorithm);

      try {
         return cipher.doFinal(data);
      } catch (Exception e) {
         throw new JCodecException(e);
      }
   }

   /** * 包裹输出流,包裹后的输出流为加密输出流 * * @param out * @param password * @param salt * @param algorithm * @return */
   public static OutputStream wrap(OutputStream out, char[] password, byte[] salt, String algorithm) {
      return wrap(out, password, salt, DEFAULT_ITERATION_COUNT, algorithm);
   }

   /** * 包裹输出流,包裹后的输出流为加密输出流 * * @param out * @param password * @param salt * @param iterationCount * @param algorithm * @return */
   public static OutputStream wrap(OutputStream out, char[] password, byte[] salt, int iterationCount,
         String algorithm) {
      // 数据加密
      Cipher cipher = getEncryptCipher(password, salt, iterationCount, algorithm);

      return new JCipherOutputStream(cipher, out);
   }

   /** * 获得加密模式的{@link Cipher} * * @param password * @param salt * @param algorithm * @return */
   public static Cipher getEncryptCipher(char[] password, byte[] salt, String algorithm) {
      return getEncryptCipher(password, salt, DEFAULT_ITERATION_COUNT, algorithm);
   }

   /** * 获得加密模式的{@link Cipher} * * @param data * @param password * @param salt * @param iterationCount * @param algorithm * @return */
   public static Cipher getEncryptCipher(char[] password, byte[] salt, int iterationCount, String algorithm) {
      return getCipher(password, salt, iterationCount, algorithm, Cipher.ENCRYPT_MODE);
   }

   /** * 解密 * * @param data * @param password * @param salt * @param algorithm * @return */
   public static byte[] decrypt(byte[] data, char[] password, byte[] salt, String algorithm) {
      return decrypt(data, password, salt, DEFAULT_ITERATION_COUNT, algorithm);
   }

   /** * 解密 * * @param data * @param password * @param salt * @param iterationCount * @param algorithm * @return */
   public static byte[] decrypt(byte[] data, char[] password, byte[] salt, int iterationCount, String algorithm) {
      // 数据解密
      Cipher cipher = getDecryptCipher(password, salt, iterationCount, algorithm);
      try {
         return cipher.doFinal(data);
      } catch (Exception e) {
         throw new JCodecException(e);
      }
   }

   /** * 包裹输入流,原输入流为加密数据输入流 * * @param in * @param password * @param salt * @param algorithm * @return */
   public static InputStream wrap(InputStream in, char[] password, byte[] salt, String algorithm) {
      return wrap(in, password, salt, DEFAULT_ITERATION_COUNT, algorithm);
   }

   /** * 包裹输入流,原输入流为加密数据输入流 * * @param in * @param password * @param salt * @param iterationCount * @param algorithm * @return */
   public static InputStream wrap(InputStream in, char[] password, byte[] salt, int iterationCount, String algorithm) {
      // 数据解密
      Cipher cipher = getDecryptCipher(password, salt, iterationCount, algorithm);
      return new JCipherInputStream(cipher, in);
   }

   /** * 获得解密模式的{@link Cipher} * * @param password * @param salt * @param algorithm * @return */
   public static Cipher getDecryptCipher(char[] password, byte[] salt, String algorithm) {
      return getDecryptCipher(password, salt, DEFAULT_ITERATION_COUNT, algorithm);
   }

   /** * 获得解密模式的{@link Cipher} * * @param password * @param salt * @param iterationCount * @param algorithm * @return */
   public static Cipher getDecryptCipher(char[] password, byte[] salt, int iterationCount, String algorithm) {
      return getCipher(password, salt, iterationCount, algorithm, Cipher.DECRYPT_MODE);
   }

   private static Cipher getCipher(char[] password, byte[] salt, int iterationCount, String algorithm, int opmode) {
      // 生成本地密钥
      SecretKey secretKey = getSecretKey(password, algorithm);
      PBEParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
      try {
         // 数据加密
         Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
         cipher.init(opmode, secretKey, paramSpec);
         return cipher;
      } catch (Exception e) {
         throw new JCodecException(e);
      }
   }

   private static SecretKey getSecretKey(char[] password, String algorithm) {
      try {
         PBEKeySpec keySpec = new PBEKeySpec(password);
         SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
         return keyFactory.generateSecret(keySpec);
      } catch (Exception e) {
         throw new JCodecException(e);
      }
   }
}

测试代码:

package com.jianggujin.codec.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

import org.junit.Test;

import com.jianggujin.codec.JBase64;
import com.jianggujin.codec.JBase64.JEncoder;
import com.jianggujin.codec.JPBE;
import com.jianggujin.codec.JPBE.JPBEAlgorithm;

public class PBETest {
   String str = "jianggujin";
   String password = "12345678";
   File file = new File(getClass().getSimpleName() + ".dat");

   @Test
   public void test() throws Exception {
      System.out.println("原串:" + str);
      JEncoder encoder = JBase64.getEncoder();
      byte[] salt = JPBE.initSalt();
      System.out.println("盐:" + encoder.encodeToString(salt, "UTF-8"));
      System.out.println("密码:" + password);
      for (JPBEAlgorithm algorithm : JPBEAlgorithm.values()) {
         System.out.println("-----------------------------------------");
         System.out.println("算法:" + algorithm.getName());
         byte[] encrypt = JPBE.encrypt(str.getBytes(), password.toCharArray(), salt, algorithm.getName());
         System.out.println("加密:" + encoder.encodeToString(encrypt, "UTF-8"));
         System.out
               .println("解密:" + new String(JPBE.decrypt(encrypt, password.toCharArray(), salt, algorithm.getName())));

         System.out.print("输出流加密:" + file.getAbsolutePath());
         OutputStream out = JPBE.wrap(new FileOutputStream(file), password.toCharArray(), salt, algorithm.getName());
         out.write(str.getBytes());
         out.flush();
         out.close();
         System.out.println();
         System.out.print("输入流解密:");
         InputStream in = JPBE.wrap(new FileInputStream(file), password.toCharArray(), salt, algorithm.getName());
         byte[] buffer = new byte[1024];
         int len = in.read(buffer);
         System.out.println(new String(buffer, 0, len));
      }
   }
}

测试结果:
原串:jianggujin
盐:pWJQ1HJ61xY=
密码:12345678
—————————————–
算法:PBEWithMD5AndDES
加密:hHk6186Lq1+VmcgYzs/8lw==
解密:jianggujin
输出流加密:F:\workspace\java\eclipse\JCodec\PBETest.dat
输入流解密:jianggujin
—————————————–
算法:PBEWithSHA1AndDESede
加密:uN/5iUjaUKYjfTqas8dhvw==
解密:jianggujin
输出流加密:F:\workspace\java\eclipse\JCodec\PBETest.dat
输入流解密:jianggujin
—————————————–
算法:PBEWithSHA1AndRC2_40
加密:J7aT2klCSCAVjAg4q3cR5A==
解密:jianggujin
输出流加密:F:\workspace\java\eclipse\JCodec\PBETest.dat
输入流解密:jianggujin

相关文章