使用密钥加密码加密

本文讨论了创建基于密码的加密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. 数据库身份证号加密密码加密_使用基于密码的加密保护会议室数据库

    数据库身份证号加密密码加密 As developers we are often tasked with securing the data we store in our applications. ...

  2. python中凯撒密码加密_凯撒密码加密

    您似乎是在交互式提示中输入此代码,而不是将其保存为文件并运行它.如果是这样,那么当您使用input时,窗口将在允许您继续输入代码之前提示您输入.在plainText = input("pyt ...

  3. python中凯撒密码加密_凯撒密码加密Python

    有人能告诉我为什么我只对纯文本信息中的一个字符进行加密?消息是"船在午夜启航",加密密钥是4.我只能让t移到x,剩下的信息无法打印.我错过了什么?在#request the mes ...

  4. 创建基于密码的加密密钥

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

  5. jsp登录密码加密_[源码和文档分享]基于JSP和MYSQL数据库的在线购物网站的设计与实现...

    1 系统概述 1.1 系统描述 IShopping购物网站是一个在线的百货商店,用户可以通过网络购买我们的商品,其基本功能包括用户的注册.登录,浏览所有商品,浏览分类商品,查看商品的详细信息,购买商品 ...

  6. 数据库身份证号加密密码加密_使用密码加密数据

    数据库身份证号加密密码加密 介绍 (Introduction) When we're encrypting data, typically we will create a random key th ...

  7. vue.js 密码加密_密码演化史-1

    码书笔记 隐私权是所有人的一项根本权利,可是如何防止自己的信息被其他人窃取呢?想让信息不被拦截在互联网时代已经不可能了,我们要做的是让其他人即使拦截到了信息也不明白它传达了什么,这就是密码的作用. 隐 ...

  8. vue.js 密码加密_密码学初探:隐藏信息的艺术——区块链技术引卷之十一

    通证通研究院 × FENBUSHI DIGITAL 联合出品 文:宋双杰,CFA:孙含儒 特别顾问:沈波:Rin:JX 导读 密码学(Cryptography),是一门将信息进行加密处理与传递,以及分 ...

  9. vue.js 密码加密_密码学初探:隐藏信息的艺术

    通证通研究院 × FENBUSHI DIGITAL 联合出品 文:宋双杰,CFA:孙含儒 特别顾问:沈波:Rin:JX 导读 密码学(Cryptography),是一门将信息进行加密处理与传递,以及分 ...

最新文章

  1. ABAP面试题系列:写一组会出现死锁(Deadlock)的ABAP程序
  2. 11g oracle xe启动_详解Oracle等待事件的分类、发现及优化
  3. [转载] Python京东抢购
  4. 哪种消息队列更好_如何编写更好的错误消息
  5. GB28181流媒体服务LiveGBS启动报错 HTTP Port[10000] In Use
  6. guido发布python版本的年份_Guido van Rossum
  7. 2022 华为软件精英挑战赛 复赛思路分享
  8. itext7相关使用
  9. 那个超级浏览器好(跨境浏览器哪个好)
  10. 神经网络之BP算法【图文并茂】
  11. ARKit入门到精通-0.0-史小川-专题视频课程
  12. 自媒体原创度检测工具有哪些?这几个可以免费用
  13. 二广高速公路4标段道路设计--武汉理工大学本科生毕业设计
  14. 003-Java技术体系
  15. Deep Learning中的层结构
  16. matlab画基因表达热图,科学网—使用pheatmap软件绘制基因表达热图 - 陈振玺的博文...
  17. 【重识云原生】第六章容器基础6.4.10.2节——StatefulSet常规操作实操
  18. 如何蒸出白白胖胖的馒头
  19. Visual Question Answering: Datasets, Algorithms, and Future Challenges文章翻译
  20. 微信小程序实战(一)---实现登录界面

热门文章

  1. 这几道 Redis 面试题都不懂,怎么拿 Offer?
  2. Spring Boot 面试题
  3. JavaScript Function.arguments 属性详解
  4. 为什么Netty这么火?与Mina相比有什么优势?
  5. ssh报错java.lang.ClassCastException: com.sun.proxy.$Proxy6 cannot be cast to org.service.impl.EmpServi
  6. Mysql对字符串去掉前后空格(trim)或者指定字符
  7. count does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manu
  8. webpack打包发布
  9. 工程打包是什么意思_太生动形象了!500个建筑施工3D动画演示,施工工艺一目了然,零基础工程人也能看懂...
  10. windows监控txt写入_Windows的bug们