2 * Copyright © 2018 Inocybe Technologies and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.aaa.impl.password.service;
10 import org.apache.shiro.codec.Base64;
11 import org.apache.shiro.crypto.hash.DefaultHashService;
12 import org.apache.shiro.crypto.hash.Hash;
13 import org.apache.shiro.crypto.hash.HashRequest;
14 import org.apache.shiro.crypto.hash.SimpleHashRequest;
15 import org.apache.shiro.util.ByteSource;
16 import org.opendaylight.aaa.api.password.service.PasswordHash;
17 import org.opendaylight.aaa.api.password.service.PasswordHashService;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.password.service.config.rev170619.PasswordServiceConfig;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.password.service.config.rev170619.PasswordServiceConfigBuilder;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
23 public class DefaultPasswordHashService implements PasswordHashService {
24 private static final Logger LOG = LoggerFactory.getLogger(DefaultPasswordHashService.class);
26 public static final String DEFAULT_HASH_ALGORITHM = "SHA-512";
27 public static final int DEFAULT_NUM_ITERATIONS = 20000;
29 private final DefaultHashService hashService;
31 public DefaultPasswordHashService() {
32 this(new PasswordServiceConfigBuilder().build());
35 public DefaultPasswordHashService(final PasswordServiceConfig passwordServiceConfig) {
36 hashService = createHashService(passwordServiceConfig.getIterations(), passwordServiceConfig.getAlgorithm(),
37 passwordServiceConfig.getPrivateSalt());
41 public PasswordHash getPasswordHash(final String password) {
42 final HashRequest hashRequest = new HashRequest.Builder()
43 .setAlgorithmName(hashService.getHashAlgorithmName())
44 .setIterations(hashService.getHashIterations())
45 .setSource(ByteSource.Util.bytes(password)).build();
47 final Hash hash = hashService.computeHash(hashRequest);
48 return PasswordHashImpl.create(
49 hash.getAlgorithmName(),
50 hash.getSalt().toBase64(),
56 public PasswordHash getPasswordHash(final String password, final String salt) {
57 final HashRequest hashRequest = new SimpleHashRequest(
58 hashService.getHashAlgorithmName(),
59 ByteSource.Util.bytes(password),
60 ByteSource.Util.bytes(Base64.decode(salt)),
61 hashService.getHashIterations());
63 final Hash hash = hashService.computeHash(hashRequest);
64 return PasswordHashImpl.create(
65 hash.getAlgorithmName(),
66 hash.getSalt().toBase64(),
72 public boolean passwordsMatch(final String plaintext, final String stored, final String salt) {
73 return getPasswordHash(plaintext, salt).getHashedPassword().equals(stored);
76 private static DefaultHashService createHashService(final Integer numIterations, final String hashAlgorithm,
77 final String privateSalt) {
78 final DefaultHashService hashService = new DefaultHashService();
80 if (numIterations != null) {
81 hashService.setHashIterations(numIterations);
82 LOG.info("DefaultPasswordHashService will utilize configured iteration count={}", numIterations);
84 hashService.setHashIterations(DEFAULT_NUM_ITERATIONS);
85 LOG.info("DefaultPasswordHashService will utilize default iteration count={}", DEFAULT_NUM_ITERATIONS);
88 if (hashAlgorithm != null) {
89 hashService.setHashAlgorithmName(hashAlgorithm);
90 LOG.info("DefaultPasswordHashService will utilize configured algorithm={}", hashAlgorithm);
92 hashService.setHashAlgorithmName(DEFAULT_HASH_ALGORITHM);
93 LOG.info("DefaultPasswordHashService will utilize default algorithm={}", DEFAULT_HASH_ALGORITHM);
96 if (privateSalt != null) {
97 hashService.setPrivateSalt(ByteSource.Util.bytes(privateSalt));
98 LOG.info("DefaultPasswordHashService will utilize a configured private salt");
100 hashService.setGeneratePublicSalt(true);
101 LOG.info("DefaultPasswordHashService will not utilize a private salt, since none was configured");