天津住房与城乡建设部网站,t购物网站开发前景,陕西省建设银行分行网站,黄埔做网站要多少钱使用密钥加密码加密本文讨论了创建基于密码的加密PBE密钥。 首先提醒您以前的要点–通常#xff0c;在实际操作中#xff0c;应将PBE密钥用作主密钥#xff0c;该主密钥仅用于解锁工作密钥。 这具有三个主要优点#xff1a; 您可以有多个密码#xff0c;例如#xff0c… 使用密钥加密码加密 本文讨论了创建基于密码的加密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: Ive believe Ive seen other code that can extract* the random bits for the IV directly from the PBEKeySpec but I havent* 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 thats 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 thats 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 well 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 well want to get it from JNDI from an appserver, or at least a* file outside of the appservers 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使用密钥加密码加密