mar*_*390 5 javascript encryption sha1 aes pbkdf2
我正在尝试使用 AES256 进行加密/解密,使用 Java 进行加密,使用 CryptoJS 进行解密。在 Java 中测试加密工作正常,但 JavaScript 中的解密方法返回空字符串。请注意,为了测试 JavaScript,我在 tmp 文件中打印出数据、IV 和 salt 的值,然后在 JS 中进行硬编码。(注意:文件中的格式为: data (byte[] base64) 、 Iv(string base64) 和 salt(string base64) )。
\n\n这是java中的代码:
\n\npublic byte[] encrypt(String plainText) throws Exception { \n //get salt\n salt = generateSalt(); \n byte[] saltBytes = salt.getBytes("UTF-8");\n\n // Derive the key\n SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");\n PBEKeySpec spec = new PBEKeySpec(\n password.toCharArray(), \n saltBytes, \n pswdIterations, \n keySize\n );\n\n SecretKey secretKey = factory.generateSecret(spec);\n SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");\n\n //encrypt the message\n Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");\n cipher.init(Cipher.ENCRYPT_MODE, secret);\n AlgorithmParameters params = cipher.getParameters();\n ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();\n byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));\n return Base64.encode(encryptedTextBytes);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n下面 JavaScript 中的解密代码有什么问题?
\n\n// the password that user provides\nvar userPass = document.getElementById("password").value; \nconsole.log("user pass : " + userPass);\n// hash contains 5 bytes\nvar hashedPass = CryptoJS.SHA1(userPass);\nconsole.log("hashed pass : " + hashedPass.toString(CryptoJS.enc.Base64) + " | array length " + hashedPass.words.length + " | " + typeof(hashedPass));\n// use only 4 bytes (128 bits) from the hashed pass\n// (same as used in java when encrypting)\n/////////////////////////var hashed4bytes = CryptoJS.lib.WordArray.create(hashedPass.words.slice(0,4));\n//console.log( "hashed4bytes encoded 64 = " + hashed4bytes.toString(CryptoJS.enc.Base64));\n\n// get the encrypted msg \nvar encMsg64 = document.getElementById("themessage").innerHTML;\nencMsg64 = encMsg64.toString( CryptoJS.enc.Base64);\n//var encMsg = CryptoJS.enc.Base64.parse(encMsg64);\nvar salt =CryptoJS.enc.Base64.parse("EAWnOgxUDuvhWqrSUsugq1umMpI=");\nvar iv =CryptoJS.enc.Base64.parse("xWpmXNbmbFjmWBUajuWYXQ==");\n//var salt = "EAWnOgxUDuvhWqrSUsugq1umMpI=";\n//var iv = "xWpmXNbmbFjmWBUajuWYXQ==";\n console.log(\'salt \'+ salt );\n console.log(\'iv \'+ iv );\n\n\n var key = CryptoJS.PBKDF2(hashedPass, salt, { keySize: 256/32, iterations: 1000 });\nconsole.log( \'key \'+ key);\n\nvar decText = \'\';\nvar ok = true;\ntry {\n debugger;\n var decMsg = CryptoJS.AES.decrypt( encMsg64, key, {\n iv:iv,\n mode: CryptoJS.mode.CBC,\n padding: CryptoJS.pad.Pkcs7\n } );\n console.log( "decryptedData = " + decMsg );\n\n // convert to UTF8 string\n decText = decMsg.toString( CryptoJS.enc.Utf8 );\n console.log( "decryptedText = " + decText );\n\n if (decText == \'\') {\n ok = false;\n } \n}\ncatch (e) {\n //console.log("Error when decrypting: " + e.message)\n ok = false;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n在 mafe 后,更改后的问题仍然存在\n这里是更改后的完整代码
\n\n爪哇
\n\npublic class AES256EncryptionServiceBean implements EncryptionService {\n\n private static final Logger LOGGER = LoggerFactory\n .getLogger(AES256EncryptionServiceBean.class);\n private String salt = null; //get bytes out of UTF-8 for decryption\n private static final int PSWDITERATIONS = 1000;//65536;\n private static final int KEYSIZE = 256;\n private static final String AES_ALGO = "AES";\n private static final String SHA1_ALGO = "PBKDF2WithHmacSHA1";\n private static final String AES_CBC_PKCS5_TRANSFORM = "AES/CBC/PKCS5Padding";\n private byte[] Iv;\n\n /**\n * Encrypts the data with AES-256 algorithm Encrypted data will be encoded\n * with base64 algorithm and the returned. Initial vector is being used\n * during encryption along with CBC encryption mode.\n * \n * output format: [algo indicator(1char)][Initialization vector()][salt()][encoded data(variable size)]\n */\n @Override\n public byte[] encrypt(String password, byte[] data) throws PibException {\n byte[] encodedData = null;\n try {\n byte[] encryptedData = encryptCBC256Bits(password, data);\n encodedData = Base64.encodeBase64(encryptedData);\n /*String finalStr=null;\n String algo256 = "2";\n String datastr = Base64.encodeBase64String(encryptedData);\n String ivstr = new String(Iv);\n finalStr = algo256 +ivstr+salt+datastr;\n\n encodedData = finalStr.getBytes();\n */\n } catch (Exception e) {\n throw ExceptionFactory.createPibException(\n MessageCodes.PIB_ENCRYPTION_FAILED, e, LOGGER);\n }\n return encodedData;\n }\n\n /**\n * Encrypts the input data with AES CBC transformation using 256 bits (32\n * bytes) Key is generated based on the provided password and random salt.\n * Salt is the extra bits added to the password to ensure every key is\n * unique SHA1 hashing is also participate in key generation.\n * \n * @throws PibException\n * \n */\n private byte[] encryptCBC256Bits(String password, byte[] data)\n throws PibException {\n\n salt = generateSalt();\n byte[] saltBytes = salt.getBytes(StandardCharsets.UTF_8);\n byte[] encryptedTextBytes = null;\n\n // Derive the key\n\n try {\n SecretKeyFactory factory = SecretKeyFactory.getInstance(SHA1_ALGO);\n // Password based key specification\n PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes,\n PSWDITERATIONS, KEYSIZE);\n SecretKey secretKey = factory.generateSecret(spec);\n SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(),\n AES_ALGO);\n\n // encrypt the data\n Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5_TRANSFORM);\n // SecureRandom random = new SecureRandom();\n // byte[] ivTemp = new byte[16];\n // random.nextBytes(ivTemp);\n cipher.init(Cipher.ENCRYPT_MODE, secret);\n AlgorithmParameters params = cipher.getParameters();\n Iv = params.getParameterSpec(IvParameterSpec.class).getIV();\n encryptedTextBytes = cipher.doFinal(data);\n\n } catch (NoSuchAlgorithmException | InvalidKeySpecException\n | NoSuchPaddingException | InvalidKeyException\n | InvalidParameterSpecException | IllegalBlockSizeException\n | BadPaddingException e) {\n throw ExceptionFactory.createPibException(\n MessageCodes.PIB_ENCRYPTION_FAILED, e, LOGGER);\n }\n\n return encryptedTextBytes;\n }\n\n private String generateSalt() {\n\n SecureRandom random = new SecureRandom();\n byte bytes[] = new byte[20];\n random.nextBytes(bytes);\n String s = new String(bytes);\n return s;\n\n }\n\n public String getSalt() {\n return salt;\n }\n\n public byte[] getIv() {\n return Iv;\n }\n\n}\nRun Code Online (Sandbox Code Playgroud)\n\nJavaScript
\n\nfunction decryptMsg256() {\n\n // the password that user provides\n var userPass = document.getElementById("password").value; \n console.log("user pass : " + userPass);\n\n\n // get the encrypted msg \n var encMsg64 = document.getElementById("themessage").innerHTML;\n var encMsg = CryptoJS.enc.Base64.parse(encMsg64);\n var salt =CryptoJS.enc.Utf8.parse("?E\xe2\x82\xacO5?\xe2\x80\xa6\xc2\xb0\xc2\xaeI^y??O:n");\n var iv =CryptoJS.enc.Utf8.parse("S;Ui?\xc2\xa8=ENzI\xe2\x80\x94$");\n\n console.log(\'salt \'+ salt );\n console.log(\'iv \'+ iv );\n\n\n var key = CryptoJS.PBKDF2("password", salt, { keySize: 256/32, iterations: 1000 });\n console.log( \'key \'+ key);\n\n var decText = \'\';\n var ok = true;\n try {\n debugger;\n var decMsg = CryptoJS.AES.decrypt( encMsg, key, {\n iv:iv,\n mode: CryptoJS.mode.CBC,\n padding: CryptoJS.pad.Pkcs7\n } );\n console.log( "decryptedData = " + decMsg );\n\n // convert to UTF8 string\n decText = decMsg.toString( CryptoJS.enc.Utf8 );\n console.log( "decryptedText = " + decText );\n\n if (decText == \'\') {\n ok = false;\n } \n }\n catch (e) {\n //console.log("Error when decrypting: " + e.message)\n ok = false;\n }\nRun Code Online (Sandbox Code Playgroud)\n\n我不明白出了什么问题,请帮忙\nCipherText、Salt 和 Iv 的检索如下:
\n\npublic void testEncryption_WriteToFile() throws Exception {\n\n byte[] data = IOUtils.toByteArray(this.getClass().getClassLoader()\n .getResourceAsStream(SOME_FILE_NAME));\n\n byte[] encryptedData = this.encryptionService.encrypt(PASSWORD, data);\n byte[] initial_vector = ((AES256EncryptionServiceBean) encryptionService)\n .getIv();\n String salt = ((AES256EncryptionServiceBean) encryptionService)\n .getSalt();\n\n\n IOUtils.write(encryptedData, new FileOutputStream(\n "C:\\\\Temp\\\\data.encrypted"));\n /*IOUtils.write(new String(encryptedData), new FileOutputStream(\n "C:\\\\Temp\\\\data[byte32string].encrypted"));\n */\n IOUtils.write(Base64.encodeBase64String(salt.getBytes(StandardCharsets.UTF_8)), new FileOutputStream(\n "C:\\\\Temp\\\\salt.encrypted"));\n /*IOUtils.write(salt.getBytes(StandardCharsets.UTF_8), new FileOutputStream(\n "C:\\\\Temp\\\\salt.encrypted"));\n */\n IOUtils.write(Base64.encodeBase64String(initial_vector), new FileOutputStream(\n "C:\\\\Temp\\\\iv.encrypted"));\n /*IOUtils.write(initial_vector, new FileOutputStream(\n "C:\\\\Temp\\\\iv.encrypted"));*/\n\n\n }\nRun Code Online (Sandbox Code Playgroud)\n
CryptoJS.PBKDF2默认使用 SHA1。因此,只要提供相同的密码、salt、密钥大小和迭代次数,就会产生相同的密钥。问题在于,在 JavaScript 中,您还使用 SHA1 对密码进行哈希处理。不要这样做,而是像在 Java 中那样将密码直接传递到 PBKDF2 中。
第二个问题是,在尝试解密时,密文应该采用 CryptoJS 的本机格式。由于您从 Java 获得了 Base 64 编码的密文,因此您必须对其进行解码。取消注释该行:
var encMsg = CryptoJS.enc.Base64.parse(encMsg64);
Run Code Online (Sandbox Code Playgroud)
并且不要这样做,encMsg64 = encMsg64.toString( CryptoJS.enc.Base64);因为这将再次对已经编码的密文进行编码。
对于更新后的代码,您不能简单地将密钥和盐打印为字符串并期望它在 JavaScript 中工作。这些都是byte[]有原因的。它们包含不可打印的字符,当您尝试在 JavaScript 中解析它时,这些字符将会丢失。您必须将byte[]要从 Java 传输到 JavaScript 的所有值编码为 Base64,然后在 JavaScript 中对其进行解码。
| 归档时间: |
|
| 查看次数: |
5504 次 |
| 最近记录: |