首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Keycloak自定义PasswordHashProvider,每个连接上的salt更改

Keycloak自定义PasswordHashProvider,每个连接上的salt更改
EN

Stack Overflow用户
提问于 2021-02-09 22:47:03
回答 1查看 202关注 0票数 1

我正在尝试创建一个自定义的PasswordHashProvider。我成功地创建了组件,算法正在工作,数据库中保存的密码是正确的。

盐是存储在数据库中的,但我不明白它是如何存储的。我以为是64号盐,但不匹配。

代码语言:javascript
复制
database secret_data : {"value":"v8Po+hMGZbS2tWr4IGRXqy3FJyQIavjsrpXHwomWHwRRs+iRVInd+9naF681EENm76lF1omK+BqsPIRrtKH1VQ==","salt":"DEiO17h4/+6gwzxn"}
database credential_data : {"hashIterations":5000,"algorithm":"message-digest"}

在创建密码和连接用户时,我在控制台中添加日志。盐是生成并存储的,但在连接期间检索到的盐在每次尝试时都是不同的。

当我注册用户密码时:

代码语言:javascript
复制
New salt : [B@7bb894a0

当我尝试连接用户时:

代码语言:javascript
复制
Existing salt: [B@d433036
// retry connection
Existing salt: [B@355bae9a

有人知道盐是怎么储存的吗?

我的类(对于测试,我强制迭代到5000次):

代码语言:javascript
复制
import org.keycloak.credential.hash.PasswordHashProvider;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.credential.PasswordCredentialModel;

import java.util.Base64;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.nio.charset.StandardCharsets;

import java.math.BigInteger; 
import java.security.NoSuchAlgorithmException; 

public class MessageDigestPasswordHashProvider implements PasswordHashProvider {
    private final int defaultIterations;
    private final String providerId;
    private byte[] salt;

    public MessageDigestPasswordHashProvider(String providerId, int defaultIterations) {
        this.providerId = providerId;
        this.defaultIterations = defaultIterations;
    }

    @Override
    public boolean policyCheck(PasswordPolicy policy, PasswordCredentialModel credential) {
        int policyHashIterations = 5000;
        return credential.getPasswordCredentialData().getHashIterations() == policyHashIterations
                && providerId.equals(credential.getPasswordCredentialData().getAlgorithm());
    }

    @Override
    public PasswordCredentialModel encodedCredential(String rawPassword, int iterations) {
        iterations = 5000;
        byte[] salt = generateSalt();
        this.salt = salt;
        System.out.print("New salt : ");
        System.out.println(salt);
        String encodedPassword = encode(rawPassword, iterations);

        return PasswordCredentialModel.createFromValues(providerId, salt, iterations, encodedPassword);
    }

    @Override
    public String encode(String rawPassword, int iterations) {
        iterations = 5000;
        byte[] salt = this.salt;
        System.out.print("Salt fonction encode :");
        System.out.println(salt);
        String salted = rawPassword + "{" + salt.toString() + "}";
        byte[] digest = getSha512(salted.getBytes());
        System.out.println(iterations);
        for (int i = 1; i < iterations; i++) {
            digest = getSha512(concat(digest, salted.getBytes()));
        }

        return Base64.getEncoder().encodeToString(digest);
    }

    @Override
    public boolean verify(String rawPassword, PasswordCredentialModel credential) {
        this.salt = credential.getSalt();
        System.out.print("Existing salt: ");
        System.out.println(this.salt);
        String encodedPassword = encode(rawPassword, credential.getHashIterations());
        return encodedPassword.equals(credential.getValue());
    }


    private static byte[] generateSalt() {
        SecureRandom random = new SecureRandom();
        byte salt[] = new byte[12];
        random.nextBytes(salt);
        return salt;
    }
    @Override
    public void close() {

    }
    public static byte[] getSha512(byte[] value) {
        try { 
            MessageDigest md = MessageDigest.getInstance("SHA-512"); 
            byte[] messageDigest = md.digest(value); 
            return messageDigest;
        } 
        catch (NoSuchAlgorithmException e) { 
            throw new RuntimeException(e); 
        } 
    }
    public static byte[] concat(byte[] a, byte[] b) {
        byte[] c = new byte[a.length + b.length];
        System.arraycopy(a, 0, c, 0, a.length);
        System.arraycopy(b, 0, c, a.length, b.length);
        return c;
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-02-10 02:16:15

盐是存储在数据库中的,但我不明白它是如何存储的。我以为是64号盐,但不匹配。

它是基于64位的。

盐是生成并存储的,但在连接期间检索到的盐在每次尝试时都是不同的。

问题是:

代码语言:javascript
复制
System.out.print("New salt : ");
System.out.println(salt);

你不是在打印盐的实际含量,你是在打印对象“盐”。

请尝试:

代码语言:javascript
复制
System.out.println(Arrays.toString(this.salt));
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66121272

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档