我正在使用springsecurity开发一个spring引导应用程序,它连接到最初由django生成的数据库,其中所有用户密码都存储在django的数据库中 pbkdf2_sha256
格式。
<algorithm>$<iterations>$<salt>$<hash>
看看Spring的保安 Pbkdf2PasswordEncoder
,我基本上能够找到它,并创建一个编码器,能够编码和匹配django的格式。
在成功地对它进行了单元测试之后,我在django生成的示例值上进行了尝试。。。结果失败了。
为什么这个编码器与django生成的值不匹配?django在引擎盖下表演~magic~?我还尝试了多种java的替代品 SecurityFactory
实施。django源代码中的这一行也引起了我的注意,但编写等效的kotlin并没有解决这个问题。
class DjangoPbkdf2PasswordEncoder : PasswordEncoder {
companion object {
private const val PREFIX = "pbkdf2_sha256"
private const val SEPARATOR = "\$"
private const val ITERATIONS = 180000
private const val HASH_WIDTH = 256
private const val ALGORITHM = "PBKDF2WithHmacSHA256"
}
private val saltGenerator: BytesKeyGenerator = KeyGenerators.secureRandom()
private fun base64Decode(string: String): ByteArray {
return Base64.getDecoder().decode(string)
}
private fun base64Encode(bytes: ByteArray): String {
return Base64.getEncoder().encodeToString(bytes)
}
override fun encode(rawPassword: CharSequence): String {
val salt = saltGenerator.generateKey()
val hash = encodeWithSalt(rawPassword, salt)
val encodedHash = base64Encode(hash)
val encodedSalt = base64Encode(salt)
return listOf(PREFIX, ITERATIONS, encodedSalt, encodedHash).joinToString(SEPARATOR)
}
private fun encodeWithSalt(rawPassword: CharSequence, salt: ByteArray): ByteArray {
return encodeWithSaltAndIterations(rawPassword, salt, ITERATIONS)
}
private fun encodeWithSaltAndIterations(rawPassword: CharSequence, salt: ByteArray, iterations: Int): ByteArray {
val keySpec = PBEKeySpec(
rawPassword.toString().toCharArray(),
salt,
iterations,
HASH_WIDTH
)
return try {
SecretKeyFactory.getInstance(ALGORITHM)
.generateSecret(keySpec)
.encoded
} catch (e: GeneralSecurityException) {
throw IllegalStateException("Could not create hash", e)
}
}
override fun matches(rawPassword: CharSequence, partsEncodedPassword: String): Boolean {
if (!partsEncodedPassword.startsWith(PREFIX)) {
throw IllegalArgumentException("Encoded password does not start with: $PREFIX")
}
val parts = partsEncodedPassword.split(SEPARATOR)
if (parts.size != 4) {
throw IllegalArgumentException("The encoded password format does not have 4 parts")
}
val iterations = parts[1].toInt()
val salt = base64Decode(parts[2])
val hash = base64Decode(parts[3])
return MessageDigest.isEqual(
hash,
encodeWithSaltAndIterations(rawPassword, salt, iterations)
)
}
}
1条答案
按热度按时间jgzswidk1#
我在进一步检查django源代码时找到了罪犯。它使用这个函数来生成一个ascii字符串作为salt。这意味着对salt使用base64编码,就像我在我的方法中所做的那样,是不正确的。要解决此问题:
和
应替换为
和