这是我参加全国信息安全大赛的设计的加密系统中的一个加密算法,虽然比赛的结果不是非常理想但是,我还是学到了很多东西,现在和大家分享一下,比赛收获的东西。

基于口令加密

PBE(Password Based Encryption,基于口令加密)算法是一种基于口令的加密算法,其特点在于口令是由用户自己掌握的,采用随机数杂凑多重加密等方法保证数据的安全性。

PBE算法没有密钥的概念,密钥在其它对称加密算法中是经过算法计算得出来的,PBE算法则是使用口令替代了密钥。

密钥的长短直接影响了算法的安全性,但不方便记忆。即便是我们将密钥经过Base64编码转换为一个可见字符,长密钥一样不容易记忆。因此,在这种情况下密钥是需要存储的,但是口令则不然。比如一般人天天开关电脑,进入操作系统的唯一途径就是输入口令。口令是我们便于记忆的一种凭证,基于这一点,PBE算法使用口令替代了密钥。

PBE算法并没有真正构建新的加密/解密算法,而是对我们已经知道的对称加密算法(如DES算法)做了包装。使用PBE算法对数据做加密/解密操作的时候,其实是使用了DES或者是AES等其它对称加密算法做了相应的操作。

既然PBE算法使用我们较为常用的对称加密算法,那就无法回避密钥的问题。口令并不能替代密钥,密钥是经过加密算法计算得来的,但是口令本身不可能很长看,单纯的口令很容易通过穷举攻击方式破译,这就引入了“盐”。盐能阻止字典攻击或预先计算的攻击,它本身是一个随机信息,相同的随机信息极不可能使用两次。将盐附加在口令上,通过消息摘要算法经过迭代计算获得构建密钥/初始化向量的基本材料,使得破译的难度加大。

基于PBE算法的消息传递模型如下图3-13所示:甲乙双方作为消息传递双方(甲方为发送方,也就是甲方是本系统的服务器,乙方作为接收方,也就是本系统客户端的使用者),假定甲乙双方在消息传递前已经商定加密算法迭代的次数,与完成一次消息传递需要经过如下步骤:

1)       由消息传递双方约定口令,这里由甲方构建口令。
2)       由口令构建者发布口令,即本系统的服务器将口令发送给系统的客户端使用者
3)       由口令构建者构建本次消息传递使用的盐,这里由甲方(本系统)构建盐
4)       由消息发送方使用口令、盐对数据加密,这里由甲方对数据加密
5)       由消息发送者将盐、加密数据放松给消息接收者,这里由甲方将盐、加密数据发送给乙方
6)       由消息接收方使用盐、口令对加密数据解密,这里由乙方完成数据解密

图3-13 基于PBE算法的消息通讯模型

基于PBE算法的消息传递模型理解起来并不是十分复杂。对于上述单项消息传递而言,如果乙方想要恢复甲方消息,甲方并不需要重复步骤1、2,仅仅想要由乙方执行3、4、5,由甲方执行步骤6即可。
       同时,甲乙双方也可以在消息传递过程中传递迭代次数。
       “盐”本身就是一种可以由消息传递双方按一定规律约定的消息,比如时间。也可以是某个不可变物理硬件的编号,比如U盘的自身唯一标识,而本系统则采用“手机的唯一标识”,WIM 是一个防篡改硬件,在安全层和应用层执行安全功能,保存处理用户的ID 和权限等功能。
      甲乙双方可以通过约定消息传递的时间,这里是由本系统直接决定时间,并将其作为基本消息,根据预定的算法(如MD5算法) 对其处理,最终获取真正的“盐”,这样一来,“盐”就无需传递,提高了安全性。
      假设一个场景:由这样的一个系统,用户使用者需要通过手机访问一个系统,同同时需要输入口令方能登录系统,那么手机本身就是“盐”的提供者!即使手机丢失,加密的信息也未必能被窃取!即“盐”与口令就像两把不可分离的钥匙。
PBE实现方案:
      Java 6 和Bouncy Castle都提供了PBE系列算法的相关实现,差别在于对各种消息摘要算法和对称加密算法的组合。常用的消息摘要算法包括MD5和SHA算法,常用的对称加密算法包括DES、RC2等。PBE系列算法就死将这些算法进行合理组合,其密钥长度均以PBE具体的算法中的对称加密算法为准。
有关PBE算法的Java6 和Bouncy Castle实现细节如下表3-11。

表3-11  PBE算法
总体看来口令和盐两边都需要知道。消息传递过程还是需要指定双方的统一算法进行。而这些算法其实还是用的那些常见的对称加密算法

三、java6和bouncycastle支持的算法列表
算法    密钥长度    密钥长度默认值    工作模式    填充方式    备注
PBEWithMD5AndDES    56    56    CBC    PKCS5Padding    java6实现
PBEWithMD5AndTripeDES    112、168    168    CBC    PKCS6Padding    java7实现
PBEWithSHA1AndDESede    112、168    168    CBC    PKCS7Padding    java8实现
PBEWithSHA1AndRC2_40    40至1024    128    CBC    PKCS8Padding    java9实现
                         
PBEWithMD5AndDES    64    64    CBC    PKCS5Padding/PKCS7Padding/ISO10126Padding/ZeroBytePadding    BouncyCastle实现
PBEWithMD5AndRC2    128    128    CBC    PKCS5Padding/PKCS7Padding/ISO10127Padding/ZeroBytePadding    BouncyCastle实现
PBEWithSHA1AndDES    64    64    CBC    PKCS5Padding/PKCS7Padding/ISO10128Padding/ZeroBytePadding    BouncyCastle实现
PBEWithSHA1AndRC2    128    128    CBC    PKCS5Padding/PKCS7Padding/ISO10129Padding/ZeroBytePadding    BouncyCastle实现
PBEWithSHAAndIDEA-CBC    128    128    CBC    PKCS5Padding/PKCS7Padding/ISO10130Padding/ZeroBytePadding    BouncyCastle实现
PBEWithSHAAnd2-KeyTripleDES-CBC    128    128    CBC    PKCS5Padding/PKCS7Padding/ISO10131Padding/ZeroBytePadding    BouncyCastle实现
PBEWithSHAAnd3-KeyTripleDES-CBC    192    192    CBC    PKCS5Padding/PKCS7Padding/ISO10132Padding/ZeroBytePadding    BouncyCastle实现
PBEWithSHAAnd128BitRC2-CBC    128    128    CBC    PKCS5Padding/PKCS7Padding/ISO10133Padding/ZeroBytePadding    BouncyCastle实现
PBEWithSHAAnd40BitRC2-CBC    40    40    CBC    PKCS5Padding/PKCS7Padding/ISO10134Padding/ZeroBytePadding    BouncyCastle实现
PBEWithSHAAnd128BitRC4    128    128    CBC    PKCS5Padding/PKCS7Padding/ISO10135Padding/ZeroBytePadding    BouncyCastle实现
PBEWithSHAAnd40BitRC4    40    40    CBC    PKCS5Padding/PKCS7Padding/ISO10136Padding/ZeroBytePadding    BouncyCastle实现
PBEWithSHAAndTwofish-CBC    256    256    CBC    PKCS5Padding/PKCS7Padding/ISO10137Padding/ZeroBytePadding    BouncyCastle实现

PBE实现代码:
PBECoder.java

  1. package com.wecode.database.secure;
  2.  
  3. import java.security.Key;
  4. import java.security.SecureRandom;
  5.  
  6. import javax.crypto.Cipher;
  7. import javax.crypto.SecretKey;
  8. import javax.crypto.SecretKeyFactory;
  9. import javax.crypto.spec.PBEKeySpec;
  10. import javax.crypto.spec.PBEParameterSpec;
  11.  
  12. /**
  13. * PBE安全编码组件
  14. *
  15. * @author WeCode ( ydonghao2 )
  16. * @version 1.0
  17. */
  18.  
  19. public class PBECoder {
  20. public static final String ALGORUTHM = "PBEWITHMD5andDES";
  21. /**
  22. * 迭代次数
  23. */
  24. public static final int ITERATION_COUN = 100;
  25.  
  26. /**
  27. * "盐"初始化<br>
  28. * 盐长度必须为8字节
  29. * @return byte[] 盐
  30. * @throws Exception
  31. */
  32. public static byte[] initSalt() throws Exception {
  33. //实例化安全随机数
  34. SecureRandom random = new SecureRandom();
  35. //产出盐
  36. return random.generateSeed(8);
  37. }
  38. /**
  39. * 转换密钥
  40. * @param password 密码
  41. * @return Key密钥
  42. * @throws Exception
  43. *
  44. */
  45.  
  46. private static Key toKey(String password) throws Exception {
  47. //密钥材料转换
  48. PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
  49. //实例化
  50. SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORUTHM);
  51. //生成密钥
  52. SecretKey secretkey = keyFactory.generateSecret(keySpec);
  53. return secretkey;
  54. }
  55.  
  56. /**
  57. * 加密
  58. * @param data 数据
  59. * @param password 密钥
  60. * @param salt 盐
  61. * @return byte[] 加密数据
  62. * @throws Exception
  63. */
  64.  
  65. public static byte[] encrypt(byte[] data, String password, byte[] salt) throws Exception{
  66. //转换密钥
  67. Key key = toKey(password);
  68. //实例化PBE参考数据
  69. PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, ITERATION_COUN);
  70. //实例化
  71. Cipher cipher = Cipher.getInstance(ALGORUTHM);
  72. //初始化
  73. cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec);
  74. //执行操作
  75.  
  76. return cipher.doFinal(data);
  77. }
  78.  
  79. /**
  80. * 解密
  81. * @param data 数据
  82. * @param password 密码
  83. * @param salt 盐
  84. * @return byte[] 解密数据
  85. * @throws Exception
  86. */
  87.  
  88. public static byte[] decrypt(byte[] data, String password, byte[] salt) throws Exception{
  89. //转换密钥
  90. Key key = toKey(password);
  91. //实例化PBE参数材料
  92. PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, ITERATION_COUN);
  93. //实例化
  94. Cipher cipher = Cipher.getInstance(ALGORUTHM);
  95. //初始化
  96. cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec);
  97. //执行操作
  98. return cipher.doFinal(data);
  99. }
  100. }

PBE算法是实现过程中需要关注的环节,包括“盐”的初始化,密钥材料的转化和加密/解密的时间。

在初始化“盐”时,必须使用随机的方式构造“盐”,最终要得到一个8字节的字节数组。鉴于安全性的要求,这里的随机数生成器只能使用SecureRandom类,如下所示:

  1. //实例化安全性随机数
  2. SecureRandomrandom = new SecureRandom();
  3. //产出“盐”
  4. byte[]b = random.generateSeed(8);

字节数组b[]就是我们要的“盐”。

密钥材料转换部分不同于其他对称加密算法,这里使用的是PBEKeySpec类,如下所示:

  1. //密钥材料转换
  2. PBEKeySpeckeySpec = new PBEKeySpec(password.toChatArray());

其他对称加密算法的密钥材料实现类的构造方法要求输入字节数组形式的变量,而PBEKeySpec类构造方法则要求输入字符数组变量。

为什么不是字符串(String)而是字符数组(char[])呢?这是因为字符串是可序列化的封装类,可在程序调用时被序列化到文件中,而字符数组只能以内存变量的形式保留在内存中。

在加密/解密实现时,需要注意使用参数材料PBEParameterSpec类,同时注意迭代次数。构建PBE参数材料后就可以转交给Cipher类完成加密/解密操作,如下所示:

  1. //实例化PBE参数材料
  2. PBEParameterSpecparamSpec = new PBEParameterSpec(salt, ITERATION_COUNT);
  3. //实例化
  4. Cipher= cipher = Cipher.getInstance(ALGORITHM);
  5. //初始化
  6. cipher.init(Cipher.DECRYPT_MODE,key, paramSpec);

- KEY_ALGORITHM 指明加密算法,这里是PBEWITHMD5andDES加密算法。
- ITERATION_COUN迭代的次数。
+initSalt()PBE加密方式的初始化盐返回的是byte[] 盐,盐长度必须为8字节。
+ toKey(Stringpassword) 转换密钥,password是密码,返回Key类型密钥。
+encrypt(byte[]data, String  password, byte[] salt) 加密方法。Data是数据,password是密钥,salt是盐,返回byte[]类型,是加密以后的数据。
+decrypt(byte[]data, String password, byte[] salt)解密方法,data是数据,password的密码,salt是盐,返回byte[]类型,是解以后的数据。

PBE算法实现和AES算法有很多类似的地方,相似的地方下面代码不具体介绍。

PBE的主要代码如下:
     本系统在这里采用的是PBEWITHMD5andDES算法。

  1. public static final String ALGORUTHM ="PBEWITHMD5andDES";

迭代次数

  1. public static final int ITERATION_COUN = 100;

"盐"初始化
盐长度必须为8字节
返回:
       byte[]盐
抛出:
java.lang.Exception

  1. public static byte[] initSalt() throws Exception {
  2. //实例化安全随机数
  3. SecureRandom random = new SecureRandom();
  4. //产出盐
  5. return random.generateSeed(8);
  6. }

转换密钥
参数:  
        password-密码
返回:
        Key密钥
抛出:
         java.lang.Exception
PBE算法定义并继承了SecretKey接口。

  1. private static Key toKey(String password) throws Exception {
  2. //密钥材料转换
  3. PBEKeySpec keySpec = newPBEKeySpec(password.toCharArray());
  4. //实例化
  5. SecretKeyFactory keyFactory =SecretKeyFactory.getInstance(ALGORUTHM);
  6. //生成密钥
  7. SecretKey secretkey =keyFactory.generateSecret(keySpec);
  8. return secretkey;
  9. }

加密方法
参数:
        data- 数据
        password- 密钥
        salt- 盐
返回:
        byte[]加密数据
抛出:
java.lang.Exception

  1. public static byte[] encrypt(byte[] data, String password, byte[] salt) throws Exception{
  2. //转换密钥
  3. Key key = toKey(password);
  4. //实例化PBE参考数据
  5. PBEParameterSpec parameterSpec = new PBEParameterSpec(salt,ITERATION_COUN);
  6. //实例化
  7. Cipher cipher = Cipher.getInstance(ALGORUTHM);
  8. //初始化
  9. cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec);
  10. //执行操作
  11.  
  12. return cipher.doFinal(data);
  13. }

解密方法
参数:
        data- 数据
        password- 密码
        salt- 盐
返回:
        byte[]解密数据
抛出:
       java.lang.Exception

  1. public static byte[] decrypt(byte[] data, String password,byte[] salt) throws Exception{
  2. //转换密钥
  3. Key key = toKey(password);
  4. //实例化PBE参数材料
  5. PBEParameterSpec parameterSpec = newPBEParameterSpec(salt, ITERATION_COUN);
  6. //实例化
  7. Cipher cipher = Cipher.getInstance(ALGORUTHM);
  8. //初始化
  9. cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec);
  10. //执行操作
  11. return cipher.doFinal(data);
  12. }

PBE算法实例验证PBECoder.java:
PBECoderTest.java

  1. package com.wecode.database.secure;
  2.  
  3. import org.apache.commons.codec.binary.Base64;
  4. import org.junit.Test;
  5.  
  6. /**
  7. * PBE 检验
  8. *
  9. * @author WeCode ydonghao2
  10. * @version 1.0
  11. */
  12.  
  13. public class PBECoderTest {
  14. /**
  15. * 测试
  16. *
  17. * @throws Exception
  18. */
  19. /**
  20. * 测试的时候人工可以引入junit.jar包
  21. * @throws Exception
  22. */
  23. //@Test
  24. public static void main(String[] args) throws Exception {
  25. String inputStr = "PBE";
  26. System.err.println("原文:\t" + inputStr);
  27. byte[] input = inputStr.getBytes();
  28. String pwd = "ydonghao";
  29. System.err.println("密码:\t" + pwd);
  30. // 初始化盐
  31. byte[] salt = PBECoder.initSalt();
  32. System.err.println("盐:\t" + Base64.encodeBase64String(salt));
  33. // 加密
  34. byte[] data = PBECoder.encrypt(input, pwd, salt);
  35. System.err.println("加密后\t" + Base64.encodeBase64String(data));
  36. // 解密
  37. byte[] output = PBECoder.decrypt(data, pwd, salt);
  38. String outputStr = new String(output);
  39. System.err.println("解密后\t" + outputStr);
  40. }
  41. }

这个加密算法的实现需要一些环境的搭建,参考这里:http://blog.csdn.net/ydonghao2/article/details/11046635

PBE加密算法的更多相关文章

  1. java-信息安全(三)-PBE加密算法

    概述 信息安全基本概念: PBE算法(Password Based Encryption,基于口令加密) PBE PBE算法(Password Based Encryption,基于口令加密)是一种基 ...

  2. JAVA实现对称加密

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.对称加密算法DES 1.概述:采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这 ...

  3. DES、3DES、AES、PBE对称加密算法实现及应用

    1.对称加密算法概述 对称加密算法是应用较早的加密算法,技术成熟.在对称加密算法中,数据发信方将明文和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去.收信方收到密文后,若想解读原文 ...

  4. Android应用安全开发之浅谈加密算法的坑

      <Android应用安全开发之浅谈加密算法的坑> 作者:阿里移动安全@伊樵,@舟海 阿里聚安全,一站式解决应用开发安全问题     Android开发中,难免会遇到需要加解密一些数据内 ...

  5. [Java 安全]加密算法

    Base64编码 算法简述 定义 Base64内容传送编码是一种以任意8位字节序列组合的描述形式,这种形式不易被人直接识别. Base64是一种很常见的编码规范,其作用是将二进制序列转换为人类可读的A ...

  6. 使用java库中的对称加密算法

    对称加密算法是说加密方和解密方使用相同的密钥.常见的对称加密算法包括4个,DES,DESede(3DES),AES,PBE. 本文讨论的内容是加密算法,不是Message Digest,不是编码.下面 ...

  7. 介绍对称加密的另一个算法——PBE

    除了DES,我们还知道有DESede(TripleDES,就是3DES).AES.Blowfish.RC2.RC4(ARCFOUR)等多种对称加密方式,其实现方式大同小异,这里介绍对称加密的另一个算法 ...

  8. Java加密技术(一)——BASE64与单向加密算法MD5&SHA&MAC

    Java加密技术(一)——BASE64与单向加密算法MD5&SHA&MAC 博客分类: Java/Security Javabase64macmd5sha     加密解密,曾经是我一 ...

  9. BASE64与单向加密算法MD5&SHA&MAC

    言归正传,这里我们主要描述Java已经实现的一些加密解密算法,最后介绍数字证书.     如基本的单向加密算法: BASE64 严格地说,属于编码格式,而非加密算法 MD5(Message Diges ...

随机推荐

  1. Eclipse 视图

    Eclipse 视图 关于视图 Eclipse视图允许用户以图表形式更直观的查看项目的元数据. 例如,项目导航视图中显示的文件夹和文件图形表示在另外一个编辑窗口中相关的项目和属性视图. Eclipse ...

  2. 【转载】ASP和ASP.NET根本区别

    ASP.NET和ASP的最大区别在于编程思维的转换,而不仅仅在于功能的增强.ASP使用VBS/JS这样的脚本语言混合html来编程,而那些脚本语言属于弱类型.面向结构的编程语言,而非面向对象,这就明显 ...

  3. Android gdb so

    gdb debug an android application 1.gdb 要有gdbserver 一般模拟器默认装有gdbserver,如2.3.3的模拟器,看一下有没有: D:\Develope ...

  4. [框架安装趟雷指南]Ubuntu+1060+cuda+cudnn+Keras+TH+TF+MXnet

    [框架安装趟雷指南]Ubuntu+1060+cuda+cudnn+Keras+TH+TF+MXnet https://zhuanlan.zhihu.com/p/23480983 天清 9 个月前 写这 ...

  5. Appium python自动化测试系列之Capability介绍(五)

    ​5.1 Capability介绍 5.1.1 什么是Capability 在讲capability之前大家是否还记得在讲log时给大家看过的启动时的日志?在我们的整个启动日志中会出现一些配置信息,其 ...

  6. 第 1 章 第 2 题 空间敏感排序问题 位向量实现( bitset位向量 )

    问题分析 在上篇文章中,给出了使用C语言中经典位运算符来实现位向量的方法.而本文,将介绍使用C++中的bitset容器来实现位向量的方法. 实现 // 请包含bitset头文件 #include &l ...

  7. git和github菜鸟使用步骤

    刚刚在windows7下安装完git.奉上安装步骤. git安装 安装git程序.运行以下操作: 1. $ cd ~/.ssh    //检查计算机ssh密钥 2.假设没有提示:No such fil ...

  8. SAM4E单片机之旅——2、LED闪烁之轮询定时器

    之前我们使用空循环,达到了延迟的目的,但是这样子的延迟比较不精确.现在就使用实时定时器(RTT)来进行更为精确的计时.RTT虽然不是特别通用,在某些单片机上可能没有,但它较为简单. RTT内部有一个计 ...

  9. RabbitMQ 基础

    Windows下安装RabbitMq 下载RabbitMq 安装参考 http://www.rabbitmq.com/install-windows.html 下载Erlang Erlang 下载安装 ...

  10. Thread join方法的用途

    主线程中会创建多个子线程做一些事情,主线程要用到这些子线程处理的数据,因此它需要等待所有的子线程处理完之后才继续运行.这就要用到join方法了.