У меня есть задача переписать некоторый криптокод Python на java. Я новичок в питоне. Код Python:
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.backends import default_backend
backend = default_backend()
PASSWORD = bytes((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16))
key = PBKDF2HMAC(hashes.SHA256(), 32, salt, iterations, backend).derive(PASSWORD)
Моя реализация Java:
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
byte[] PASSWORD = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
SecretKey tmp = factory.generateSecret(new PBEKeySpec(new String(PASSWORD).toCharArray(), salt, iterations, 256));
byte[] key = tmp.getEncoded();
Как видите, PASSWORD — это массив байтов, который я получаю из шестнадцатеричной строки, т. е. 010203….0F10, я не могу его изменить (т. е. не могу указать его как строку в реализации Python, поскольку я понимаю серверные преобразования ПАРОЛЬ к байтовому массиву также). Все работало нормально с этим фиктивным ПАРОЛЕМ, т.е. ключи, сгенерированные кодом python и java, были равны. Но я столкнулся с проблемой, когда пароль изменился на произвольный, т.е. например, AFFFFFFFFDBGEHTH.... Насколько я понимаю проблема с представлением массива байтов java в виде целых чисел со знаком. т.е. когда я конвертирую шестнадцатеричный FFFAAABBBCCCDDDDFFAAAAAAAAAAAABB, например, в байтовый массив, это будет байтовый массив [-1, -6, -86, -69, -68, -52, -35, -35, -1, -86, -86, - 86, -86, -86, -86, -69], но в питоне будет [255, 250, 170, 187, 188, 204, 221, 221, 255, 170, 170, 170, 170, 170, 170 , 187]. Затем, когда я конвертирую массив байтов java в charArray для конструктора PBEKeySpec - new PBEKeySpec (новая строка (новый байт [] {-1, -6, -86, -69, -68, -52, -35, -35, -1 , -86, -86, -86, -86, -86, -86, -69}).toCharArray()... работает неожиданно.
Как мне изменить свой java-код, чтобы получить тот же ключ, что и в python? Насколько я понимаю, мне нужно закодировать строку массива байтов java в то же значение, что и в методе python .derive(...). Заранее спасибо.
ОБНОВИТЬ:
salt = b'salt'
PASSWORD = = bytes((255, 250, 170, 187, 188, 204, 221, 221, 255, 170, 170, 170, 170, 170, 170, 187))
key = PBKDF2HMAC(hashes.SHA256(), 32, salt, 512, backend).derive(PASSWORD)
а также
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
password = new String(new byte[]{-1, -6, -86, -69, -68, -52, -35, -35, -1, -86, -86, -86, -86, -86, -86, -69});
var key = secretKeyFactory
.generateSecret(new PBEKeySpec(password.toCharArray(),
"salt".getBytes(), 512, 256))
.getEncoded();
должен дать тот же результат. Он работает для нового пароля byte[]{1,2,3,4,....16}.
ОБНОВЛЕНИЕ 2: я изменил пароль на unsigned int[], но он все равно не работает:
char[] password = new char[PASSWORD.length];
for (int i = 0; i<PASSWORD.length; password[i] = (char)(PASSWORD[i++] & 0xFF));
var key = secretKeyFactory
.generateSecret(new PBEKeySpec(password, "salt".getBytes(), 512, 256))
.getEncoded();
-1
и255
— одно и то же значение байта011111111b
. Первая интерпретация со знаком (дополнение до 2), вторая интерпретация без знака. Все зависит от того, как вы (обычно человек) хотите это интерпретировать. Компьютер не запутается. - person Kayaman   schedule 15.09.2020