代码之家  ›  专栏  ›  技术社区  ›  Rumesh Krishnan

如何在JAVA或SCALA中使用AES 256 CBC提取enc加密数据?

  •  1
  • Rumesh Krishnan  · 技术社区  · 8 年前

    我需要关于使用JAVA或SCALA进行AES 256解密的帮助。我可以使用 openssl .

    Base 64编码密钥: 5UX8IBWruBk1QmMZlZ1ESYmZRiC9w1DsrPpLIP9QF+Q=

    Base 64编码的有效负载: U2FsdGVkX19XO99r3f7LgNbPTW8tKexv26mCPUYTMTTiwSSayFvB/QraYJkfzKjEB+tisqzzrU9aZu/tQ5CIVrHHwkUxpyjKEjx3N5q+Ba3weNK/NthpcCsNw5GQxl3NWGoDPe2IFXHMpvpy9xb2mbMnPtwr3m4nF3JzRD6Ft34Q7bHmmTCDkh5kEF9Hx+nbeiLURqLJ1S5YeGq7xhZqalimuQPwT7cr3MPkWPGyZVtNtrKJfIRStoMqP9F2qvm6 .

    OpenSSL解密命令:

    # extract the json from payload
    $ openssl enc -d -aes-256-cbc -salt -in data.payload -out output.json -pass file:./key.otkey
    

    输入 key.otkey 上述和 data.payload 文件包含上面提到的base64解码字符串。 我可以使用 openssl 和输出:

    {"fields":["NSN","store_busn_dt","all_net_sales_amt","all_net_sales_qty","dt_net_sale_qty","brfst_net_sale_qty"],"data":[[38099,"2018-04-01",7675.900000000001,998,752,262]]}
    

    但我无法使用Scala代码提取:

    import java.nio.charset.StandardCharsets
    import java.util.Base64
    
    import javax.crypto.Cipher
    import javax.crypto.spec.SecretKeySpec
    import javax.crypto.spec.IvParameterSpec
    import javax.xml.bind.DatatypeConverter
    
    object AesDecryption extends App {
    
      val key: String = "5UX8IBWruBk1QmMZlZ1ESYmZRiC9w1DsrPpLIP9QF+Q="
      val keyOut = Base64.getDecoder.decode(key)
    
      val otKey: SecretKeySpec = new SecretKeySpec(keyOut, "AES")
    
      val payload: String = "U2FsdGVkX19XO99r3f7LgNbPTW8tKexv26mCPUYTMTTiwSSayFvB/QraYJkfzKjEB+tisqzzrU9aZu/tQ5CIVrHHwkUxpyjKEjx3N5q+Ba3weNK/NthpcCsNw5GQxl3NWGoDPe2IFXHMpvpy9xb2mbMnPtwr3m4nF3JzRD6Ft34Q7bHmmTCDkh5kEF9Hx+nbeiLURqLJ1S5YeGq7xhZqalimuQPwT7cr3MPkWPGyZVtNtrKJfIRStoMqP9F2qvm6"
    
      val encryptedData: Array[Char] = payload.toCharArray
      //Base64.getDecoder.decode(payload)
      val encData: Array[Byte] = DatatypeConverter.parseBase64Binary(new String(encryptedData))
      println(new String(encData, StandardCharsets.ISO_8859_1))
    
      val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
    
      // Generating IV.// Generating IV.
      val ivSize = 16
      val iv = new Array[Byte](ivSize)
      // Extract IV.// Extract IV.
      System.arraycopy(encData, 0, iv, 0, iv.length)
      val ivParameterSpec = new IvParameterSpec(iv)
    
      // extract data
      cipher.init(Cipher.DECRYPT_MODE, otKey, ivParameterSpec)
      val output: Array[Byte] = cipher.doFinal(encData)
    
      // print result
      println(new String(output, StandardCharsets.ISO_8859_1))
    
    }
    

    输出:

    Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
        at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:989)
        at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:845)
        at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
        at javax.crypto.Cipher.doFinal(Cipher.java:2165)
    

    上述json的例外输出。提前谢谢。!

    2 回复  |  直到 7 年前
        1
  •  2
  •   Eugene Loy    7 年前

    我认为您使用的初始化向量(IV)是错误的。

    在代码中派生 ivParameterSpec (四) 发件人 encData (反过来来自有效载荷,即加密数据)

    您在加密期间没有明确指定它,并且基于 openssl docs :

    如果没有明确给出,它将从密码中派生。有关详细信息,请参阅密钥派生。

    因此,我的建议是:

    1. 从用于加密的密钥文件中获取需要使用的IV openssl
    2. 加密期间显式指定IV( openssl -iv <IV here> )并在解密过程中重用

    更新: 还有,看看 this answer 例如代码示例(包括使用适当的IV)。

        2
  •  0
  •   Rumesh Krishnan    7 年前

    最后,我能够使用AES 256位CBC解码器解密数据,以提供加密的文件和传递密钥。

    $ echo -n "U2FsdGVkX19XO99r3f7LgNbPTW8tKexv26mCPUYTMTTiwSSayFvB/QraYJkfzKjE
    B+tisqzzrU9aZu/tQ5CIVrHHwkUxpyjKEjx3N5q+Ba3weNK/NthpcCsNw5GQxl3N
    WGoDPe2IFXHMpvpy9xb2mbMnPtwr3m4nF3JzRD6Ft34Q7bHmmTCDkh5kEF9Hx+nb
    eiLURqLJ1S5YeGq7xhZqalimuQPwT7cr3MPkWPGyZVtNtrKJfIRStoMqP9F2qvm6
    
    "  | openssl enc -aes-256-cbc -salt -base64 -pass pass:5UX8IBWruBk1QmMZlZ1ESYmZRiC9w1DsrPpLIP9QF+Q= -d
    

    Scala代码:

    def aesDecryption(secret: String, data: String): String = {
        val decoded: Array[Byte] = Base64.getDecoder.decode(data)
        val salt = decoded.slice(8,16)
        val encryptedData = decoded.slice(16, decoded.length)
        val (key, iv) = getKeyIv(secret.getBytes(), salt)
        val sKeySpec = new SecretKeySpec(key, "AES")
        val ivSpec = new IvParameterSpec(iv)
    
        val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
        cipher.init(Cipher.DECRYPT_MODE, sKeySpec, ivSpec)
        new String(cipher.doFinal(encryptedData))   }
    
    private def getKeyIv(password: Array[Byte], salt: Array[Byte]): (Array[Byte], Array[Byte]) = {
        val md5: MessageDigest = MessageDigest.getInstance("MD5")
        // first digest
        md5.update(password)
        md5.update(salt)
        val hash1 = md5.digest()
        // second digest
        md5.reset()
        md5.update(hash1)
        md5.update(password)
        md5.update(salt)
        val hash2 = md5.digest()
        // third digest
        md5.reset()
        md5.update(hash2)
        md5.update(password)
        md5.update(salt)
        val hash3 = md5.digest()
        val key = hash1.take(16) ++ hash2.take(16)
        val iv = hash3.take(16)
        (key, iv)   
    }
    

    aesDecryption(secret, encryptedData) 使用这个函数调用,我们可以解密数据。

    参考号: https://github.com/chmduquesne/minibackup/blob/master/samples/OpensslAES.java