View Javadoc
1   package org.apache.fulcrum.jce.crypto.extended;
2   
3   import java.security.Provider;
4   import java.security.Security;
5   import java.util.ArrayList;
6   import java.util.Arrays;
7   import java.util.Collections;
8   import java.util.LinkedHashSet;
9   import java.util.List;
10  import java.util.Set;
11  import java.util.stream.Collectors;
12  
13  /*
14   * Licensed to the Apache Software Foundation (ASF) under one
15   * or more contributor license agreements.  See the NOTICE file
16   * distributed with this work for additional information
17   * regarding copyright ownership.  The ASF licenses this file
18   * to you under the Apache License, Version 2.0 (the
19   * "License"); you may not use this file except in compliance
20   * with the License.  You may obtain a copy of the License at
21   *
22   *   http://www.apache.org/licenses/LICENSE-2.0
23   *
24   * Unless required by applicable law or agreed to in writing,
25   * software distributed under the License is distributed on an
26   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
27   * KIND, either express or implied.  See the License for the
28   * specific language governing permissions and limitations
29   * under the License.
30   */
31  
32  /**
33   * CryptoParameters used for encryption/decryption.
34   *
35   * @author <a href="mailto:gk@apache.org">Georg Kallidis</a>
36   */
37  
38  public interface CryptoParametersJ8 {
39  	
40  	/**
41  	 * 
42  	 * Implementing classes are either using
43  	 * 
44  	 * <ul>
45  	 * <li>PBEWith &lt;digest&gt;And&lt;encryption&gt; - the password-based encryption algorithm defined in PKCS #5: PBEWithHmacSHA256AndAES_256/CBC/PKCS5Padding in {@link #ALGORITHM_J8_PBE}</li>
46  	 * </ul>
47  	 * 
48  	 * or
49  	 * 
50  	 * <ul>
51  	 * <li>AES/GCM/NoPadding in {@link #ALGORITHM_J8_GCM} (Cipher Algorithm Names/Cipher Algorithm Modes/Cipher Algorithm Padding). Cipher is Galois/Counter Mode, as defined in NIST Special Publication SP 800-38D: </li>
52  	 * </ul>
53  	 * 
54  	 * 
55  	 * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html#SunJCEProvider">The Oracle Security SunJCE Provider</a>
56  	 * 
57  	 * Algo/mode/padding for cipher transformation:
58  	 * 
59  	 * Java 8: <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">The Oracle Security Standard Names Cipher Algorithms</a>
60  	 * 
61  	 * Java 14: <a href="https://docs.oracle.com/en/java/javase/14/docs/specs/security/standard-names.html#security-algorithm-implementation-requirements">Security Algorithm Implementation Requirements</a>
62  	 * 
63  	 */
64  	public enum TYPES_IMPL {
65  		
66  		// key size 256
67  		ALGORITHM_J8_PBE("PBEWithHmacSHA256AndAES_256"), 
68  		// key size 128
69  		ALGORITHM_J8_GCM("AES_128/GCM/NoPadding");
70  
71  		private final String algorithm;
72  
73  		private TYPES_IMPL(String algo) {
74  			algorithm = algo;
75  		}
76  
77  		@Override
78  		public String toString() {
79  			return this.algorithm;
80  		}
81  
82  		public String getAlgorithm() {
83  			return algorithm;
84  		}
85  		
86  		/**
87  		 * clear code depending on algorithm AES size return <pre>J8AESAES_&lt;size&gt;;</pre>.
88  		 * {@link CryptoParametersJ8#CLEAR_CODE_DEFAULT}
89  		 *  
90  		 * @return clear code J8AES_&lt;size&gt;; with three digit size.
91  		 */
92  		public String getClearCode() {
93  			
94  			return String.format("J8%1$s;", 
95  					algorithm.subSequence(algorithm.indexOf("AES_"),algorithm.indexOf("AES_")+7));
96  		}
97  	}
98  
99  	/**
100 	 * 
101 	 * short names, exact names @see {@link TYPES_IMPL}.
102 	 *
103 	 */
104 	public enum TYPES {
105 		
106 		/**
107 		 *  PBE algorithm is kind of meta algorithm, uses AES, see above. 
108 		 */
109 		PBE, 
110 		/**
111 		 *  AES algorithm, but GCM is is actually the algorithm mode, but nevertheless used as a short name.
112 		 */
113 		GCM;
114 
115 		/**
116 		 * Clear code should be always 10 bytes.
117 		 * 
118 		 * {@link CryptoParametersJ8#CLEAR_CODE_DEFAULT}
119 		 * 
120 		 * @return clear code
121 		 * 
122 		 */
123 		public String getClearCode() {
124 			return this.equals(TYPES.PBE)? 
125 					TYPES_IMPL.ALGORITHM_J8_PBE.getClearCode():
126 				TYPES_IMPL.ALGORITHM_J8_GCM.getClearCode();
127 		}
128 	}
129 
130 	/**
131 	 * Prefix to decrypted hex hash to get a clue, what to use and what it is; should be always 10 bytes.
132 	 */
133 	public String CLEAR_CODE_DEFAULT = "J8_AES064;";
134 	
135 	public TYPES DEFAULT_TYPE = TYPES.PBE;
136 
137 	
138 	/**
139 	 * Checks Java provider with <b>type</b> has exact type or contains any of the strings in algoList.
140 	 * <pre>Types</pre> may be Cipher, AlgorithmParameters, KeyGenerator, Alg, Mac, SecretKeyFactory.
141 	 * 
142 	 * @param algoList the types to be checked
143 	 * @param type the type is ignored if not exact, instead uses the two types: "AlgorithmParameters", "Cipher".
144 	 * @param exact if exact does a exact match 
145 	 * @return the matched results as a list or emtpy list
146 	 */
147 	public static List<String> getSupportedAlgos(List<String> algoList, String type, boolean exact) {
148 		List<String> result = new ArrayList<String>();
149 		Provider p[] = Security.getProviders();
150 		List<Provider> providerList = Arrays.asList(p);
151 
152 		for (Provider provider : providerList) {
153 			//System.out.println(provider);
154 			result.addAll(Collections.list(provider.keys()).stream().map(t -> t.toString())
155 					.filter(x->
156 							(exact)? 
157 							(x.startsWith(type) && algoList.contains(x.replaceAll(type + ".", ""))):
158 							(x.matches("(" +String.join("|", PROVIDER_TYPES) + ").*$") && 
159 									algoList.stream().anyMatch(y -> y.contains(x.replaceAll(type + ".", "")))
160 							)
161 					)
162 					.map( x ->
163 					(exact)? 
164 					   x.replaceAll(type + ".", ""):
165 						   x.replaceAll("(" +String.join("|", PROVIDER_TYPES) + ")" + ".", "")
166 					)
167 					.collect(Collectors.toList()));
168 		}
169 		return result;
170 	}
171 	
172 	public static List[] LISTS = {  Arrays.stream(CryptoParametersJ8.TYPES.values()).map(t -> t.toString())
173 			.collect(Collectors.toList()), 
174 					Arrays.stream(CryptoParametersJ8.TYPES_IMPL.values()).map(t -> t.toString())
175 					.collect(Collectors.toList()) };
176 	
177 	public static String[] PROVIDER_TYPES = { "AlgorithmParameters", "Cipher" };
178 
179 	/**
180 	 * initializes supported parameters by filtering {@link TYPES} against <i>AlgorithmParameters</i> in system supported cipher suites:
181 	 * first by an exact match with type <i>AlgorithmParameters</i>, then by inexact matching.
182 	 * 
183 	 * {@link #getSupportedAlgos(List, String, boolean)}
184 	 * @return list of supported algo short codes, if nothing is found, the list is empty.
185 	 */
186 	static List<String> init() {
187 		List<String> result = new ArrayList<String>();
188 		List<String> defaultSupportedTypes = LISTS[0];
189 		String providerType = PROVIDER_TYPES[0];
190 		result = getSupportedAlgos(defaultSupportedTypes, providerType, true);
191 		// no duplicates
192 		Set<String> resultSet = new LinkedHashSet<String>(result);
193 		resultSet.addAll( getSupportedAlgos(defaultSupportedTypes, providerType, false));
194 
195 		List<String> algoList = LISTS[1];
196 		String type = PROVIDER_TYPES[1];
197 		List<String> result3 = CryptoParametersJ8.getSupportedAlgos(algoList, type, true);
198 		defaultSupportedTypes.stream().forEach(c-> {
199 			if (result3.stream().anyMatch(x -> x.contains(c))) {
200 				//System.out.println("adding " + c);
201 				resultSet.add(c);
202 			}
203 		});
204 		return new ArrayList<>(resultSet);
205 	}
206 
207 }