Python эквивалент java PBKDF2WithHmacSHA1 - PullRequest
0 голосов
/ 24 августа 2018

Мне поручено создать потребителя API, для которого требуется зашифрованный токен с начальным значением, которое соответствует времени UNIX.Показанный мной пример был реализован с использованием Java, с которым я не знаком, и после прочтения документации и других статей стека не смогли найти решение.

Использование javax.crypto.SecretKey, javax.crypto.SecretKeyFactory, *Для протоколов 1005 * и javax.crypto.spec.SecretKeySpec мне нужно сгенерировать токен, подобный приведенному ниже:

public class EncryptionTokenDemo {

    public static void main(String args[]) {
        long millis = System.currentTimeMillis();
        String time = String.valueOf(millis);
        String secretKey = "somekeyvalue";
        int iterations = 12345;
        String iters = String.valueOf(iterations);
        String strToEncrypt_acctnum = "somevalue|" + time + "|" + iterations;

        try {

            byte[] input = strToEncrypt_acctnum.toString().getBytes("utf-8");
            byte[] salt = secretKey.getBytes("utf-8");
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            SecretKey tmp = factory.generateSecret(new PBEKeySpec(secretKey.toCharArray(), salt, iterations, 256));
            SecretKeySpec skc = new SecretKeySpec(tmp.getEncoded(), "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, skc);
            byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
            int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
            ctLength += cipher.doFinal(cipherText, ctLength);
            String query = Base64.encodeBase64URLSafeString(cipherText);
            // String query = cipherText.toString();
            System.out.println("The unix time in ms is :: " + time);
            System.out.println("Encrypted Token is :: " + query);
        } catch (Exception e) {
            System.out.println("Error while encrypting :" + e);

        }

    }
}

Должен ли я использовать встроенную библиотеку hashlib для реализации чего-то подобного?Я не могу найти документацию для реализации шифрования PBKDF2 с итерациями / солью в качестве входных данных.Должен ли я использовать pbkdf2?Извините за смутные вопросы, я не знаком с процессом шифрования и чувствую, что даже просто зная, каким будет правильный конструктор, это шаг в правильном направлении.

1 Ответ

0 голосов
/ 28 августа 2018

Да, эквивалент Python равен hashlib.pbkdf2_hmac.Например, этот код:

from hashlib import pbkdf2_hmac

key = pbkdf2_hmac(
    hash_name = 'sha1', 
    password = b"somekeyvalue", 
    salt = b"somekeyvalue", 
    iterations = 12345, 
    dklen = 32
)

print(key)

создает тот же ключ, что и ваш код Java.

Однако проблема с этим кодом (как упомянуто в комментариях memo ) заключается в использовании соли.Соль должна быть случайной и уникальной для каждого пароля.Вы можете создать безопасные случайные байты с помощью os.urandom, поэтому лучшим примером будет:

from hashlib import pbkdf2_hmac
from os import urandom

salt = urandom(16)
key = pbkdf2_hmac('sha1', b"somekeyvalue", salt, 12345, 32)

Вы также можете увеличить количество итераций (я думаю, рекомендуемое минимальное число - 10 000).


Остальной код легко «перевести».

  • Для отметки времени, используйте time.time, чтобы получить текущее время и умножьте на 1000.

    import time
    
    milliseconds = str(round(time.time() * 1000))
    
  • Для кодирования вы можете использоватьbase64.urlsafe_b64encode (включает заполнение, но вы можете удалить его с помощью .rstrip(b'=')).

  • Теперь для части шифрования Python не имеетвстроенный модуль шифрования, поэтому вам придется использовать стороннюю библиотеку.Я рекомендую pycryptodome или cryptography.
    В этот момент я должен предупредить вас, что используемый вами режим AES очень слабый.Пожалуйста, рассмотрите возможность использования CBC или CTR или, что еще лучше, используйте алгоритм шифрования с аутентификацией .

...