1 /*
   2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.crypto.provider;
  27 
  28 import java.security.InvalidKeyException;
  29 import java.security.spec.KeySpec;
  30 import java.security.spec.InvalidKeySpecException;
  31 import javax.crypto.SecretKey;
  32 import javax.crypto.SecretKeyFactorySpi;
  33 import javax.crypto.spec.PBEKeySpec;
  34 import java.util.HashSet;
  35 import java.util.Locale;
  36 
  37 /**
  38  * This class implements a key factory for PBE keys according to PKCS#5,
  39  * meaning that the password must consist of printable ASCII characters
  40  * (values 32 to 126 decimal inclusive) and only the low order 8 bits
  41  * of each password character are used.
  42  *
  43  * @author Jan Luehe
  44  *
  45  */
  46 abstract class PBEKeyFactory extends SecretKeyFactorySpi {
  47 
  48     private String type;
  49     private static HashSet<String> validTypes;
  50 
  51     /**
  52      * Simple constructor
  53      */
  54     private PBEKeyFactory(String keytype) {
  55         type = keytype;
  56     }
  57 
  58     static {
  59         validTypes = new HashSet<String>(17);
  60         validTypes.add("PBEWithMD5AndDES".toUpperCase(Locale.ENGLISH));
  61         validTypes.add("PBEWithSHA1AndDESede".toUpperCase(Locale.ENGLISH));
  62         validTypes.add("PBEWithSHA1AndRC2_40".toUpperCase(Locale.ENGLISH));
  63         validTypes.add("PBEWithSHA1AndRC2_128".toUpperCase(Locale.ENGLISH));
  64         validTypes.add("PBEWithSHA1AndRC4_40".toUpperCase(Locale.ENGLISH));
  65         validTypes.add("PBEWithSHA1AndRC4_128".toUpperCase(Locale.ENGLISH));
  66         // Proprietary algorithm.
  67         validTypes.add("PBEWithMD5AndTripleDES".toUpperCase(Locale.ENGLISH));
  68         validTypes.add("PBEWithHmacSHA1AndAES_128".toUpperCase(Locale.ENGLISH));
  69         validTypes.add("PBEWithHmacSHA224AndAES_128".toUpperCase(Locale.ENGLISH));
  70         validTypes.add("PBEWithHmacSHA256AndAES_128".toUpperCase(Locale.ENGLISH));
  71         validTypes.add("PBEWithHmacSHA384AndAES_128".toUpperCase(Locale.ENGLISH));
  72         validTypes.add("PBEWithHmacSHA512AndAES_128".toUpperCase(Locale.ENGLISH));
  73         validTypes.add("PBEWithHmacSHA1AndAES_256".toUpperCase(Locale.ENGLISH));
  74         validTypes.add("PBEWithHmacSHA224AndAES_256".toUpperCase(Locale.ENGLISH));
  75         validTypes.add("PBEWithHmacSHA256AndAES_256".toUpperCase(Locale.ENGLISH));
  76         validTypes.add("PBEWithHmacSHA384AndAES_256".toUpperCase(Locale.ENGLISH));
  77         validTypes.add("PBEWithHmacSHA512AndAES_256".toUpperCase(Locale.ENGLISH));
  78     }
  79 
  80     public static final class PBEWithMD5AndDES
  81             extends PBEKeyFactory {
  82         public PBEWithMD5AndDES()  {
  83             super("PBEWithMD5AndDES");
  84         }
  85     }
  86 
  87     public static final class PBEWithSHA1AndDESede
  88             extends PBEKeyFactory {
  89         public PBEWithSHA1AndDESede()  {
  90             super("PBEWithSHA1AndDESede");
  91         }
  92     }
  93 
  94     public static final class PBEWithSHA1AndRC2_40
  95             extends PBEKeyFactory {
  96         public PBEWithSHA1AndRC2_40()  {
  97             super("PBEWithSHA1AndRC2_40");
  98         }
  99     }
 100 
 101     public static final class PBEWithSHA1AndRC2_128
 102             extends PBEKeyFactory {
 103         public PBEWithSHA1AndRC2_128()  {
 104             super("PBEWithSHA1AndRC2_128");
 105         }
 106     }
 107 
 108     public static final class PBEWithSHA1AndRC4_40
 109             extends PBEKeyFactory {
 110         public PBEWithSHA1AndRC4_40()  {
 111             super("PBEWithSHA1AndRC4_40");
 112         }
 113     }
 114 
 115     public static final class PBEWithSHA1AndRC4_128
 116             extends PBEKeyFactory {
 117         public PBEWithSHA1AndRC4_128()  {
 118             super("PBEWithSHA1AndRC4_128");
 119         }
 120     }
 121 
 122     /*
 123      * Private proprietary algorithm for supporting JCEKS.
 124      */
 125     public static final class PBEWithMD5AndTripleDES
 126             extends PBEKeyFactory {
 127         public PBEWithMD5AndTripleDES()  {
 128             super("PBEWithMD5AndTripleDES");
 129         }
 130     }
 131 
 132     public static final class PBEWithHmacSHA1AndAES_128
 133             extends PBEKeyFactory {
 134         public PBEWithHmacSHA1AndAES_128()  {
 135             super("PBEWithHmacSHA1AndAES_128");
 136         }
 137     }
 138 
 139     public static final class PBEWithHmacSHA224AndAES_128
 140             extends PBEKeyFactory {
 141         public PBEWithHmacSHA224AndAES_128()  {
 142             super("PBEWithHmacSHA224AndAES_128");
 143         }
 144     }
 145 
 146     public static final class PBEWithHmacSHA256AndAES_128
 147             extends PBEKeyFactory {
 148         public PBEWithHmacSHA256AndAES_128()  {
 149             super("PBEWithHmacSHA256AndAES_128");
 150         }
 151     }
 152 
 153     public static final class PBEWithHmacSHA384AndAES_128
 154             extends PBEKeyFactory {
 155         public PBEWithHmacSHA384AndAES_128()  {
 156             super("PBEWithHmacSHA384AndAES_128");
 157         }
 158     }
 159 
 160     public static final class PBEWithHmacSHA512AndAES_128
 161             extends PBEKeyFactory {
 162         public PBEWithHmacSHA512AndAES_128()  {
 163             super("PBEWithHmacSHA512AndAES_128");
 164         }
 165     }
 166 
 167     public static final class PBEWithHmacSHA1AndAES_256
 168             extends PBEKeyFactory {
 169         public PBEWithHmacSHA1AndAES_256()  {
 170             super("PBEWithHmacSHA1AndAES_256");
 171         }
 172     }
 173 
 174     public static final class PBEWithHmacSHA224AndAES_256
 175             extends PBEKeyFactory {
 176         public PBEWithHmacSHA224AndAES_256()  {
 177             super("PBEWithHmacSHA224AndAES_256");
 178         }
 179     }
 180 
 181     public static final class PBEWithHmacSHA256AndAES_256
 182             extends PBEKeyFactory {
 183         public PBEWithHmacSHA256AndAES_256()  {
 184             super("PBEWithHmacSHA256AndAES_256");
 185         }
 186     }
 187 
 188     public static final class PBEWithHmacSHA384AndAES_256
 189             extends PBEKeyFactory {
 190         public PBEWithHmacSHA384AndAES_256()  {
 191             super("PBEWithHmacSHA384AndAES_256");
 192         }
 193     }
 194 
 195     public static final class PBEWithHmacSHA512AndAES_256
 196             extends PBEKeyFactory {
 197         public PBEWithHmacSHA512AndAES_256()  {
 198             super("PBEWithHmacSHA512AndAES_256");
 199         }
 200     }
 201 
 202     /**
 203      * Generates a <code>SecretKey</code> object from the provided key
 204      * specification (key material).
 205      *
 206      * @param keySpec the specification (key material) of the secret key
 207      *
 208      * @return the secret key
 209      *
 210      * @exception InvalidKeySpecException if the given key specification
 211      * is inappropriate for this key factory to produce a public key.
 212      */
 213     protected SecretKey engineGenerateSecret(KeySpec keySpec)
 214         throws InvalidKeySpecException
 215     {
 216         if (!(keySpec instanceof PBEKeySpec)) {
 217             throw new InvalidKeySpecException("Invalid key spec");
 218         }
 219         return new PBEKey((PBEKeySpec)keySpec, type);
 220     }
 221 
 222     /**
 223      * Returns a specification (key material) of the given key
 224      * in the requested format.
 225      *
 226      * @param key the key
 227      *
 228      * @param keySpec the requested format in which the key material shall be
 229      * returned
 230      *
 231      * @return the underlying key specification (key material) in the
 232      * requested format
 233      *
 234      * @exception InvalidKeySpecException if the requested key specification is
 235      * inappropriate for the given key, or the given key cannot be processed
 236      * (e.g., the given key has an unrecognized algorithm or format).
 237      */
 238     protected KeySpec engineGetKeySpec(SecretKey key, Class<?> keySpecCl)
 239         throws InvalidKeySpecException {
 240         if ((key instanceof SecretKey)
 241             && (validTypes.contains(key.getAlgorithm().toUpperCase(Locale.ENGLISH)))
 242             && (key.getFormat().equalsIgnoreCase("RAW"))) {
 243 
 244             // Check if requested key spec is amongst the valid ones
 245             if ((keySpecCl != null)
 246                 && PBEKeySpec.class.isAssignableFrom(keySpecCl)) {
 247                 byte[] passwdBytes = key.getEncoded();
 248                 char[] passwdChars = new char[passwdBytes.length];
 249                 for (int i=0; i<passwdChars.length; i++)
 250                     passwdChars[i] = (char) (passwdBytes[i] & 0x7f);
 251                 PBEKeySpec ret = new PBEKeySpec(passwdChars);
 252                 // password char[] was cloned in PBEKeySpec constructor,
 253                 // so we can zero it out here
 254                 java.util.Arrays.fill(passwdChars, ' ');
 255                 java.util.Arrays.fill(passwdBytes, (byte)0x00);
 256                 return ret;
 257             } else {
 258                 throw new InvalidKeySpecException("Invalid key spec");
 259             }
 260         } else {
 261             throw new InvalidKeySpecException("Invalid key "
 262                                               + "format/algorithm");
 263         }
 264     }
 265 
 266     /**
 267      * Translates a <code>SecretKey</code> object, whose provider may be
 268      * unknown or potentially untrusted, into a corresponding
 269      * <code>SecretKey</code> object of this key factory.
 270      *
 271      * @param key the key whose provider is unknown or untrusted
 272      *
 273      * @return the translated key
 274      *
 275      * @exception InvalidKeyException if the given key cannot be processed by
 276      * this key factory.
 277      */
 278     protected SecretKey engineTranslateKey(SecretKey key)
 279         throws InvalidKeyException
 280     {
 281         try {
 282             if ((key != null) &&
 283                 (validTypes.contains(key.getAlgorithm().toUpperCase(Locale.ENGLISH))) &&
 284                 (key.getFormat().equalsIgnoreCase("RAW"))) {
 285 
 286                 // Check if key originates from this factory
 287                 if (key instanceof com.sun.crypto.provider.PBEKey) {
 288                     return key;
 289                 }
 290 
 291                 // Convert key to spec
 292                 PBEKeySpec pbeKeySpec = (PBEKeySpec)engineGetKeySpec
 293                     (key, PBEKeySpec.class);
 294 
 295                 // Create key from spec, and return it
 296                 return engineGenerateSecret(pbeKeySpec);
 297             } else {
 298                 throw new InvalidKeyException("Invalid key format/algorithm");
 299             }
 300 
 301         } catch (InvalidKeySpecException ikse) {
 302             throw new InvalidKeyException("Cannot translate key: "
 303                                           + ikse.getMessage());
 304         }
 305     }
 306 }