本文讨论了创建基于密码的加密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

创建基于密码的加密密钥相关推荐

  1. 使用密钥加密码加密_创建基于密码的加密密钥

    使用密钥加密码加密 本文讨论了创建基于密码的加密PBE密钥. 首先提醒您以前的要点–通常,在实际操作中,应将PBE密钥用作主密钥,该主密钥仅用于解锁工作密钥. 这具有三个主要优点: 您可以有多个密码, ...

  2. 创建bdlink密码是数字_如何创建实际上是安全的密码

    创建bdlink密码是数字 I am very tired of seeing arbitrary password rules that are different for every web or ...

  3. 在 Linux 中用Seahorse管理你的密码和加密密钥

    Seahorse 是一个简洁的开源密码和加密密钥管理器,让我们来探讨一下它的功能和如何安装它. Seahorse 是一个简洁的开源密码和加密密钥管理器,让我们来探讨一下它的功能和如何安装它. 我们经常 ...

  4. Web应用中基于密码的身份认证机制(表单认证、HTTP认证: Basic、Digest、Mutual)

    Web应用中基于密码的身份认证机制 背景概念 认证(Authentication) 会话管理 1 表单认证(Form-Based Authentication) 1.1 介绍 1.2 流程 2 通用的 ...

  5. 利用cocoapods创建基于git的私有库Spec Repo

    上一篇文章记录了我利用cocoapods创建基于SVN的私有库的全部过程,今天我再记录一下基于git创建的过程. 整体先说明一下创建一个私有的podspec包括如下那么几个步骤: 创建并设置一个私有的 ...

  6. Kataspace:用HTML5和WebGL创建基于浏览器的虚拟世界

    源自斯坦福的创业公司Katalabs发布了一个用于创建基于浏览器的虚拟世界的开源框架. 名叫KataSpace的软件,利用了新兴的HTML5技术,以及WebGL和WebSockets,允许用户无需安装 ...

  7. 优秀教程:创建基于 Ajax 的文件拖放上传功能

    分享来自 Tutorialzine 的优秀教程--创建基于 Ajax 的文件拖放上传功能,结合 jQuery File Upload 插件和 jQuery Knob 插件实现漂亮的 CSS3/JS 驱 ...

  8. 技术分享:看我如何利用Outlook来创建基于电子邮件的持久化后门

    目录 写在前面的话 技术分析 宏武器化 持久化PoC PoC演示 检测 写在前面的话 使用低等级用户权限来实现持久化感染,是一种非常有价值的技术,因此我们打算在这篇文章中,跟大家介绍这种基于Outlo ...

  9. 云服务器 ECS 建站教程:创建基于ECS和RDS的WordPress环境

    创建基于ECS和RDS的WordPress环境 您可以在资源编排服务ROS (Resource Orchestration Service)中通过模版创建一组阿里云资源. ROS 的控制台已经提供了一 ...

最新文章

  1. 重磅|我国科学家成功研制全球神经元规模最大的类脑计算机
  2. python报错UnicodeDecodeError: ‘gbk‘ codec can‘t decode解决方案
  3. pthread_join
  4. Office 365 Exchange 2016 混合部署前准备
  5. 将数据流链接到加密转换的流CryptoStream 类
  6. 河南理工大学计算机学院课表,河南理工大学实验课课程表.doc
  7. qlineargradient线性渐变
  8. 流程图绘制软件 EDraw Mind Map
  9. 美通企业日报 | 易车收到腾讯等私有化要约;沃尔玛中国推出快时尚品牌George...
  10. excle批量填充自增数据
  11. 人员招聘与培训实务【1】
  12. CROSS APPLY 和 OUTER APPLY 函数
  13. 我们算了笔账,月薪过万可能还不配结婚!
  14. 各双拼输入方案之间有明显的优劣之分吗?
  15. 使用命令结束Linux系统
  16. ICP许可证有多重要
  17. 语音动画设置 android,Anroid Studio第七期 - 语音动画
  18. 怎么在mysql中创建用户名和密码是什么_mysql中怎么创建用户名和密码
  19. actin/phobos后缀勒索病毒处理 百分百解密[cleverhorse@protonmail.
  20. oy5.xyz_Oy ... XPathDocument 2.0更改已移回XmlDocument!

热门文章

  1. 三国志战略版360区S4服务器合并信息,三国志战略版pk赛季怎么转区?s4转区规则[多图]...
  2. 计算机网络产生的历史背景,网络技术背景及sdn概述.pdf
  3. springmvc新建拦截器
  4. 命令行执行Junit测试
  5. java流与文件——java生成解压缩文件(夹)
  6. Springboot实现文件上传,并防止同文件重复上传
  7. 古巴比伦乘法_古巴:为生产做准备
  8. okta-spring_通过Okta的单点登录保护Spring Boot Web App的安全
  9. thymeleaf与jsp_PagingAndSortingRepository –如何与Thymeleaf一起使用
  10. aws集群重启_在AWS中设置Cassandra集群