1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.wss4j.common.util;
21
22 import java.io.IOException;
23 import java.nio.charset.StandardCharsets;
24 import java.security.MessageDigest;
25 import java.security.NoSuchAlgorithmException;
26
27 import javax.security.auth.callback.Callback;
28 import javax.security.auth.callback.CallbackHandler;
29 import javax.security.auth.callback.UnsupportedCallbackException;
30
31 import org.apache.wss4j.common.ext.WSPasswordCallback;
32 import org.apache.wss4j.common.ext.WSSecurityException;
33 import org.apache.xml.security.stax.ext.XMLSecurityConstants;
34
35 public final class UsernameTokenUtil {
36 public static final int DEFAULT_ITERATION = 1000;
37
38 private static final org.slf4j.Logger LOG =
39 org.slf4j.LoggerFactory.getLogger(UsernameTokenUtil.class);
40
41 private UsernameTokenUtil() {
42
43 }
44
45
46
47
48
49
50
51
52
53
54
55
56 public static byte[] generateDerivedKey(
57 byte[] password,
58 byte[] salt,
59 int iteration
60 ) throws WSSecurityException {
61 byte[] pwSalt = new byte[salt.length + password.length];
62 System.arraycopy(password, 0, pwSalt, 0, password.length);
63 System.arraycopy(salt, 0, pwSalt, password.length, salt.length);
64
65 MessageDigest sha = null;
66 try {
67 sha = MessageDigest.getInstance("SHA1");
68 } catch (NoSuchAlgorithmException e) {
69 LOG.debug(e.getMessage(), e);
70 throw new WSSecurityException(
71 WSSecurityException.ErrorCode.FAILURE, e, "decoding.general"
72 );
73 }
74
75
76
77 byte[] k = sha.digest(pwSalt);
78
79
80
81 int iter = iteration;
82 if (iter <= 0) {
83 iter = DEFAULT_ITERATION;
84 }
85 for (int i = 1; i < iter; i++) {
86 k = sha.digest(k);
87 }
88 return k;
89 }
90
91
92
93
94
95
96
97
98
99
100
101
102 public static byte[] generateDerivedKey(
103 String password,
104 byte[] salt,
105 int iteration
106 ) throws WSSecurityException {
107 return generateDerivedKey(password.getBytes(StandardCharsets.UTF_8), salt, iteration);
108 }
109
110
111
112
113
114
115
116
117 public static byte[] generateSalt(boolean useForMac) {
118 byte[] saltValue = null;
119 try {
120 saltValue = generateNonce(16);
121 } catch (WSSecurityException ex) {
122 LOG.debug(ex.getMessage(), ex);
123 return new byte[0];
124 }
125 if (useForMac) {
126 saltValue[0] = 0x01;
127 } else {
128 saltValue[0] = 0x02;
129 }
130 return saltValue;
131 }
132
133
134
135
136
137
138
139
140 public static byte[] generateNonce(int length) throws WSSecurityException {
141 try {
142 return XMLSecurityConstants.generateBytes(length);
143 } catch (Exception ex) {
144 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex,
145 "empty", new Object[] {"Error in generating nonce of length " + length}
146 );
147 }
148 }
149
150 public static String doPasswordDigest(byte[] nonce, String created, String password) throws WSSecurityException {
151 return doPasswordDigest(nonce, created, password.getBytes(StandardCharsets.UTF_8));
152 }
153
154 public static String doPasswordDigest(byte[] nonce, String created, byte[] password) throws WSSecurityException {
155 byte[] digestBytes = doRawPasswordDigest(nonce, created, password);
156 return org.apache.xml.security.utils.XMLUtils.encodeToString(digestBytes);
157 }
158
159 public static byte[] doRawPasswordDigest(byte[] nonce, String created, byte[] password) throws WSSecurityException {
160 try {
161 byte[] b1 = nonce != null ? nonce : new byte[0];
162 byte[] b2 = created != null ? created.getBytes(StandardCharsets.UTF_8) : new byte[0];
163 byte[] b3 = password;
164 byte[] b4 = new byte[b1.length + b2.length + b3.length];
165 int offset = 0;
166 System.arraycopy(b1, 0, b4, offset, b1.length);
167 offset += b1.length;
168
169 System.arraycopy(b2, 0, b4, offset, b2.length);
170 offset += b2.length;
171
172 System.arraycopy(b3, 0, b4, offset, b3.length);
173
174 return KeyUtils.generateDigest(b4);
175 } catch (Exception e) {
176 LOG.debug(e.getMessage(), e);
177 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e, "decoding.general");
178 }
179 }
180
181
182
183
184 public static String getRawPassword(CallbackHandler callbackHandler, String username,
185 String password, String passwordType) throws WSSecurityException {
186 if (callbackHandler == null) {
187 LOG.debug("CallbackHandler is null");
188 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
189 }
190
191 WSPasswordCallback pwCb =
192 new WSPasswordCallback(
193 username, password, passwordType, WSPasswordCallback.USERNAME_TOKEN
194 );
195 try {
196 callbackHandler.handle(new Callback[]{pwCb});
197 } catch (IOException | UnsupportedCallbackException e) {
198 LOG.debug(e.getMessage(), e);
199 throw new WSSecurityException(
200 WSSecurityException.ErrorCode.FAILED_AUTHENTICATION, e
201 );
202 }
203 return pwCb.getPassword();
204 }
205 }