Java中的OpenSSL EVP_BytesToKey问题

我正在对一个API进行逆向工程,我发现它使用AES-256-CBC进行加密。
我还发现它使用EVP_BytesToKey来加密HTTP请求。 在我发现这个之后我测试了它但是我遇到了一些问题(可能是因为我没经验)。 我不知道在哪里放密码

这是需要被解密的内容: FP2xttTh/wm5Kr45Vh/PEvsdxgfL3NgxxMMk9hTkPfJd7vSJXTlhjiZlQajnBcMAVknANpv5FNCMRD+epDSOA2epKOzstSmhC0il2TlwgKqaT+97zomCMUCIfdaJYnLz5gBth1MIpxO30bx9zPg8cbOJcLnMmCo3vtSDCalgjHICf5FevI7DgrWnWC1U4wab0rx/rWhGFJ0sOW1ImDi9DkCy+guQZIrojbZxRlvGzv1mU/avP5hbKgWIheJpYQvvM12RyCNuVxjHK/oZ1mCQLVjvpED291lxsGTNHPUrc2NI7LCj/xOztjgsukpBP9K1nsUIgEyfVFUfTf5sh4QPccZnJ1bzKqPD

告诉我钥匙和解密方式的人也给了我这个

REMOVED

告诉我钥匙和解密方式的人也给了我这个

 # base64 data must be stored in a file named "...-tmp.decrypt" # Usage: decrypt.sh secret sessionId SALT="$(cat $2 | base64 -d | head -c +8 | od -A n -t x1 | head -n 1 | tr -d " ")" echo -n "Salted__" > $2.enc cat $2 | base64 -d >> $2.enc cat $2.enc | openssl aes-256-cbc -d -k "$1" -md md5 -S "$SALT" 

我们在这里有什么

  • salt由输入的前8个字节组成
  • 使用aes-256-cbc

常量:

  private static final int SALT_LENGTH = 8; private static final int ITERATIONS = 1; private static final int KEY_SIZE_BITS = 256; private static final int INDEX_KEY = 0; private static final int INDEX_IV = 1; 

分盐和输入

  // iv is 8 bytes of the input byte[] inputBytes = Base64.getDecoder().decode(INPUT); byte[] salt = new byte[SALT_LENGTH]; System.arraycopy(inputBytes, 0, salt, 0, SALT_LENGTH); byte[] encrypted = new byte[inputBytes.length - SALT_LENGTH]; System.arraycopy(inputBytes, SALT_LENGTH, encrypted, 0, encrypted.length); 

并解密(你从哪里获得原始代码?原始作者的归属不会受到伤害)

  Cipher aesCBC = Cipher.getInstance("AES/CBC/Pkcs5Padding"); MessageDigest md5 = MessageDigest.getInstance("MD5"); // --- create key and IV --- // the IV is useless, OpenSSL might as well have use zero's final byte[][] keyAndIV = EVP_BytesToKey( KEY_SIZE_BITS / 8, aesCBC.getBlockSize(), md5, salt, PASSWORD_STRING.getBytes("UTF-8"), ITERATIONS); SecretKeySpec key = new SecretKeySpec(keyAndIV[INDEX_KEY], "AES"); IvParameterSpec iv = new IvParameterSpec(keyAndIV[INDEX_IV]); // --- initialize cipher instance and decrypt --- aesCBC.init(Cipher.DECRYPT_MODE, key, iv); byte[] decrypted = aesCBC.doFinal(encrypted); System.out.println(new String(decrypted, "UTF-8")); 

我们得到一个结果

  {"difficulty":5,"friend_id":1962395051,"is_playing_script":true, "selected_team_num":3,"support_items": [{"quantity":2,"support_item_id":6},{"quantity":2,"support_item_id":1505},{"quantity":2,"support_item_id":1202},{"quantity":2,"support_item_id":1701}]} 

我仍然看到两件事缺失:

  1. 密码强度

正如@ dave_thompson_085指出的那样,密码看起来像是PEM文件的一部分,我同意他的看法。 这是非常错误的,因为PEM文件定义了严格的模式,这将有效地降低密码的随机性

我建议使用真正随机的密码,e,g,生成为

 openssl rand -hex 16 openssl rand -base64 16 
  1. 认证加密

密文不包含任何完整性信息,因此如果密文被更改,则无法检测到更改,因此无法确保完整性

需要沿密文发送额外的完整性信息(例如密文的hmac)