问题
I'm tasked with building a consumer of an API that requires an encrypted token with a seed value that is the UNIX time. The example I was shown was implemented using Java which I'm unfamiliar with, and after reading through documentation and other stack articles have been unable to find a solution.
Using the javax.crypto.SecretKey
, javax.crypto.SecretKeyFactory
, javax.crypto.spec.PBEKeySpec
, and javax.crypto.spec.SecretKeySpec
protocols, I need to generate a token similar to the below:
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);
}
}
}
Should I be using the built-in library hashlib
to implement something like this? I can't really find documentation for implementing a PBKDF2
encryption with iterations/salt as inputs. Should I be using pbkdf2
? Sorry for the vague questions, I'm unfamiliar with the encryption process and feel like even just knowing what the correct constructor would be is a step in the right direction.
回答1:
Yes, the Python equivalent is hashlib.pbkdf2_hmac. For example this code:
from hashlib import pbkdf2_hmac
key = pbkdf2_hmac(
hash_name = 'sha1',
password = b"somekeyvalue",
salt = b"somekeyvalue",
iterations = 12345,
dklen = 32
)
print(key)
produces the same key as your Java code.
However, the problem with this code (as mentioned in memo's comment) is the use of salt. The salt should be random and unique for each password. You can create secure random bytes with os.urandom
, so a better example would be:
from hashlib import pbkdf2_hmac
from os import urandom
salt = urandom(16)
key = pbkdf2_hmac('sha1', b"somekeyvalue", salt, 12345, 32)
You may also want to increase the number of iterations (I think the recommended minimum number is 10,000).
The rest of the code is easy to 'translate'.
For the timestamp, use
time.time
to get the current time and multiply by 1000.import time milliseconds = str(round(time.time() * 1000))
For encoding you can use base64.urlsafe_b64encode (it includes padding, but you could remove it with
.rstrip(b'=')
).Now, for the encryption part, Python doesn't have a built-in encryption module, so you'll have to use a third party library. I recommend pycryptodome or cryptography.
At this point I must warn you that the AES mode you're using is very weak. Please consider using CBC or CTR, or better yet use an authenticated encryption algorithm.
来源:https://stackoverflow.com/questions/52009682/python-equivalent-of-java-pbkdf2withhmacsha1