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 org.apache.wss4j.common.ext.WSSecurityException;
23 import org.apache.xml.security.algorithms.JCEMapper;
24 import org.apache.xml.security.encryption.XMLCipher;
25 import org.apache.xml.security.signature.XMLSignature;
26 import org.apache.xml.security.utils.JavaUtils;
27
28 import javax.crypto.Cipher;
29 import javax.crypto.KeyGenerator;
30 import javax.crypto.NoSuchPaddingException;
31 import javax.crypto.SecretKey;
32 import javax.crypto.spec.SecretKeySpec;
33 import java.security.MessageDigest;
34 import java.security.NoSuchAlgorithmException;
35 import java.security.NoSuchProviderException;
36 import java.util.HashMap;
37 import java.util.Map;
38
39 public final class KeyUtils {
40 private static final org.slf4j.Logger LOG =
41 org.slf4j.LoggerFactory.getLogger(KeyUtils.class);
42 private static final int MAX_SYMMETRIC_KEY_SIZE = 1024;
43 private static final Map<String, Integer> DEFAULT_DERIVED_KEY_LENGTHS = new HashMap<>();
44
45 public static final String RSA_ECB_OAEPWITH_SHA1_AND_MGF1_PADDING = "RSA/ECB/OAEPWithSHA1AndMGF1Padding";
46
47
48
49
50 private static MessageDigest digest;
51
52 static {
53 DEFAULT_DERIVED_KEY_LENGTHS.put(XMLSignature.ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5, 128);
54 DEFAULT_DERIVED_KEY_LENGTHS.put(XMLSignature.ALGO_ID_MAC_HMAC_RIPEMD160, 160);
55 DEFAULT_DERIVED_KEY_LENGTHS.put(XMLSignature.ALGO_ID_MAC_HMAC_SHA1, 160);
56 DEFAULT_DERIVED_KEY_LENGTHS.put(XMLSignature.ALGO_ID_MAC_HMAC_SHA224, 224);
57 DEFAULT_DERIVED_KEY_LENGTHS.put(XMLSignature.ALGO_ID_MAC_HMAC_SHA256, 256);
58 DEFAULT_DERIVED_KEY_LENGTHS.put(XMLSignature.ALGO_ID_MAC_HMAC_SHA384, 384);
59 DEFAULT_DERIVED_KEY_LENGTHS.put(XMLSignature.ALGO_ID_MAC_HMAC_SHA512, 512);
60 }
61
62 private KeyUtils() {
63
64 }
65
66
67
68
69
70
71
72
73 public static int getKeyLength(String algorithm) throws WSSecurityException {
74 if (algorithm == null) {
75 return 0;
76 }
77
78 int size = JCEMapper.getKeyLengthFromURI(algorithm);
79 if (size == 0 && DEFAULT_DERIVED_KEY_LENGTHS.containsKey(algorithm)) {
80
81 size = DEFAULT_DERIVED_KEY_LENGTHS.get(algorithm);
82 }
83
84 return size / 8;
85 }
86
87
88
89
90 public static SecretKey prepareSecretKey(String algorithm, byte[] rawKey) {
91
92 int size = 0;
93 try {
94 size = JCEMapper.getKeyLengthFromURI(algorithm) / 8;
95 } catch (Exception e) {
96
97 LOG.debug(e.getMessage());
98 }
99 String keyAlgorithm = JCEMapper.getJCEKeyAlgorithmFromURI(algorithm);
100 SecretKeySpec keySpec;
101 if (size > 0 && !algorithm.endsWith("gcm") && !algorithm.contains("hmac-")) {
102 keySpec =
103 new SecretKeySpec(
104 rawKey, 0, rawKey.length > size ? size : rawKey.length, keyAlgorithm
105 );
106 } else if (rawKey.length > MAX_SYMMETRIC_KEY_SIZE) {
107
108 keySpec =
109 new SecretKeySpec(
110 rawKey, 0, MAX_SYMMETRIC_KEY_SIZE, keyAlgorithm
111 );
112 } else {
113 keySpec = new SecretKeySpec(rawKey, keyAlgorithm);
114 }
115 return keySpec;
116 }
117
118 public static KeyGenerator getKeyGenerator(String algorithm) throws WSSecurityException {
119 try {
120
121
122
123 String keyAlgorithm = JCEMapper.getJCEKeyAlgorithmFromURI(algorithm);
124 if (keyAlgorithm == null || keyAlgorithm.length() == 0) {
125 keyAlgorithm = JCEMapper.translateURItoJCEID(algorithm);
126 }
127 KeyGenerator keyGen = KeyGenerator.getInstance(keyAlgorithm);
128 if (algorithm.equalsIgnoreCase(XMLCipher.AES_128)
129 || algorithm.equalsIgnoreCase(XMLCipher.AES_128_GCM)) {
130 keyGen.init(128);
131 } else if (algorithm.equalsIgnoreCase(XMLCipher.AES_192)
132 || algorithm.equalsIgnoreCase(XMLCipher.AES_192_GCM)) {
133 keyGen.init(192);
134 } else if (algorithm.equalsIgnoreCase(XMLCipher.AES_256)
135 || algorithm.equalsIgnoreCase(XMLCipher.AES_256_GCM)) {
136 keyGen.init(256);
137 }
138 return keyGen;
139 } catch (NoSuchAlgorithmException e) {
140 throw new WSSecurityException(
141 WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, e
142 );
143 }
144 }
145
146
147
148
149
150
151
152 public static Cipher getCipherInstance(String cipherAlgo)
153 throws WSSecurityException {
154 return getCipherInstance(cipherAlgo, null);
155 }
156
157
158
159
160
161
162
163
164 public static Cipher getCipherInstance(String cipherAlgo, String provider)
165 throws WSSecurityException {
166 String keyAlgorithm = JCEMapper.translateURItoJCEID(cipherAlgo);
167 if (keyAlgorithm == null) {
168 throw new WSSecurityException(
169 WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, "unsupportedKeyTransp",
170 new Object[]{"No such algorithm: \"" + cipherAlgo + "\""});
171 }
172
173 if (provider == null) {
174 provider = JCEMapper.getProviderId();
175 } else {
176 JavaUtils.checkRegisterPermission();
177 }
178
179 try {
180 if (provider == null) {
181 return Cipher.getInstance(keyAlgorithm);
182 } else {
183 return Cipher.getInstance(keyAlgorithm, provider);
184 }
185 } catch (NoSuchPaddingException | NoSuchAlgorithmException e) {
186 if (XMLCipher.RSA_OAEP.equals(cipherAlgo)) {
187
188
189 try {
190 if (provider == null) {
191 return Cipher.getInstance(RSA_ECB_OAEPWITH_SHA1_AND_MGF1_PADDING);
192 } else {
193 return Cipher.getInstance(RSA_ECB_OAEPWITH_SHA1_AND_MGF1_PADDING, provider);
194 }
195 } catch (NoSuchProviderException ex1) {
196 throw new WSSecurityException(
197 WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, ex1, "unsupportedKeyTransp",
198 new Object[]{
199 "No such provider \"" + JCEMapper.getProviderId() + "\" for \""
200 + RSA_ECB_OAEPWITH_SHA1_AND_MGF1_PADDING + "\""
201 });
202 } catch (NoSuchPaddingException ex1) {
203 throw new WSSecurityException(
204 WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, e, "unsupportedKeyTransp",
205 new Object[]{"No such padding: \"" + RSA_ECB_OAEPWITH_SHA1_AND_MGF1_PADDING + "\""});
206 } catch (NoSuchAlgorithmException ex1) {
207 throw new WSSecurityException(
208 WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, e, "unsupportedKeyTransp",
209 new Object[]{"No such algorithm: \"" + RSA_ECB_OAEPWITH_SHA1_AND_MGF1_PADDING + "\""});
210 }
211 } else {
212 if (e instanceof NoSuchAlgorithmException) {
213 throw new WSSecurityException(
214 WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, e, "unsupportedKeyTransp",
215 new Object[]{"No such algorithm: \"" + keyAlgorithm + "\""});
216 } else {
217 throw new WSSecurityException(
218 WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, e, "unsupportedKeyTransp",
219 new Object[]{"No such padding: \"" + keyAlgorithm + "\""});
220 }
221 }
222 } catch (NoSuchProviderException ex) {
223 throw new WSSecurityException(
224 WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, ex, "unsupportedKeyTransp",
225 new Object[]{"No such provider \"" + JCEMapper.getProviderId() + "\" for \"" + keyAlgorithm + "\""});
226 }
227 }
228
229
230
231
232
233
234
235
236 public static synchronized byte[] generateDigest(byte[] inputBytes) throws WSSecurityException {
237 try {
238 if (digest == null) {
239 digest = MessageDigest.getInstance("SHA-1");
240 }
241 return digest.digest(inputBytes);
242 } catch (Exception e) {
243 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e, "empty",
244 new Object[] {"Error in generating digest"}
245 );
246 }
247 }
248 }