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 java.util.Optional;
11 import org.apache.shiro.codec.Base64;
12 import org.apache.shiro.crypto.SecureRandomNumberGenerator;
13 import org.apache.shiro.crypto.hash.DefaultHashService;
14 import org.apache.shiro.crypto.hash.Hash;
15 import org.apache.shiro.crypto.hash.HashRequest;
16 import org.apache.shiro.crypto.hash.SimpleHashRequest;
17 import org.apache.shiro.util.ByteSource;
18 import org.opendaylight.aaa.api.password.service.PasswordHash;
19 import org.opendaylight.aaa.api.password.service.PasswordHashService;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.password.service.config.rev170619.PasswordServiceConfig;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
24 public class DefaultPasswordHashService implements PasswordHashService {
26 private static final Logger LOG = LoggerFactory.getLogger(DefaultPasswordHashService.class);
28 public static final String DEFAULT_HASH_ALGORITHM = "SHA-512";
29 public static final int DEFAULT_NUM_ITERATIONS = 20000;
31 private final DefaultHashService hashService = new DefaultHashService();
33 public DefaultPasswordHashService() {
34 hashService.setRandomNumberGenerator(new SecureRandomNumberGenerator());
35 hashService.setGeneratePublicSalt(true);
36 setNumIterations(Optional.of(DEFAULT_NUM_ITERATIONS));
37 setHashAlgorithm(Optional.of(DEFAULT_HASH_ALGORITHM));
40 public DefaultPasswordHashService(final PasswordServiceConfig passwordServiceConfig) {
42 final Optional<Integer> numIterationsOptional = Optional.ofNullable(passwordServiceConfig.getIterations());
43 setNumIterations(numIterationsOptional);
45 final Optional<String> hashAlgorithmOptional = Optional.ofNullable(passwordServiceConfig.getAlgorithm());
46 setHashAlgorithm(hashAlgorithmOptional);
48 final Optional<String> privateSaltOptional = Optional.ofNullable(passwordServiceConfig.getPrivateSalt());
49 setPrivateSalt(privateSaltOptional);
52 private void setNumIterations(final Optional<Integer> numIterationsOptional) {
53 if (numIterationsOptional.isPresent()) {
54 final Integer numIterations = numIterationsOptional.get();
55 hashService.setHashIterations(numIterations);
56 LOG.info("DefaultPasswordHashService will utilize configured iteration count={}", numIterations);
58 hashService.setHashIterations(DEFAULT_NUM_ITERATIONS);
59 LOG.info("DefaultPasswordHashService will utilize default iteration count={}", DEFAULT_NUM_ITERATIONS);
63 private void setHashAlgorithm(final Optional<String> hashAlgorithmOptional) {
64 if (hashAlgorithmOptional.isPresent()) {
65 final String hashAlgorithm = hashAlgorithmOptional.get();
66 hashService.setHashAlgorithmName(hashAlgorithm);
67 LOG.info("DefaultPasswordHashService will utilize configured algorithm={}", hashAlgorithm);
69 hashService.setHashAlgorithmName(DEFAULT_HASH_ALGORITHM);
70 LOG.info("DefaultPasswordHashService will utilize default algorithm={}", DEFAULT_HASH_ALGORITHM);
74 private void setPrivateSalt(final Optional<String> privateSaltOptional) {
75 if (privateSaltOptional.isPresent()) {
76 hashService.setPrivateSalt(ByteSource.Util.bytes(privateSaltOptional.get()));
77 LOG.info("DefaultPasswordHashService will utilize a configured private salt");
79 LOG.info("DefaultPasswordHashService will not utilize a private salt, since none was configured");
84 public PasswordHash getPasswordHash(final String password) {
85 final HashRequest hashRequest = new HashRequest.Builder()
86 .setAlgorithmName(hashService.getHashAlgorithmName())
87 .setIterations(hashService.getHashIterations())
88 .setSource(ByteSource.Util.bytes(password)).build();
90 final Hash hash = hashService.computeHash(hashRequest);
91 return PasswordHashImpl.create(
92 hash.getAlgorithmName(),
93 hash.getSalt().toBase64(),
99 public PasswordHash getPasswordHash(final String password, final String salt) {
100 final HashRequest hashRequest = new SimpleHashRequest(
101 hashService.getHashAlgorithmName(),
102 ByteSource.Util.bytes(password),
103 ByteSource.Util.bytes(Base64.decode(salt)),
104 hashService.getHashIterations());
106 final Hash hash = hashService.computeHash(hashRequest);
107 return PasswordHashImpl.create(
108 hash.getAlgorithmName(),
109 hash.getSalt().toBase64(),
110 hash.getIterations(),
115 public boolean passwordsMatch(final String plaintext, final String stored, final String salt) {
116 final String hash = getPasswordHash(plaintext, salt).getHashedPassword();
117 return hash.equals(stored);