Coverage Summary for Class: JasyptPasswordEncryptor (com.acciente.oacc.encryptor.jasypt)
Class | Class, % | Method, % | Line, % |
---|---|---|---|
JasyptPasswordEncryptor | 100% (1/ 1) | 100% (6/ 6) | 100% (24/ 24) |
1 /*
2 * Copyright 2009-2018, Acciente LLC
3 *
4 * Acciente LLC licenses this file to you under the
5 * Apache License, Version 2.0 (the "License"); you
6 * may not use this file except in compliance with the
7 * License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
14 * OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License.
17 */
18 package com.acciente.oacc.encryptor.jasypt;
19
20 import com.acciente.oacc.encryptor.PasswordEncryptor;
21 import com.acciente.oacc.normalizer.TextNormalizer;
22
23 import java.io.Serializable;
24 import java.nio.ByteBuffer;
25 import java.nio.CharBuffer;
26 import java.nio.charset.StandardCharsets;
27 import java.util.Arrays;
28
29 /**
30 * Password encryptor implementation that uses the Jasypt digester for creating password hashes.
31 */
32 public final class JasyptPasswordEncryptor implements PasswordEncryptor, Serializable {
33 private static final long serialVersionUID = 1L;
34
35 public static final String NAME = "jasypt";
36
37 private static final StandardByteDigesterPool digesterPool = new StandardByteDigesterPool();
38 private static final PasswordEncoderDecoder passwordEncoderDecoder = new PasswordEncoderDecoder();
39
40 private final String algorithm;
41 private final int iterations;
42 private final int saltSizeBytes;
43
44 /**
45 * Creates a password encryptor that uses the Jasypt digester for password hashing with the specified values for
46 * algorithm, iterations and saltSizeBytes.
47 *
48 * @param algorithm the name of the message digest algorithm to be used for password hashing.
49 * See the MessageDigest section in the <a href=
50 * "https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#MessageDigest">
51 * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
52 * for information about standard algorithm names.
53 * @param iterations the number of times the password hash function will be applied recursively
54 * @param saltSizeBytes the size of the salt to be used, in bytes
55 * @return a {@link JasyptPasswordEncryptor} instance.
56 */
57 public static JasyptPasswordEncryptor newInstance(String algorithm,
58 int iterations,
59 int saltSizeBytes) {
60 return new JasyptPasswordEncryptor(algorithm, iterations, saltSizeBytes);
61 }
62
63 private JasyptPasswordEncryptor(String algorithm, int iterations, int saltSizeBytes) {
64 this.algorithm = algorithm;
65 this.iterations = iterations;
66 this.saltSizeBytes = saltSizeBytes;
67 }
68
69 @Override
70 public String encryptPassword(final char[] plainPassword) {
71 if (plainPassword == null) {
72 return null;
73 }
74
75 final byte[] digest = digesterPool.getStandardByteDigester(algorithm, iterations, saltSizeBytes)
76 .digest(getCleanedBytes(plainPassword));
77
78 return passwordEncoderDecoder.encode(algorithm, iterations, saltSizeBytes, digest);
79 }
80
81 @Override
82 public boolean checkPassword(final char[] plainPassword,
83 final String storedPassword) {
84 if (plainPassword == null) {
85 return (storedPassword == null);
86 }
87 else if (storedPassword == null) {
88 return false;
89 }
90
91 final DecodedPassword decodedPassword = passwordEncoderDecoder.decode(storedPassword);
92 return digesterPool.getStandardByteDigester(decodedPassword.getAlgorithm(),
93 decodedPassword.getIterations(),
94 decodedPassword.getSaltSizeBytes())
95 .matches(getCleanedBytes(plainPassword), decodedPassword.getDigest());
96 }
97
98 private static byte[] getCleanedBytes(char[] password) {
99 final char[] normalizedChars = TextNormalizer.getInstance().normalizeToNfc(password);
100 final ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode(CharBuffer.wrap(normalizedChars));
101 final byte[] byteArray = new byte[byteBuffer.remaining()];
102 byteBuffer.get(byteArray);
103 Arrays.fill(byteBuffer.array(), (byte) 0);
104 return byteArray;
105 }
106 }