Я не могу получить такой же вывод из своего кода Python, в чем моя ошибка?
я не уверен, но я делаю ошибку в процессе кодирования и декодирования
from Crypto.Cipher import AES
from Crypto import Random
import base64
from hashlib import pbkdf2_hmac
import binascii
import os
import datetime, time
def pad(byte_array):
BLOCK_SIZE = 16
pad_len = BLOCK_SIZE - len(byte_array) % BLOCK_SIZE
return byte_array + (bytes([pad_len]) * pad_len)
key = pbkdf2_hmac(
hash_name = 'SHA1',
password = b"75820705-2b7a-46dc-b811-0f6ad4ff33af",
salt = os.urandom(8),
iterations = 100,
dklen = 384
)
auth_key = "d4eee068-272a-4aec-9681-5e16dcef6fbd";
timedate = x = datetime.datetime.fromtimestamp(time.time()-1000*10*60)
paylaod = auth_key+"|"+x.strftime('%Y-%m-%dT%H:%M:%S.0000%f')[:-3]+"Z"
cipher = AES.new(key[:32], AES.MODE_CBC, key[32:48])
plain = pad(paylaod.encode("UTF-8"))
encrypted_text = cipher.encrypt( plain )
print (base64.b64encode(encrypted_text).decode("UTF-8"))
это рабочий метод на java
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.security.SecureRandom;
import java.util.Arrays;
import java.lang.StringBuilder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Calendar;
import java.util.*;
byte[] bArr = new byte[8];
new SecureRandom().nextBytes(bArr);
byte[] encoded = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(new PBEKeySpec(str2.toCharArray(), bArr, 100, 384)).getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(Arrays.copyOfRange(encoded, 0, 32), "AES");
Cipher instance = Cipher.getInstance("AES/CBC/PKCS5Padding");
instance.init(instance.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(Arrays.copyOfRange(encoded, 32, 48)));
byte[] doFinal = instance.doFinal(str.getBytes("UTF-8"));
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byteArrayOutputStream.write(doFinal);
byteArrayOutputStream.write(bArr);
return Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
и это основная часть java:
public static void main(String[] args)
{
String auth_key = "d4eee068-272a-4aec-9681-5e16dcef6fbd";
SimpleDateFormat var0 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'", Locale.US);
var0.setTimeZone(TimeZone.getTimeZone("UTC"));
String payload = auth_key+"|"+var0.format(new Date(Long.valueOf((new Date()).getTime()-1000*10*60))); //random key from /keys endpoint
String outputVal = a(payload, "bd1676b5-5ce3-4351-a39b-36a7b7219c11"); //x-vmob-uid
System.out.println(outputVal.replace("\n", "").replace(" ", ""));
}
Правильный вывод таков:
Wgxc7xuqdKd2CqyT2KLE6ihankSTbTS/grIj+uyGG4IgpXWFxJ+KE4En/lQnL2vEu67w0sHeT6Tu1ibV0zahqpCKjw4pGPhhuCErS/8pojzg2TSMfFh7fw==
но я получаю это:
8/VHDoMCOOI4Aaxus2nxridBPfm4Gvy2g8yRgK3VJUr3eSa3UucsAdzRMapuQj6pN3el12tqaAKYeNpFZCv5SuVosd4AYXwvmf/3uy5yr2U=
надеюсь, кто-нибудь предложит мне, где проверить или дать мне ошибку
также, можете ли вы сделать pip freeze и опубликовать вывод в вопросе? чтобы мы могли видеть, какие пакеты в Python используются.
Я вижу на стороне Python, когда вы создаете ключ key = pbkdf2_hmac(..., аргумент соли является случайным salt = os.urandom(8). Затем ключ используется шифром. Итак, если вы используете разные соли, как результат может быть таким же? Кроме того, полезная нагрузка отличается, потому что она рассчитывается из time.time(), которая будет отличаться при каждом запуске (и в Java должны соблюдаться те же рассуждения). Обратите внимание, что я не знаю шифрования, но это то, что бросилось мне в глаза.
Ваш код Java ссылается на переменные str2 и str, но ваш фрагмент кода не показывает, как они инициализируются
@StevenRumbalski в java это: byte[] bArr = new byte[8]; новый SecureRandom().nextBytes(bArr); значит генератор случайных чисел
@Palamino, вы можете просто выполнить код Java, скопировав код фрагмента
@FreeWar, когда я запускаю ваш Java-код локально, он дает разные результаты для каждого запуска. например VUnWoEYyKDphtUB7U2yS7hRLoou8Atu9f4CerOFkyI+EjpfUQ6MCqpb6NUzyvMoXap6o3E6GMTv1JCSFrgsfdngSM4sM9A1H8IFJe8ATTJcjf5mtCaV8mg==
Дело не в том, что вы не используете рандомизацию в обоих случаях. Дело в том, что рандомизация означает, что ваши результаты будут разными — не только между двумя программами, но и от запуска к запуску.
да, я знаю это, но вывод отличается длиной и последними двумя символами! Когда я вызываю вывод из java, я получаю длину 120 с ==, но в python у меня есть слово длины 108 и только 1 '=' @StevenRumbalski
@JeffXiao вывод каждый раз разный, но это правильный вывод «длина и последние 2 символа»
Добавлен ответ @FreeWar




Причины, по которым вы видите различия в результатах Java и Python:
pbkdf2_hmacbyteArrayOutputStream.write(bArr); вводит немного более длинную строку в вывод Java.Я предполагаю, что 3 - это то, что вы ищете, но позвольте мне дать длинный ответ мыслительного процесса для вышеуказанных выводов.
package answer;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.Arrays;
import java.text.SimpleDateFormat;
import java.io.ByteArrayOutputStream;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.Cipher;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.util.Base64;
public class SO56189889 {
public static void main(String[] args) {
String auth_key = "d4eee068-272a-4aec-9681-5e16dcef6fbd";
SimpleDateFormat var0 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'", Locale.US);
var0.setTimeZone(TimeZone.getTimeZone("UTC"));
// random key from /keys endpoint
String formatted = var0.format(getSeedDate());
String payload = auth_key + "|" + formatted;
System.out.println(payload);
String outputVal = magic(payload, "bd1676b5-5ce3-4351-a39b-36a7b7219c11"); // x-vmob-uid
System.out.println(outputVal.length());
System.out.println(outputVal);
}
public static Date getSeedDate() {
Date now = new Date(Long.valueOf((new Date()).getTime() - 1000 * 10 * 60));
return now;
}
public static String magic(String str, String str2) {
try {
byte[] bArr = new byte[8];
// new SecureRandom().nextBytes(bArr);
for (int i = 0; i < 8; i++) {
bArr[i] = 'X';
}
String temp = new String(bArr);
System.out.println(temp);
byte[] encoded = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
.generateSecret(new PBEKeySpec(str2.toCharArray(), bArr, 100, 384)).getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(Arrays.copyOfRange(encoded, 0, 32), "AES");
Cipher instance = Cipher.getInstance("AES/CBC/PKCS5Padding");
// XXX: use Cipher.ENCRYPT_MODE (was: instance.ENCRYPT_MODE)
instance.init(Cipher.ENCRYPT_MODE, secretKeySpec,
new IvParameterSpec(Arrays.copyOfRange(encoded, 32, 48)));
byte[] doFinal = instance.doFinal(str.getBytes("UTF-8"));
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byteArrayOutputStream.write(doFinal);
byteArrayOutputStream.write(bArr);
System.out.println("no exception, everything OK");
return Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
} catch (Exception e) {
System.out.println(e.toString());
return "NOT WORKING";
}
}
}
Полный код Python, который работает:
from Crypto.Cipher import AES
from Crypto import Random
import base64
from hashlib import pbkdf2_hmac
import binascii
import os
import datetime, time
def pad(byte_array):
BLOCK_SIZE = 16
pad_len = BLOCK_SIZE - len(byte_array) % BLOCK_SIZE
return byte_array + (bytes([pad_len]) * pad_len)
# salt = os.urandom(8)
salt = b'XXXXXXXX'
print(salt)
print('---------------')
key = pbkdf2_hmac(
hash_name = 'SHA1',
# password = b"75820705-2b7a-46dc-b811-0f6ad4ff33af",
password = b"bd1676b5-5ce3-4351-a39b-36a7b7219c11",
# salt = os.urandom(8),
salt = salt,
iterations = 100,
dklen = 384
)
auth_key = "d4eee068-272a-4aec-9681-5e16dcef6fbd"
x = datetime.datetime.fromtimestamp(time.time()-1000*10*60)
timedate = x
# payload = auth_key+"|" + x.strftime('%Y-%m-%dT%H:%M:%S.0000%f')[:-3]+"Z"
payload = "d4eee068-272a-4aec-9681-5e16dcef6fbd|1970-01-01T00:00:00.0000000Z"
print(payload)
print('-----------------')
cipher = AES.new(key[:32], AES.MODE_CBC, key[32:48])
plain = pad(payload.encode("UTF-8"))
encrypted_text = cipher.encrypt(plain)
result = base64.b64encode(encrypted_text).decode("UTF-8")
print(len(result))
print(result)
В приведенном выше Java-коде изменение исходит из:
getSeedDate()
new SecureRandom().nextBytes(bArr); в magic()
Давайте изменим их:
public static Date getSeedDate() {
Date seed = new Date(0L); // 0L: the milliseconds since January 1, 1970, 00:00:00 GMT.
return seed;
}
// new SecureRandom().nextBytes(bArr);
for (int i = 0; i < 8; i++) {
bArr[i] = 'X';
}
Теперь вывод Java всегда одинаков:
Z6iTzNaJcDVdL5Rv8psb1D+xakq4By4KUxipmVv0ASjZUfIZO3nu+an5p27BxQ+x1+qoMLgD4vEub5PWcs69FDFy4y2etgiBCiCVnOM6RFlYWFhYWFhYWA==
Измените следующее, чтобы программа Python использовала те же значения, что и программа Java.
# payload = auth_key+"|" + x.strftime('%Y-%m-%dT%H:%M:%S.0000%f')[:-3]+"Z"
payload = "d4eee068-272a-4aec-9681-5e16dcef6fbd|1970-01-01T00:00:00.0000000Z"
# salt = os.urandom(8)
salt = b'XXXXXXXX'
key = pbkdf2_hmac(
hash_name = 'SHA1',
# password = b"75820705-2b7a-46dc-b811-0f6ad4ff33af",
password = b"bd1676b5-5ce3-4351-a39b-36a7b7219c11",
salt = salt,
iterations = 100,
dklen = 384
)
Обратите внимание, что password должен быть идентичен тому, что есть в Java.
Теперь программа Python всегда выводит:
Z6iTzNaJcDVdL5Rv8psb1D+xakq4By4KUxipmVv0ASjZUfIZO3nu+an5p27BxQ+x1+qoMLgD4vEub5PWcs69FDFy4y2etgiBCiCVnOM6RFk=
Java outputVal.length() — 120, а Python len(result) — 108.
Давайте посмотрим их вместе:
Джава: Z6iTzNaJcDVdL5Rv8psb1D+xakq4By4KUxipmVv0ASjZUfIZO3nu+an5p27BxQ+x1+qoMLgD4vEub5PWcs69FDFy4y2etgiBCiCVnOM6RFлЫВФхЙВФхЙВА==
Питон: Z6iTzNaJcDVdL5Rv8psb1D+xakq4By4KUxipmVv0ASjZUfIZO3nu+an5p27BxQ+x1+qoMLgD4vEub5PWcs69FDFy4y2etgiBCiCVnOM6RFк=
В этот момент я заметил, что в Java у вас есть doFinal и bArr,
byteArrayOutputStream.write(doFinal);
byteArrayOutputStream.write(bArr);
В то время как в Python вы используете только plain
plain = pad(payload.encode("UTF-8"))
encrypted_text = cipher.encrypt(plain)
result = base64.b64encode(encrypted_text).decode("UTF-8")
Эксперимент показывает, что удаление byteArrayOutputStream.write(bArr); в Java генерирует точную строку, что и Python.
убедитесь, что входные данные одинаковы, прежде чем сравнивать результаты
дважды проверьте строки, которые вы используете
в некоторых случаях метод проб и ошибок может сработать
я действительно глуп, хахахаха, я не заметил "byteArrayOutputStream.write(bArr);" Просто добавил его в свой массив байтов, и все работает хорошо! Спасибо, бро
Вы также можете добавить часть
importв Java? чтобы мы могли видеть, какие библиотеки используются.