1fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro/*
28b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
3fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro *
5fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * This code is free software; you can redistribute it and/or modify it
6fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * under the terms of the GNU General Public License version 2 only, as
7fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * published by the Free Software Foundation.  Oracle designates this
8fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * particular file as subject to the "Classpath" exception as provided
9fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * by Oracle in the LICENSE file that accompanied this code.
10fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro *
11fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * This code is distributed in the hope that it will be useful, but WITHOUT
12fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * version 2 for more details (a copy is included in the LICENSE file that
15fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * accompanied this code).
16fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro *
17fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * You should have received a copy of the GNU General Public License version
18fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * 2 along with this work; if not, write to the Free Software Foundation,
19fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro *
21fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * or visit www.oracle.com if you need additional information or have any
23fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * questions.
24fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro */
25fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
26fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giropackage sun.security.util;
27fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
28fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giroimport java.util.HashSet;
29fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giroimport java.util.Set;
30fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giroimport java.util.regex.Pattern;
31fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
32fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro/**
33fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro * The class decomposes standard algorithms into sub-elements.
34fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro */
35fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giropublic class AlgorithmDecomposer {
36fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
37fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro    private static final Pattern transPattern = Pattern.compile("/");
38fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro    private static final Pattern pattern =
39fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro                    Pattern.compile("with|and", Pattern.CASE_INSENSITIVE);
40fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
418b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak    private static Set<String> decomposeImpl(String algorithm) {
42fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
43fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        // algorithm/mode/padding
44fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        String[] transTockens = transPattern.split(algorithm);
45fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
46fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        Set<String> elements = new HashSet<>();
47fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        for (String transTocken : transTockens) {
48fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            if (transTocken == null || transTocken.length() == 0) {
49fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro                continue;
50fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            }
51fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
52fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            // PBEWith<digest>And<encryption>
53fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            // PBEWith<prf>And<encryption>
54fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            // OAEPWith<digest>And<mgf>Padding
55fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            // <digest>with<encryption>
56fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            // <digest>with<encryption>and<mgf>
57fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            String[] tokens = pattern.split(transTocken);
58fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
59fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            for (String token : tokens) {
60fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro                if (token == null || token.length() == 0) {
61fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro                    continue;
62fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro                }
63fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
64fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro                elements.add(token);
65fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            }
66fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        }
678b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        return elements;
688b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak    }
698b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak
708b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak    /**
718b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak     * Decompose the standard algorithm name into sub-elements.
728b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak     * <p>
738b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak     * For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA"
748b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak     * so that we can check the "SHA1" and "RSA" algorithm constraints
758b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak     * separately.
768b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak     * <p>
778b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak     * Please override the method if need to support more name pattern.
788b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak     */
798b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak    public Set<String> decompose(String algorithm) {
808b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        if (algorithm == null || algorithm.length() == 0) {
818b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak            return new HashSet<>();
828b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        }
838b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak
848b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        Set<String> elements = decomposeImpl(algorithm);
85fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
86fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        // In Java standard algorithm name specification, for different
87fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        // purpose, the SHA-1 and SHA-2 algorithm names are different. For
88fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        // example, for MessageDigest, the standard name is "SHA-256", while
89fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        // for Signature, the digest algorithm component is "SHA256" for
90fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        // signature algorithm "SHA256withRSA". So we need to check both
91fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        // "SHA-256" and "SHA256" to make the right constraint checking.
92fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
93fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        // handle special name: SHA-1 and SHA1
94fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        if (elements.contains("SHA1") && !elements.contains("SHA-1")) {
95fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            elements.add("SHA-1");
96fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        }
97fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        if (elements.contains("SHA-1") && !elements.contains("SHA1")) {
98fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            elements.add("SHA1");
99fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        }
100fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
101fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        // handle special name: SHA-224 and SHA224
102fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        if (elements.contains("SHA224") && !elements.contains("SHA-224")) {
103fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            elements.add("SHA-224");
104fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        }
105fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        if (elements.contains("SHA-224") && !elements.contains("SHA224")) {
106fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            elements.add("SHA224");
107fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        }
108fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
109fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        // handle special name: SHA-256 and SHA256
110fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        if (elements.contains("SHA256") && !elements.contains("SHA-256")) {
111fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            elements.add("SHA-256");
112fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        }
113fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        if (elements.contains("SHA-256") && !elements.contains("SHA256")) {
114fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            elements.add("SHA256");
115fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        }
116fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
117fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        // handle special name: SHA-384 and SHA384
118fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        if (elements.contains("SHA384") && !elements.contains("SHA-384")) {
119fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            elements.add("SHA-384");
120fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        }
121fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        if (elements.contains("SHA-384") && !elements.contains("SHA384")) {
122fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            elements.add("SHA384");
123fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        }
124fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
125fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        // handle special name: SHA-512 and SHA512
126fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        if (elements.contains("SHA512") && !elements.contains("SHA-512")) {
127fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            elements.add("SHA-512");
128fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        }
129fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        if (elements.contains("SHA-512") && !elements.contains("SHA512")) {
130fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro            elements.add("SHA512");
131fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        }
132fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
133fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro        return elements;
134fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro    }
135fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro
1368b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak    private static void hasLoop(Set<String> elements, String find, String replace) {
1378b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        if (elements.contains(find)) {
1388b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak            if (!elements.contains(replace)) {
1398b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak                elements.add(replace);
1408b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak}
1418b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak            elements.remove(find);
1428b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        }
1438b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak    }
1448b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak
1458b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak    /*
1468b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak     * This decomposes a standard name into sub-elements with a consistent
1478b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak     * message digest algorithm name to avoid overly complicated checking.
1488b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak     */
1498b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak    public static Set<String> decomposeOneHash(String algorithm) {
1508b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        if (algorithm == null || algorithm.length() == 0) {
1518b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak            return new HashSet<>();
1528b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        }
1538b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak
1548b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        Set<String> elements = decomposeImpl(algorithm);
1558b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak
1568b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        hasLoop(elements, "SHA-1", "SHA1");
1578b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        hasLoop(elements, "SHA-224", "SHA224");
1588b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        hasLoop(elements, "SHA-256", "SHA256");
1598b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        hasLoop(elements, "SHA-384", "SHA384");
1608b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        hasLoop(elements, "SHA-512", "SHA512");
1618b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak
1628b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        return elements;
1638b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak    }
1648b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak
1658b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak    /*
1668b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak     * The provided message digest algorithm name will return a consistent
1678b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak     * naming scheme.
1688b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak     */
1698b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak    public static String hashName(String algorithm) {
1708b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak        return algorithm.replace("-", "");
1718b5ba217ca0e811a8e8602666b10f3b3e0bcc62cPrzemyslaw Szczepaniak    }
172fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro}
173