content: /*
   *  Licensed to the Apache Software Foundation (ASF) under one or more
   *  contributor license agreements.  See the NOTICE file distributed with
   *  this work for additional information regarding copyright ownership.
   *  The ASF licenses this file to You under the Apache License, Version 2.0
   *  (the "License"); you may not use this file except in compliance with
   *  the License.  You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   */
  
  /**
  * @author Vladimir N. Molotkov
  * @version $Revision$
  */
  
  package android.framework.org.apache.harmony.security_custom.utils;
  
  import java.security.Provider;
  import java.security.Security;
  import java.util.HashMap;
  import java.util.Locale;
  import java.util.Map;
  import java.util.Map.Entry;
  import java.util.Set;
  import android.framework.org.apache.harmony.security_custom.asn1.ObjectIdentifier;
  
  /**
   * Provides Algorithm Name to OID and OID to Algorithm Name mappings. Some known
   * mappings are hardcoded. Tries to obtain additional mappings from installed
   * providers during initialization.
   */
  public class AlgNameMapper {
  
      // Will search OID mappings for these services
      private static final String[] serviceName = {
              "Cipher",
              "AlgorithmParameters",
              "Signature"
      };
  
      // These mappings CAN NOT be overridden
      // by the ones from available providers
      // during maps initialization
      // (source: http://asn1.elibel.tm.fr):
      private static final String[][] knownAlgMappings = {
          {"1.2.840.10040.4.1",       "DSA"},
          {"1.2.840.10040.4.3",       "SHA1withDSA"},
          {"1.2.840.113549.1.1.1",    "RSA"},
          // BEGIN android-removed
          // Dropping MD2
          // {"1.2.840.113549.1.1.2",    "MD2withRSA"},
          // END android-removed
          {"1.2.840.113549.1.1.4",    "MD5withRSA"},
          {"1.2.840.113549.1.1.5",    "SHA1withRSA"},
          {"1.2.840.113549.1.3.1",    "DiffieHellman"},
          {"1.2.840.113549.1.5.3",    "pbeWithMD5AndDES-CBC"},
          {"1.2.840.113549.1.12.1.3", "pbeWithSHAAnd3-KeyTripleDES-CBC"},
          {"1.2.840.113549.1.12.1.6", "pbeWithSHAAnd40BitRC2-CBC"},
          {"1.2.840.113549.3.2",      "RC2-CBC"},
          {"1.2.840.113549.3.3",      "RC2-EBC"},
          {"1.2.840.113549.3.4",      "RC4"},
          {"1.2.840.113549.3.5",      "RC4WithMAC"},
          {"1.2.840.113549.3.6",      "DESx-CBC"},
          {"1.2.840.113549.3.7",      "TripleDES-CBC"},
          {"1.2.840.113549.3.8",      "rc5CBC"},
          {"1.2.840.113549.3.9",      "RC5-CBC"},
          {"1.2.840.113549.3.10",     "DESCDMF"},
          {"2.23.42.9.11.4.1",        "ECDSA"},
      };
      // Maps alg name to OID
      private static final Map<String, String> alg2OidMap = new HashMap<String, String>();
      // Maps OID to alg name
      private static final Map<String, String> oid2AlgMap = new HashMap<String, String>();
      // Maps aliases to alg names
      private static final Map<String, String> algAliasesMap = new HashMap<String, String>();
  
      static {
          for (String[] element : knownAlgMappings) {
              String algUC = element[1].toUpperCase(Locale.US);
              alg2OidMap.put(algUC, element[0]);
              oid2AlgMap.put(element[0], algUC);
              // map upper case alg name to its original name
              algAliasesMap.put(algUC, element[1]);
          }
          //
          // Now search providers for mappings like
          // Alg.Alias.<service>.<OID-INTS-DOT-SEPARATED>=<alg-name>
          //  or
          // Alg.Alias.<service>.OID.<OID-INTS-DOT-SEPARATED>=<alg-name>
          //
          Provider[] pl = Security.getProviders();
          for (Provider element : pl) {
              selectEntries(element);
          }
      }
  
      // No instances
      private AlgNameMapper() {
      }
  
      /**
       * Returns OID for algName
       *
       * @param algName algorithm name to be mapped
       * @return OID as String
       */
      public static String map2OID(String algName) {
          // alg2OidMap map contains upper case keys
          return alg2OidMap.get(algName.toUpperCase(Locale.US));
      }
  
      /**
       * Returns algName for OID
       *
       * @param oid OID to be mapped
       * @return algorithm name
       */
      public static String map2AlgName(String oid) {
          // oid2AlgMap map contains upper case values
          String algUC = oid2AlgMap.get(oid);
          // if not null there is always map UC->Orig
          return algUC == null ? null : algAliasesMap.get(algUC);
      }
  
      /**
       * Returns Algorithm name for given algorithm alias
       *
       * @param algName - alias
       * @return algorithm name
       */
      public static String getStandardName(String algName) {
          return algAliasesMap.get(algName.toUpperCase(Locale.US));
      }
  
      // Searches given provider for mappings like
      // Alg.Alias.<service>.<OID-INTS-DOT-SEPARATED>=<alg-name>
      //  or
      // Alg.Alias.<service>.OID.<OID-INTS-DOT-SEPARATED>=<alg-name>
      // Puts mappings found into appropriate internal maps
      private static void selectEntries(Provider p) {
          Set<Map.Entry<Object, Object>> entrySet = p.entrySet();
          for (String service : serviceName) {
              String keyPrfix2find = "Alg.Alias." + service + ".";
              for (Entry<Object, Object> me : entrySet) {
                  String key = (String)me.getKey();
                  if (key.startsWith(keyPrfix2find)) {
                      String alias = key.substring(keyPrfix2find.length());
                      String alg = (String)me.getValue();
                      String algUC = alg.toUpperCase(Locale.US);
                      if (isOID(alias)) {
                          if (alias.startsWith("OID.")) {
                              alias = alias.substring(4);
                          }
                          // Do not overwrite already known mappings
                          boolean oid2AlgContains = oid2AlgMap.containsKey(alias);
                          boolean alg2OidContains = alg2OidMap.containsKey(algUC);
                          if (!oid2AlgContains || !alg2OidContains) {
                              if (!oid2AlgContains) {
                                  oid2AlgMap.put(alias, algUC);
                              }
                              if (!alg2OidContains) {
                                  alg2OidMap.put(algUC, alias);
                              }
                              // map upper case alg name to its original name
                              algAliasesMap.put(algUC, alg);
                          }
                             // Do not override known standard names
                      } else if (!algAliasesMap.containsKey(alias.toUpperCase(Locale.US))) {
                          algAliasesMap.put(alias.toUpperCase(Locale.US), alg);
                      }
                  }
              }
          }
      }
  
      /**
       * Checks if parameter represents OID
       *
       * @param alias alias to be checked
       * @return 'true' if parameter represents OID
       */
      public static boolean isOID(String alias) {
          return ObjectIdentifier.isOID(normalize(alias));
      }
  
      /**
       * Removes leading "OID." from oid String passed
       *
       * @param oid string that may contain leading "OID."
       * @return string passed without leading "OID."
       */
      public static String normalize(String oid) {
          return oid.startsWith("OID.")
              ? oid.substring(4)
              : oid;
      }
  }
  