创建基于密码的加密密钥

本文讨论了创建基于密码的加密PBE密钥。

首先提醒您以前的要点–通常,在实际操作中,应将PBE密钥用作主密钥,该主密钥仅用于解锁工作密钥。 这具有三个主要优点:

  • 您可以有多个密码,例如,托管的恢复密钥,
  • 您无需更改密码即可更改密码,
  • 您可以更改工作密钥,而不必强行更改密码。

我将在以后的文章中讨论在数据库加密中使用工作密钥。

使用PBKDF2WithHmacSHA1的基于密码的加密密钥生成

Java过去没有创建PBE密钥的标准方法。 各个密码提供者提供了自己的生成器,但是识别和使用与您的密码匹配的生成器是一个痛苦的过程。

Java 7对此进行了更改。现在,所有JCE实现中都提供了一种标准的密钥生成算法。 它绝对可以用于生成AES密钥。 我已经看到了一个示例,该示例用于生成任意长度的密钥,但是我无法复制该行为–这可能是非标准扩展。

该算法采用四个参数。 第一个是密钥长度– AES密钥使用128。 其他可能的值是192和256位。 第二个是迭代次数。 您的wifi路由器使用4096次迭代,但是现在很多人建议至少进行10,000次迭代。

第三个参数是“盐”。 wifi路由器使用SSID,许多站点使用一个小文件,下面我将讨论另一种方法。 盐应足够大,以使熵大于密钥长度。 例如,如果要使用128位密钥,则应该(至少)具有128位随机二进制数据或大约22个随机字母数字字符。

最后一个参数是密码。 同样,熵应大于密钥长度。 在Webapp中,密码通常是由应用服务器通过JNDI提供的。

最后,我们既需要密码密钥,又需要IV,而不仅仅是密码密钥。 缺乏IV或使用较弱的IV是不熟悉密码学的人最常见的错误之一。 (请参阅: 不使用具有密码块链接模式的随机初始化矢量 [owasp.org]。)一种常见的方法是生成随机盐,并将其添加到密文中以供解密期间使用,但是我将讨论另一种使用密码和盐。

现在的代码。 首先,我们了解如何从密码和盐创建密码密钥和IV。 (我们待会儿讨论盐。)

public class PbkTest {private static final Provider bc = new BouncyCastleProvider();private static final ResourceBundle BUNDLE = ResourceBundle.getBundle(PbkTest.class.getName());private SecretKey cipherKey;private AlgorithmParameterSpec ivSpec;/*** Create secret key and IV from password.* * Implementation note: I've believe I've seen other code that can extract* the random bits for the IV directly from the PBEKeySpec but I haven't* been able to duplicate it. It might have been a BouncyCastle extension.* * @throws Exception*/public void createKeyAndIv(char[] password) throws SecurityException,NoSuchAlgorithmException, InvalidKeySpecException {final String algorithm = "PBKDF2WithHmacSHA1";final SecretKeyFactory factory = SecretKeyFactory.getInstance(algorithm);final int derivedKeyLength = 128;final int iterations = 10000;// create saltfinal byte[][] salt = feistelSha1Hash(createSalt(), 1000);// create cipher keyfinal PBEKeySpec cipherSpec = new PBEKeySpec(password, salt[0],iterations, derivedKeyLength);cipherKey = factory.generateSecret(cipherSpec);cipherSpec.clearPassword();// create IV. This is just one of many approaches. You do// not want to use the same salt used in creating the PBEKey.try {final Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", bc);cipher.init(Cipher.ENCRYPT_MODE, cipherKey, new IvParameterSpec(salt[1], 0, 16));ivSpec = new IvParameterSpec(cipher.doFinal(salt[1], 4, 16));} catch (NoSuchPaddingException e) {throw new SecurityException("unable to create IV", e);} catch (InvalidAlgorithmParameterException e) {throw new SecurityException("unable to create IV", e);} catch (InvalidKeyException e) {throw new SecurityException("unable to create IV", e);} catch (BadPaddingException e) {throw new SecurityException("unable to create IV", e);} catch (IllegalBlockSizeException e) {throw new SecurityException("unable to create IV", e);}}
}

我们可以简单地加载包含随机二进制数据的文件,但是使用Feistel密码可以使我们混合来自两个来源的熵。

/*** Create salt. Two values are provided to support creation of both a cipher* key and IV from a single password.* * The 'left' salt is pulled from a file outside of the app context. this* makes it much harder for a compromised app to obtain or modify this* value. You could read it as classloader resource but that's not really* different from the properties file used below. Another possibility is to* load it from a read-only value in a database, ideally one with a* different schema than the rest of the application. (It could even be an* in-memory database such as H2 that contains nothing but keying material,* again initialized from a file outside of the app context.)* * The 'right' salt is pulled from a properties file. It is possible to use* a base64-encoded value but administration is a lot easier if we just take* an arbitrary string and hash it ourselves. At a minimum it should be a* random mix-cased string of at least (120/5 = 24) characters.* * The generated salts are equally strong.* * Implementation note: since this is for demonstration purposes a static* string in used in place of reading an external file.*/public byte[][] createSalt() throws NoSuchAlgorithmException {final MessageDigest digest = MessageDigest.getInstance("SHA1");final byte[] left = new byte[20]; // fall back to all zeroesfinal byte[] right = new byte[20]; // fall back to all zeroes// load value from file or database.// note: we use fixed value for demonstration purposes.final String leftValue = "this string should be read from file or database";if (leftValue != null) {System.arraycopy(digest.digest(leftValue.getBytes()), 0, left, 0,left.length);digest.reset();}// load value from resource bundle.final String rightValue = BUNDLE.getString("salt");if (rightValue != null) {System.arraycopy(digest.digest(rightValue.getBytes()), 0, right, 0,right.length);digest.reset();}final byte[][] salt = feistelSha1Hash(new byte[][] { left, right },1000);return salt;}

使用资源束(在类路径中可见)和从文件系统或数据库加载的字符串的实际实现是:

/*** Create salt. Two values are provided to support creation of both a cipher* key and IV from a single password.* * The 'left' salt is pulled from a file outside of the app context. this* makes it much harder for a compromised app to obtain or modify this* value. You could read it as classloader resource but that's not really* different from the properties file used below. Another possibility is to* load it from a read-only value in a database, ideally one with a* different schema than the rest of the application. (It could even be an* in-memory database such as H2 that contains nothing but keying material,* again initialized from a file outside of the app context.)* * The 'right' salt is pulled from a properties file. It is possible to use* a base64-encoded value but administration is a lot easier if we just take* an arbitrary string and hash it ourselves. At a minimum it should be a* random mix-cased string of at least (120/5 = 24) characters.* * The generated salts are equally strong.* * Implementation note: since this is for demonstration purposes a static* string in used in place of reading an external file.*/public byte[][] createSalt() throws NoSuchAlgorithmException {final MessageDigest digest = MessageDigest.getInstance("SHA1");final byte[] left = new byte[20]; // fall back to all zeroesfinal byte[] right = new byte[20]; // fall back to all zeroes// load value from file or database.// note: we use fixed value for demonstration purposes.final String leftValue = "this string should be read from file or database";if (leftValue != null) {System.arraycopy(digest.digest(leftValue.getBytes()), 0, left, 0,left.length);digest.reset();}// load value from resource bundle.final String rightValue = BUNDLE.getString("salt");if (rightValue != null) {System.arraycopy(digest.digest(rightValue.getBytes()), 0, right, 0,right.length);digest.reset();}final byte[][] salt = feistelSha1Hash(new byte[][] { left, right },1000);return salt;}

最后,我们可以通过两种测试方法在实践中看到它:

/*** Obtain password. Architectually we'll want good "separation of concerns"* and we should get the cipher key and IV from a separate place than where* we use it.* * This is a unit test so the password is stored in a properties file. In* practice we'll want to get it from JNDI from an appserver, or at least a* file outside of the appserver's directory.* * @throws Exception*/@Beforepublic void setup() throws Exception {createKeyAndIv(BUNDLE.getString("password").toCharArray());}/*** Test encryption.* * @throws Exception*/@Testpublic void testEncryption() throws Exception {String plaintext = BUNDLE.getString("plaintext");Cipher cipher = Cipher.getInstance(BUNDLE.getString("algorithm"), bc);cipher.init(Cipher.ENCRYPT_MODE, cipherKey, ivSpec);byte[] actual = cipher.doFinal(plaintext.getBytes());assertEquals(BUNDLE.getString("ciphertext"),new String(Base64.encode(actual), Charset.forName("UTF-8")));}/*** Test decryption.* * @throws Exception*/@Testpublic void testEncryptionAndDecryption() throws Exception {String ciphertext = BUNDLE.getString("ciphertext");Cipher cipher = Cipher.getInstance(BUNDLE.getString("algorithm"), bc);cipher.init(Cipher.DECRYPT_MODE, cipherKey, ivSpec);byte[] actual = cipher.doFinal(Base64.decode(ciphertext));assertEquals(BUNDLE.getString("plaintext"),new String(actual, Charset.forName("UTF-8")));}
  • 完整的源代码可从http://code.google.com/p/invariant-properties-blog/source/browse/pbekey获取 。
  • 另请参阅: NIST SP 800-132,基于密码的密钥派生建议 ,第5.3节。
  • 另请参阅: http : //stackoverflow.com/questions/2465690/pbkdf2-hmac-sha1/2465884#2465884 ,有关创建WPA2网络主密钥的讨论。

参考: Invariant Properties博客中的JCG合作伙伴 Bear Giles 创建了基于密码的加密密钥 。

翻译自: https://www.javacodegeeks.com/2013/10/creating-password-based-encryption-keys.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/367612.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php-5.6.26源代码 - PHP文件汇编成opcode、执行

文件 php-5.6.26/Zend/zend.c ZEND_API int zend_execute_scripts(int type TSRMLS_DC, zval **retval, int file_count, ...) /* {{{ */ {va_list files;int i;zend_file_handle *file_handle;zend_op_array *orig_op_array EG(active_op_array); // 保存现场,操作…

java1a2b3c4d5e6f_用两个线程,一个输出字母,一个输出数字,交替输出1A2B3C4D...26Z...

用两个线程,一个输出字母,一个输出数字,交替输出1A2B3C4D...26Z方法一public class Test {static Thread t1 null, t2 null;public static void main(String[] args) {char[] aI "1234567".toCharArray();char[] aC "ABCD…

js如何设置浏览器全屏效果?

现在很多网页游戏进入游戏界面后都是全屏显示的效果,很多人问我这个要怎么实现,其实这个只要调用Fullscreen API就可以实现了作为一个比较新的 API,目前只有 Safari、Chrome 和 FireFox以及IE10以上的浏览器才支持该特性。因为尚未发布正式版…

6759: 异或序列

6759: 异或序列 时间限制: 1 Sec 内存限制: 128 MB题目描述 已知一个长度为n的整数数列a1,a2,…,an,给定查询参数l、r,问在al,al1,…,ar区间内,有多少子序列满足异或和等于k。也就是说,对于所有的x,y(l≤x≤y≤r),满足…

Neo4j Java REST绑定–第2部分(批处理)

在第1部分中 ,我们讨论了使用Java REST绑定建立与Neo4j Server的连接。 现在让我们详细了解事务,批处理以及REST请求的实际情况。确保org.neo4j.rest.logging_filter to true) as described in Part 1打开日志记录(将系统属性org.neo4j.rest.…

selector简介

最近在学习java NIO,发现java nio selector 相对 channel ,buffer 这两个概念是比较难理解的 ,把学习理解的东西以文字的东西记录下来,就像从内存落地到硬盘,把内存中内容换成该知识点的索引。 在介绍Selector之前先明确以下3个问题&#…

java随机数排序算法_理解快速排序算法

快速排序在平均状况下,排序n个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n^2)次比较,但这种状况并不常见。事实上,快速排序通常明显比 其他Ο(n log n)算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地…

开课吧视频内容汇总

1. 前端读取文件内容, FileReader对象 2. 用户联网状态 3. application/x-www-form-urlencoded 参数序列化 (具体借鉴jquery的$.param方法),后端接收到的数据格式是 a[0][a] 1,并不会将其整理成对象或者数组 var nextStr ;funct…

PhantomJS宣布终止开发

由于没有人贡献代码,我很快就要把这个项目归档了。也许未来的某一天,我又想开发了,还会重新启动起来。既然决定停止开发了,那么自然地,PhantomJS 2.5 和原定的 PhantomJS2.1.x 就告吹了。对应的,这两个版本…

Servlet和JSP中的文件上传示例

使用Servlet和JSP将文件上传到服务器是Java Web应用程序中的常见任务。 在对Servlet或JSP进行编码以处理文件上传请求之前&#xff0c;您需要了解一点有关HTML和HTTP协议中文件上传支持的知识。 如果要让用户从文件系统中选择文件并上传到服务器&#xff0c;则需要使用<inpu…

20165312-第4周-课上内容补做以及知识点总结

20165312-第4周-课上内容补做以及知识点总结 1、课上内容补做 教材代码完成情况测试p45这题很快就做完了&#xff0c;然后忘记提交了。。就开始做递归。想起来的时候已经过了时间。 public class Example3_7 {public static void main(String args[]) {int sum0,i,j;for(i1;i&l…

java入门就是死敲代码吗_JAVA入门第二季综合练习(直接思考敲的代码,面向过程,不好)...

package com.imocc;/*author ndh2016年3月27日 21:03:02*/import java.util.Scanner;public class DiDi {public static void main(String[] args){Scanner sc new Scanner(System.in);System.out.println("欢迎使用迪迪租车系统&#xff01;");System.out.println(…

JavaScript实现表单的全选,反选,获取值

构思 通过for循环和for in循环来实现&#xff0c;界面效果如下 步骤 全选&#xff1a; 循环给所有的表单设置checked 反选&#xff1a; 循环内判断checked是否为true&#xff0c;如果为true则改为false否则改为true 获取值&#xff1a; 最开始用for取&#xff0c;但是只打印最后…

jQuery.extend() 使用语法详解

今天在写插件&#xff0c;使用$.extend({}, defaults, options)的时候发现漏写了 {}&#xff0c;浪费了一些时间&#xff0c; 所以详细记录下该方法的 API 和使用。API 如下&#xff1a;jQuery.extend( [ deep ], target, [ object1 ], [ objectN ] )描述&#xff1a;合并两个或…

EJB钝化和激活示例

在本教程中&#xff0c;我们将了解状态Java企业会话Bean中激活和钝化的工作方式。 1.简介 有状态会话Bean通常保存有关特定客户端的信息&#xff0c;并在整个会话中保存该信息。 但是&#xff0c;事实是&#xff0c;客户端会话往往会在相当长的时间内保持活动状态&#xff0c;…

Python进阶_面对对象面对过程

这节主要讲面对对象与面对过程两种编程思想的主要区别。 一. 简单对比 面向过程是一种基础的方法&#xff0c;它考虑的是实际的实现步骤&#xff0c;一般情况下&#xff0c;面向过程是自顶向下逐步求精&#xff0c;其最重要的是模块化的思想方法。 面向对象的方法主要是把事物给…

puppet 安装mysql_Puppet安装dashboard

Puppet安装dashboard安装依赖包[rootmaster ~]# sudo yum install -y mysql mysql-devel mysql-server ruby ruby-devel ruby-irb ruby-mysql ruby-rdoc ruby-ri启动mysql并设置开机启动[rootmaster ~]# service mysqld start [rootmaster ~]# chkconfig mysqld on下载并安装…

命令模式详解

原文链接:https://www.cnblogs.com/java-my-life/archive/2012/06/01/2526972.html 在阎宏博士的《JAVA与模式》一书中开头是这样描述命令&#xff08;Command&#xff09;模式的&#xff1a; 命令模式属于对象的行为模式。命令模式又称为行动(Action)模式或交易(Transaction)模…

JDK 8中几乎命名的方法参数

有时在Java中命名方法参数确实很不错&#xff0c;这看起来可能不会出现很长时间了&#xff0c;但是始终还有其他一些解决方法&#xff0c;例如使用构建器模式来获得类似的行为&#xff0c;这将为一点点。 在我看来&#xff0c;使用JDK 8中的Lambda支持可以使您获得非常接近的效…

深入解析jQuery中的延时对象的概念

首先我们需要明白延时对象有什么用&#xff1f;第一个作用&#xff0c;解决时序以及动态添加执行函数的问题。function a(){alert(1)};function b(){alert(2)};function c(){alert(3)};a();setTimeout(function(){b();},0);c();很明显函数执行顺序是a->c->b,而不是按照函…