Not sure if it is the right output but when I hash a password with argon in java, i get the output:
$argon2i$v=19$m=512,t=2,p=2$J1w6n04CBSEA8p0cCqeK7A$tb1ihqduhONYZN0+ldKkw980Y7h7ZJ2OcDTsXyIMibo
while python gives me:
argon2$argon2i$v=19$m=512,t=2,p=2$TjZiM3ZTdGFIQUlZ$CocCpAIXQc722ndqkFZWxw
the parameters seem the same: i, 512, 2, p =2
Any argon2 guru who can tell me how I can have the same length output? Prefer playing with the java since it is a simple ussd app.
After the p=2 in the string, there is a dollar sign. The string between this dollar sign and the next dollar sign is the salt of the hash. After the second dollar sign is the actual key that has been derived by Argon2. In the Java example, (after being base64 decoded), the hash length is 32. However, in Python, the hash length is 16 (which is the default in Python). So, in Python, if you did:
import argon2
argon2.hash_password(b"Password",memory_cost=512,time_cost=2,parallelism=2,hash_len=32)
Then you will have the same length hash as in the Java example. Also, if you specify the same salt for both the Python and Java implementations, then the hashes should be identical to each other (given that the parameters are the same between the two).
Related
I have this code created using Google Guava:
String sha256hex = Hashing.sha256()
.hashString(cardNum, StandardCharsets.UTF_8)
.toString();
How I can verify the generated values is a properly generated hash?
SHA-256 and, in general, the family of SHA 2 algorithms is wonderfully described in Wikipedia and different RFCs, RFC 6234 and the superseded RFC 4634.
All these sources dictate that the output provided by the SHA 256 hash function is 256 bits length, 32 bytes (the number that accompanies the SHA word is the mentioned value for every algorithm in the family, roughly speaking).
These sequence of bytes is typically encoded in hex. This is the implementation provided by Guava as well.
Then, the problem can be reduced to identify if a string in Java is a valid hex encoding.
That problem has been already answered here, in SO, for example in this question.
For its simplicity, consider the solution proposed by #laycat:
boolean isHex = mac_addr.matches("^[0-9a-fA-F]+$");
As every byte is encoded with two hex characters and, as mentioned, the SHA-256 algorithm produces and output of 32 bytes you can safely check for a string of 64 characters length, as suggested in the answer of #D.O. as well. Your validation code could be similar to this:
boolean canBeSha256Output = sha256Hex.matches("^[0-9a-fA-F]{64}$");
Please, be aware that there is no possibility for saying if a character hex string of a certain length on its own is or not the result of a hash function, whichever hash function you consider.
You only can be sure that a hash output is a hash output if and only if it matches the result of applying the corresponding hash function over the original input.
You could use a regex to verify that it looks like a sha256 hash(64 hexadecimal characters), like
\b[A-Fa-f0-9]{64}\b
in some tests i using MessageDigest library in Groovy and sometimes this function returns incorrect value. Here is my code below:
import java.security.MessageDigest;
String.metaClass.toSHA256 = {
def messageDigest = MessageDigest.getInstance("SHA-256")
messageDigest.update(delegate.getBytes("UTF-8"))
new BigInteger(1, messageDigest.digest()).toString(16).padLeft(40, '0')
}
for example - i tryed to encode to SHA-256 this string:
582015-04-23 20:47:112015-04-23 23:59:000020502015-04-23 20:47:11tests-from-api["afoot"]33facafaece3afd353bcbe88637d11b7
My method return
cb2814380117cd5621064c1d7512b32e3cb8c8cb2b1f20016f6da763598d738
But online generators, returns 0cb2814380117cd5621064c1d7512b32e3cb8c8cb2b1f20016f6da763598d738
it calculates wrong like 2 times in 40 tries
Could you help me how to fix it?
You're missing a '0' at the start, because you're padding left to 40 characters (presumably having copied that code from something where the hash is expected to be 40 characters) instead of the 64 characters that actually makes up a SHA-256 hash (in hex).
So you could just fix the padLeft code - but personally I would just avoid using BigInteger for hex conversions. That's not what it's designed for - it's designed for maths operations on large integers.
Instead, use one of the many hex converters in common utility libraries - which are designed precisely to convert byte arrays to hex, with nothing about integers at all. If you don't want to use a library, there's plenty of code on Stack Overflow to convert a byte[] to hex.
I have written a method to convert a plain text into it's hashcode using MD5 algorithm. Please find the code below which I used.
public static String convertToMD5Hash(final String plainText){
MessageDigest messageDigest = null;
try {
messageDigest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
LOGGER.warn("For some wierd reason the MD5 algorithm was not found.", e);
}
messageDigest.reset();
messageDigest.update(plainText.getBytes());
final byte[] digest = messageDigest.digest();
final BigInteger bigInt = new BigInteger(1, digest);
String hashtext = bigInt.toString(8);
return hashtext;
}
This method works perfectly but it returns a lengthy hash. I need to limit this hash text to 8 characters. Is there any possibilities to set the length of the hashcodes in Java?
Yes and No. You can use a substring of the original hash if you always cut the original hash-string similary (ie. 8 last/first characters). What are you going to do with that "semi-hash" is another thing.
Whatever it is you're going to do, be sure it has nothing to do with security.
Here's why: MD5 is 128-bit hash, so there's 2^128 = ~340,000,000,000,000,000,000,000,000,000,000,000,000 possible permutations. The quite astronomical amount of permutations is the thing that makes bruteforcing this kind of string virtually impossible. By cutting down to 8 characters, you'll end up with 32-bit hash. This is because a single hex-value takes 4 bits to represent (thus, also 128-bit / 4 bit = 32 hex-values). With 32-bit hash there's only 2^32 = 4,294,967,296 combinations. That's about 79,228,162,514,264,337,593,543,950,336 times less secure than original 128-bit hash and can be broken in matter of seconds with any old computer that has processing power of an 80's calculator.
No. MD5 is defined to return 128 bit values. You could use Base64 to encode them to ASCII and truncate it using String#substring(0, 8).
In Java 8 (not officially released yet), you can encode a byte[] to Base64 as follows:
String base64 = Base64.getEncoder().encodeToString(digest);
For earlier Java versions see Decode Base64 data in Java
all hash algorithms should randomly change bits in whole hash whenever any part of data has changed. so you can just choose 8 chars from your hash. just don't pick them randomly - it must be reproducible
Firstly as everyone has mentioned, the 64 bit hash is not secure enough. Ultimately it depends on what you exactly plan to do with the hash.
If you still need to convert this to 8 characters, I suggest downcasting the BigInteger to a Long value using BigIteger.longValue()
It will ensure that the long value it produces is consistent with the hash that was produced.
I am not sure if taking most significant 64 bits from the 128 bit hash is good idea. I would rather take least significant 64 bits. What this ensures is that
when hash(128, a) = hash(128, b) then hash(64, a) = hash(64, b) will always be true.
But we have to live with collision in case of 64 bits i.e. when hash(64, a) = hash(64, b) then hash(128, a) = hash(128, b) is not always true.
In a nutshell, we ensure that we do not have a case where 128 bit hashes of 2 texts are different, but their 64 bit hashes are same. It depends on what you really use the hash for, but I personally feel this approach is more correct.
I need to generate a unique hash from a ID value of type Long. My concern is that it should not globally generate the same hash from two different Long/long values.
MD5 hashing looks a nice solution but the hash String is very long. I only need characters
0-9
a-z and A-Z
And just 6-characters like: j4qwO7
What could be the simpliest solution?
Your requirements cannot be met. You've got an alphabet of 62 possible characters, and 6 characters available - which means there are 626 possible IDs of that form.
However, there are 2568 possible long values. By the pigeon-hole principle, it's impossible to give each of those long values a different ID of the given form.
You don't have to use the hex representation. Build your own hash representation by using the actual hash bytes from the function. You could truncate the hash output to simplify the hash representation, but that would make collisions more probable.
Edit:
The other answers stating that what you ask isn't possible, based on the number of possible long values, is teoretically true, if you actually need the whole range.
If your IDs are auto incremented from zero and up, just 62^6 = 56800235584 values might be more than enough for you, depending on your needs.
Step 1. Switch to using ints instead of longs, or allow for a longer "hash". See every other answer for discussion of why 6 characters is unsufficient for dealing with longs.
Step 2. Encrypt your number using an algorithm which does not using padding. Personally, I suggest skip32 encoding. I make no promises that this is strong enough for security, but if your goal is "make random-looking IDs," it works well.
Step 3. Encode your number as a base_62 number (as opposed to base_10, not as opposed to base64 encoding).
Your question doesn't make sense.
'Unique hash' is a contradiction in terms.
A 'unique hash' value of a Java long must be 64 bits in length, like the long itself, and of course the simplest hash function for that is f(x) = x, i.e. the long value itself.
6 characters that can be 0-9, A-Z, and a-z can only yield 62^6 = 56800235584 distinct values, which isn't enough.
You can use long value irself as same as hash (for indexing/search purposes).
if you need to obfuscate/hide your long value, you can use any symmetric
encryption algorithm with 64-bit block, for example - DES or AES in ECB-mode.
Update:
No need to use Hashids. Base 36 is pretty enough.
long id = 12345;
String hash = Integer.toString(Math.abs((int)id), 36);
Original answer, with Hashids:
You might want to use Hashids
long id = 12345;
Hashids hashids = new Hashids("this is my salt");
String hash = hashids.encrypt(id); // "ryBo"
"ryBo" is going to be unique, as it can be converted back to your long. Hashids just converts, doesn't hash further.
long[] numbers = hashids.decrypt("ryBo");
// numbers[0] == 12345
If you really have a 64-bit value, the hash string is going to be quite long (around 16 characters, depending on the alphabet), but if you don't plan to have more than 2^16 thingies, you can get away with truncating the 64-bit hash to 32-bit (an int).
long id = 12345;
String hash = hashids.encrypt(Math.abs((int)id));
I want to encrypt an integer with DES, the resultant cipher text should also be an integer.
Decryption function should follow this notion as well.
I am trying to modifying the code at Encrypting a String with DES, by converting the byte array to integer, instead of using Base64 encoding. However the decryption function throws an exception of improper padding, as the conversion of integer to byte[] results in a 4 byte array.
Is there any other encryption algorithm that I can use to achieve this.
I am not concerned about the weakness of the cipher text.
If you are running an Integer value through DES to produce another Integer value, and you don't care about the cipher text weakness, then you are merely doing a very expensive hashing operation. You'd be better off generating a random integer as the key and bitwise xor-ing the exponent and the random integer. This would take nanoseconds to compute and have exactly the same security.
DES has a 64 bit blocksize, so in general the output from the encryption of a 32 bit int will be a 64 bit block. It will be easier to encrypt a 64 bit long to another 64 bit long. Use ECB mode so that padding is not an issue, or at least you are adding zero bits to the front of your int to extend it to 64 bits.
If you merely want to smush up your int then Jim's suggestion is excellent.
You want to look at Format Perserving Encryption. There are a couple of techniques for it, but in general all of them will generate a value in the same domain as your input ( i.e. integers, credit card numbers,etc)