1fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro/*
2874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw 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
41874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw 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        }
67874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak        return elements;
68874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak    }
69874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak
70874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak    /**
71874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak     * Decompose the standard algorithm name into sub-elements.
72874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak     * <p>
73874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak     * For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA"
74874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak     * so that we can check the "SHA1" and "RSA" algorithm constraints
75874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak     * separately.
76874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak     * <p>
77874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak     * Please override the method if need to support more name pattern.
78874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak     */
79874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak    public Set<String> decompose(String algorithm) {
80874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak        if (algorithm == null || algorithm.length() == 0) {
81874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak            return new HashSet<>();
82874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak        }
83874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak
84874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw 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
136874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak    private static void hasLoop(Set<String> elements, String find, String replace) {
137874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak        if (elements.contains(find)) {
138874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak            if (!elements.contains(replace)) {
139874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak                elements.add(replace);
140874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak}
141874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak            elements.remove(find);
142874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak        }
143874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak    }
144874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak
145874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak    /*
146874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak     * This decomposes a standard name into sub-elements with a consistent
147874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak     * message digest algorithm name to avoid overly complicated checking.
148874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak     */
149874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak    public static Set<String> decomposeOneHash(String algorithm) {
150874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak        if (algorithm == null || algorithm.length() == 0) {
151874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak            return new HashSet<>();
152874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak        }
153874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak
154874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak        Set<String> elements = decomposeImpl(algorithm);
155874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak
156874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak        hasLoop(elements, "SHA-1", "SHA1");
157874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak        hasLoop(elements, "SHA-224", "SHA224");
158874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak        hasLoop(elements, "SHA-256", "SHA256");
159874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak        hasLoop(elements, "SHA-384", "SHA384");
160874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak        hasLoop(elements, "SHA-512", "SHA512");
161874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak
162874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak        return elements;
163874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak    }
164874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak
165874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak    /*
166874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak     * The provided message digest algorithm name will return a consistent
167874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak     * naming scheme.
168874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak     */
169874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak    public static String hashName(String algorithm) {
170874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak        return algorithm.replace("-", "");
171874c25b3bc5831e286885d08a60cf0f4c75d36dcPrzemyslaw Szczepaniak    }
172fb4c7d4fd77a0e37a3414b7199e0020c19acc5e5Sergio Giro}
173