Last active
March 20, 2024 22:37
-
-
Save DeepSnowNeeL/b97214c6410d83b0cbb8f998a53e75d5 to your computer and use it in GitHub Desktop.
java version of C# identity hashing method (password version 3)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.degineo.server.tools; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.spec.InvalidKeySpecException; | |
import java.util.Arrays; | |
import java.util.Base64; | |
import javax.crypto.SecretKey; | |
import javax.crypto.SecretKeyFactory; | |
import javax.crypto.spec.PBEKeySpec; | |
public class TestAuth { | |
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException { | |
String dbPassword = "BASE64PWD"; | |
String password = "test"; | |
//https://github.com/aspnet/Identity/blob/master/src/Core/PasswordHasher.cs | |
System.out.println(u.getPasswordHash()); | |
byte[] dbPass = Base64.getDecoder().decode(dbPassword); | |
System.out.println(dbPass.length == 0x31); | |
System.out.println(Arrays.toString(dbPass)); | |
int prf = ReadNetworkByteOrder(dbPass, 1); | |
System.out.println(prf); | |
int iterCount = ReadNetworkByteOrder(dbPass, 5); | |
System.out.println(iterCount); | |
int saltLength = ReadNetworkByteOrder(dbPass, 9); | |
System.out.println(saltLength); | |
byte[] salt = new byte[saltLength]; | |
System.arraycopy(dbPass, 13, salt, 0, salt.length); | |
//Buffer.BlockCopy(hashedPassword, 13, salt, 0, salt.Length); | |
System.out.println(Arrays.toString(salt)); | |
int subKeyLength = dbPass.length - 13 - salt.length; | |
byte[] expectedSubkey = new byte[subKeyLength]; | |
System.arraycopy(dbPass, 13 + salt.length, expectedSubkey, 0, expectedSubkey.length); | |
System.out.println("expected " + Arrays.toString(expectedSubkey)); | |
//Buffer.BlockCopy(hashedPassword, 13 + salt.Length, expectedSubkey, 0, expectedSubkey.Length); | |
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHMACSHA256"); | |
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterCount, expectedSubkey.length * 8); | |
SecretKey secretKey = factory.generateSecret(spec); | |
byte[] actualSubKey = secretKey.getEncoded(); | |
System.out.println("actual " + Arrays.toString(actualSubKey)); | |
//byte[] actualSubkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, subkeyLength); | |
//return ByteArraysEqual(actualSubkey, expectedSubkey); | |
System.out.println("Password is ok : " + Arrays.equals(expectedSubkey, actualSubKey)); | |
//Create a new hashed password | |
System.out.println("New hash " + hash(password)); | |
} | |
private static String hash(String password) throws NoSuchAlgorithmException, InvalidKeySpecException { | |
int saltSize = 128 / 8; | |
int numBytesRequested = 256; | |
int prf = 1; | |
int iterCount = 10000; | |
byte[] salt = new byte[saltSize]; | |
SecureRandom random = new SecureRandom(); | |
random.nextBytes(salt); | |
//rng.GetBytes(salt); | |
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHMACSHA256"); | |
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterCount, numBytesRequested); | |
SecretKey secretKey = factory.generateSecret(spec); | |
byte[] subkey = secretKey.getEncoded(); | |
//byte[] subkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, numBytesRequested); | |
var outputBytes = new byte[13 + salt.length + subkey.length]; | |
outputBytes[0] = 0x01; // format marker | |
WriteNetworkByteOrder(outputBytes, 1, prf); | |
WriteNetworkByteOrder(outputBytes, 5, iterCount); | |
WriteNetworkByteOrder(outputBytes, 9, saltSize); | |
System.arraycopy(salt, 0, outputBytes, 13, salt.length); | |
//Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.length); | |
System.arraycopy(subkey, 0, outputBytes, 13 + saltSize, subkey.length); | |
//Buffer.BlockCopy(subkey, 0, outputBytes, 13 + saltSize, subkey.Length); | |
System.out.println(outputBytes.length + " " + Arrays.toString(outputBytes)); | |
return Base64.getEncoder().encodeToString(outputBytes); | |
} | |
private static void WriteNetworkByteOrder(byte[] buffer, int offset, int value) { | |
buffer[offset + 0] = (byte) (value >> 24); | |
buffer[offset + 1] = (byte) (value >> 16); | |
buffer[offset + 2] = (byte) (value >> 8); | |
buffer[offset + 3] = (byte) (value >> 0); | |
} | |
private static int ReadNetworkByteOrder(byte[] buffer, int offset) { | |
return ((buffer[offset + 0]) << 24) | ((buffer[offset + 1]) << 16) | ((buffer[offset + 2]) << 8) | ((buffer[offset + 3])); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment