Path: blob/master/src/java.base/share/classes/sun/security/util/AlgorithmDecomposer.java
41159 views
/*1* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.util;2627import java.util.HashSet;28import java.util.Set;29import java.util.Arrays;30import java.util.Collection;31import java.util.regex.Pattern;3233/**34* The class decomposes standard algorithms into sub-elements.35*/36public class AlgorithmDecomposer {3738// '(?<!padd)in': match 'in' but not preceded with 'padd'.39private static final Pattern PATTERN =40Pattern.compile("with|and|(?<!padd)in", Pattern.CASE_INSENSITIVE);4142private static Set<String> decomposeImpl(String algorithm) {43Set<String> elements = new HashSet<>();4445// algorithm/mode/padding46String[] transTokens = algorithm.split("/");4748for (String transToken : transTokens) {49if (transToken == null || transToken.isEmpty()) {50continue;51}5253// PBEWith<digest>And<encryption>54// PBEWith<prf>And<encryption>55// OAEPWith<digest>And<mgf>Padding56// <digest>with<encryption>57// <digest>with<encryption>and<mgf>58// <digest>with<encryption>in<format>59String[] tokens = PATTERN.split(transToken);6061for (String token : tokens) {62if (token == null || token.isEmpty()) {63continue;64}6566elements.add(token);67}68}69return elements;70}7172/**73* Decompose the standard algorithm name into sub-elements.74* <p>75* For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA"76* so that we can check the "SHA1" and "RSA" algorithm constraints77* separately.78* <p>79* Please override the method if need to support more name pattern.80*/81public Set<String> decompose(String algorithm) {82if (algorithm == null || algorithm.isEmpty()) {83return new HashSet<>();84}8586Set<String> elements = decomposeImpl(algorithm);8788// In Java standard algorithm name specification, for different89// purpose, the SHA-1 and SHA-2 algorithm names are different. For90// example, for MessageDigest, the standard name is "SHA-256", while91// for Signature, the digest algorithm component is "SHA256" for92// signature algorithm "SHA256withRSA". So we need to check both93// "SHA-256" and "SHA256" to make the right constraint checking.9495// handle special name: SHA-1 and SHA196if (elements.contains("SHA1") && !elements.contains("SHA-1")) {97elements.add("SHA-1");98}99if (elements.contains("SHA-1") && !elements.contains("SHA1")) {100elements.add("SHA1");101}102103// handle special name: SHA-224 and SHA224104if (elements.contains("SHA224") && !elements.contains("SHA-224")) {105elements.add("SHA-224");106}107if (elements.contains("SHA-224") && !elements.contains("SHA224")) {108elements.add("SHA224");109}110111// handle special name: SHA-256 and SHA256112if (elements.contains("SHA256") && !elements.contains("SHA-256")) {113elements.add("SHA-256");114}115if (elements.contains("SHA-256") && !elements.contains("SHA256")) {116elements.add("SHA256");117}118119// handle special name: SHA-384 and SHA384120if (elements.contains("SHA384") && !elements.contains("SHA-384")) {121elements.add("SHA-384");122}123if (elements.contains("SHA-384") && !elements.contains("SHA384")) {124elements.add("SHA384");125}126127// handle special name: SHA-512 and SHA512128if (elements.contains("SHA512") && !elements.contains("SHA-512")) {129elements.add("SHA-512");130}131if (elements.contains("SHA-512") && !elements.contains("SHA512")) {132elements.add("SHA512");133}134135return elements;136}137138/**139* Get aliases of the specified algorithm.140*141* May support more algorithms in the future.142*/143public static Collection<String> getAliases(String algorithm) {144String[] aliases;145if (algorithm.equalsIgnoreCase("DH") ||146algorithm.equalsIgnoreCase("DiffieHellman")) {147aliases = new String[] {"DH", "DiffieHellman"};148} else {149aliases = new String[] {algorithm};150}151152return Arrays.asList(aliases);153}154155private static void hasLoop(Set<String> elements, String find, String replace) {156if (elements.contains(find)) {157if (!elements.contains(replace)) {158elements.add(replace);159}160elements.remove(find);161}162}163164/*165* This decomposes a standard name into sub-elements with a consistent166* message digest algorithm name to avoid overly complicated checking.167*/168public static Set<String> decomposeOneHash(String algorithm) {169if (algorithm == null || algorithm.isEmpty()) {170return new HashSet<>();171}172173Set<String> elements = decomposeImpl(algorithm);174175hasLoop(elements, "SHA-1", "SHA1");176hasLoop(elements, "SHA-224", "SHA224");177hasLoop(elements, "SHA-256", "SHA256");178hasLoop(elements, "SHA-384", "SHA384");179hasLoop(elements, "SHA-512", "SHA512");180181return elements;182}183184/*185* The provided message digest algorithm name will return a consistent186* naming scheme.187*/188public static String hashName(String algorithm) {189return algorithm.replace("-", "");190}191}192193194