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 <digest>And<encryption> - 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_<size>;</pre>. 88 * {@link CryptoParametersJ8#CLEAR_CODE_DEFAULT} 89 * 90 * @return clear code J8AES_<size>; 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 }