我正在对 API 进行逆向工程,发现它使用 AES-256-CBC 进行加密。
我还发现它使用 EVP_BytesToKey 来加密 HTTP 请求。当我发现this之后我测试了它,但遇到了一些问题(可能是因为我缺乏经验)。我不知道密码该放在哪里
这就是需要解密的内容:FP2xttTh/wm5Kr45Vh/PEvsdxgfL3NgxxMMk9hTkPfJd7vSJXTlhjiZlQajnBcMAVknANpv5FNCMRD+epDSOA2epKOzstSmhC0il2TlwgKqaT+97zomCMUCIfdaJYnLz5g Bth1MIpxO30bx9zPg8cbOJcLnMmCo3vtSDCalgjHICf5FevI7DgrWnWC1U4wab0rx/rWhGFJ0sOW1ImDi9DkCy+guQZIrojbZxRlvGzv1mU/avP5hbKgWIheJpYQvvM12RyCNuVxjHK/oZ1mCQ LVjvpED291lxsGTNHPUrc2NI7LCj/xOztjgsukpBP9K1nsUIgEyfVFUfTf5sh4QPccZnJ1bzKqPD
告诉我 key 及其解密方式的人也给了我这个
已删除
最佳答案
The person who told me the key and the way it's decrypted also gave me this
# 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"
我们这里有什么
- 盐由输入的前 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}]}
我仍然发现缺少两件事:
- 密码强度
正如 @dave_thompson_085 所指出的,密码看起来像是 PEM 文件的一部分,我同意他的观点。这是非常错误的,因为 PEM 文件定义了严格的架构,这将有效降低密码的随机性
我建议使用真正随机的密码,例如生成为
openssl rand -hex 16
openssl rand -base64 16
密文不包含任何完整性信息,因此如果密文被更改,则无法检测到更改,因此无法确保完整性
额外的完整性信息需要与密文一起发送(例如密文的hmac)
关于java - Java 中的 OpenSSL EVP_BytesToKey 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47094518/