【问题标题】:Python equivalent of java PBKDF2WithHmacSHA1Python 等效于 java PBKDF2WithHmacSHA1
【发布时间】:2019-01-31 05:49:46
【问题描述】:

我的任务是构建 API 的使用者,该使用者需要具有 UNIX 时间种子值的加密令牌。我展示的示例是使用我不熟悉的 Java 实现的,并且在阅读文档和其他堆栈文章后无法找到解决方案。

使用javax.crypto.SecretKey、javax.crypto.SecretKeyFactory、javax.crypto.spec.PBEKeySpec 和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 吗?对于模糊的问题,我很抱歉,我不熟悉加密过程,并且觉得即使知道正确的构造函数是什么,也是朝着正确方向迈出的一步。

【问题讨论】:

  • 几年前写的,应该是一个OK的起点:gist.github.com/is/13a519282e676dca861e
  • 请注意:代码中的盐不应该与密钥相同。要么生成一个确定的非重复序列,要么使用 SecureRandom 生成它;然后将其与加密消息一起传输。

标签: java python pbkdf2 hmacsha1 hashlib


【解决方案1】:

是的,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 代码相同的密钥。

但是,这段代码的问题(如备忘录的comment 中所述)是盐的使用。每个密码的盐值应该是随机且唯一的。您可以使用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,或者更好的是使用 authenticated encryption 算法。

【讨论】:

  • 感谢亚当提供的重要信息。关于盐的信息特别有用。 API 服务实际上为我提供了有关盐创建的示例,因此我可以提供该反馈。接受和赞赏
  • 再次感谢这个亚当;只是为了跟进;以上java 示例中的skc 和tmp 有什么区别?我能够使用您提到的方法重现tmp,但是我需要AES 实例来创建SecretKeySpec 吗?如果不是,我将如何获得 skc 的等效值?
  • skc 和 tmp 都包含相同的密钥 - 相同的字节。我们必须在cipher.init 中为key 参数指定加密算法,因此我们使用SecretKeySpec 对象和"AES" 来作为algorithm 参数。它基本上是相同的键,只是不同的对象。
  • 啊,好吧,所以实际字节是一样的,但是SecretKey 对象上的AES 字段是Cipher 对象使用的?有没有在 python 中实现该类型密码的示例?
猜你喜欢
  • 2023-03-26
  • 2016-08-04
  • 1970-01-01
  • 2012-05-29
  • 2011-09-02
  • 1970-01-01
  • 2014-01-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多