问题描述
由于我们将哈希密码迁移到了不同的平台,因此我试图在Liferay使用PBKDF2WithHmacSHA1/160/128000的c#中编写相同的算法.但是,哈希密码值在C#中却有所不同不太确定我在哪里做错了.我对Java不太熟悉.
I am trying to write the same algorithm in c# of what Liferay uses PBKDF2WithHmacSHA1/160/128000 as we have hashed passwords migrated to different platforms. however the hashed passwords values are coming as different in C#Not too sure where I am doing wrong. I am not very much familiar with Java.
在Java中传递的参数是
parameters passed in Java are
String algorithm = "PBKDF2WithHmacSHA1/160/128000"
String plainTextPassword = "!!Fres1966"
String encryptedPassword = null
Java中的
哈希值="AAAAoAAB9ACnaq7ogwbkgRWfNcsfFh2DEMKmfl7JAqR8SAqk"c#中的哈希值="FAAAAAD0AQAAAAAAAAAAAFJZUX3EUFdhFHeMZLSdlo9RxsxO"
hash value in Java = "AAAAoAAB9ACnaq7ogwbkgRWfNcsfFh2DEMKmfl7JAqR8SAqk"hash value in c# = "FAAAAAD0AQAAAAAAAAAAAFJZUX3EUFdhFHeMZLSdlo9RxsxO"
我无法复制的一行代码是
There is one line of code which I have not been able to replicate is
BigEndianCodec.putLong(_saltBytes, 0, SecureRandomUtil.nextLong())
不太确定这行代码在做什么以及如何在c#中复制类似的逻辑
not too sure what this line of code is doing and how can I replicate the similar logic in c#
Java代码-------------
Code in Java-------------
public class PBKDF2PasswordEncryptor
extends BasePasswordEncryptor implements PasswordEncryptor {
@Override
public String[] getSupportedAlgorithmTypes() {
return new String[] {PasswordEncryptorUtil.TYPE_PBKDF2};
}
@Override
protected String doEncrypt(
String algorithm, String plainTextPassword,
String encryptedPassword)
throws PwdEncryptorException {
try {
PBKDF2EncryptionConfiguration pbkdf2EncryptionConfiguration =
new PBKDF2EncryptionConfiguration();
pbkdf2EncryptionConfiguration.configure(
algorithm, encryptedPassword);
byte[] saltBytes = pbkdf2EncryptionConfiguration.getSaltBytes();
PBEKeySpec pbeKeySpec = new PBEKeySpec(
plainTextPassword.toCharArray(), saltBytes,
pbkdf2EncryptionConfiguration.getRounds(),
pbkdf2EncryptionConfiguration.getKeySize());
String algorithmName = algorithm;
int index = algorithm.indexOf(CharPool.SLASH);
if (index > -1) {
algorithmName = algorithm.substring(0, index);
}
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(
algorithmName);
SecretKey secretKey = secretKeyFactory.generateSecret(pbeKeySpec);
byte[] secretKeyBytes = secretKey.getEncoded();
ByteBuffer byteBuffer = ByteBuffer.allocate(
2 * 4 + saltBytes.length + secretKeyBytes.length);
byteBuffer.putInt(pbkdf2EncryptionConfiguration.getKeySize());
byteBuffer.putInt(pbkdf2EncryptionConfiguration.getRounds());
byteBuffer.put(saltBytes);
byteBuffer.put(secretKeyBytes);
return Base64.encode(byteBuffer.array());
}
catch (Exception e) {
throw new PwdEncryptorException(e.getMessage(), e);
}
}
private static final int _KEY_SIZE = 160;
private static final int _ROUNDS = 128000;
private static final int _SALT_BYTES_LENGTH = 8;
private static Pattern _pattern = Pattern.compile(
"^.*/?([0-9]+)?/([0-9]+)$");
private class PBKDF2EncryptionConfiguration {
public void configure(String algorithm, String encryptedPassword)
throws PwdEncryptorException {
if (Validator.isNull(encryptedPassword)) {
Matcher matcher = _pattern.matcher(algorithm);
if (matcher.matches()) {
_keySize = GetterUtil.getInteger(
matcher.group(1), _KEY_SIZE);
_rounds = GetterUtil.getInteger(matcher.group(2), _ROUNDS);
}
BigEndianCodec.putLong(
_saltBytes, 0, SecureRandomUtil.nextLong());
}
else {
byte[] bytes = new byte[16];
try {
byte[] encryptedPasswordBytes = Base64.decode(
encryptedPassword);
System.arraycopy(
encryptedPasswordBytes, 0, bytes, 0, bytes.length);
}
catch (Exception e) {
throw new PwdEncryptorException(
"Unable to extract salt from encrypted password " +
e.getMessage(),
e);
}
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
_keySize = byteBuffer.getInt();
_rounds = byteBuffer.getInt();
byteBuffer.get(_saltBytes);
}
}
public int getKeySize() {
return _keySize;
}
public int getRounds() {
return _rounds;
}
public byte[] getSaltBytes() {
return _saltBytes;
}
private int _keySize = _KEY_SIZE;
private int _rounds = _ROUNDS;
private byte[] _saltBytes = new byte[_SALT_BYTES_LENGTH];
}
}
public string HasPassword(string password)
{
byte[] salt = new byte[8];
Rfc2898DeriveBytes Rfcbytes = new Rfc2898DeriveBytes(password, salt,
128000);
byte[] key = Rfcbytes.GetBytes(160/8);
var ms = new MemoryStream(8+salt.Length+key.Length);
using (BinaryWriter writer = new BinaryWriter(ms))
{
writer.Write(160/8);
writer.Write(128000);
writer.Write(salt);
writer.Write(key);
}
byte[] bytes = ms.ToArray();
string finalhash = Convert.ToBase64String(bytes);
return finalhash;
}
推荐答案
BigEndianCodec.putLong(_saltBytes, 0, SecureRandomUtil.nextLong())
似乎是生成一个随机的8字节值并将其写入数组(按Big Endian顺序;但是它是随机的,因此不会没关系)".
BigEndianCodec.putLong(_saltBytes, 0, SecureRandomUtil.nextLong())
Seems to be "Generate a random 8-byte value and write it into an array (in Big Endian order; but it's random, so that doesn't matter)".
所以你想要
using (RandomNumberGenerator csprng = RandomNumberGenerator.Create())
{
csprng.GetBytes(salt);
}
在分配salt
并将其传递给Rfc2898DeriveBytes
'ctor之间.
Between allocating salt
and passing it to Rfc2898DeriveBytes
' ctor.
这篇关于.Net C#中的Liferay加密算法实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!