Home | History | Annotate | Download | only in conscrypt
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package org.conscrypt;
     17 
     18 import java.security.InvalidAlgorithmParameterException;
     19 import java.security.InvalidParameterException;
     20 import java.security.SecureRandom;
     21 import java.security.spec.AlgorithmParameterSpec;
     22 import javax.crypto.KeyGeneratorSpi;
     23 import javax.crypto.SecretKey;
     24 import javax.crypto.spec.DESedeKeySpec;
     25 import javax.crypto.spec.SecretKeySpec;
     26 
     27 /**
     28  * An implementation of {@link javax.crypto.KeyGenerator} suitable for use with other Conscrypt
     29  * algorithms.
     30  *
     31  * @hide
     32  */
     33 @Internal
     34 public abstract class KeyGeneratorImpl extends KeyGeneratorSpi {
     35     private final String algorithm;
     36     protected SecureRandom secureRandom;
     37     private int keySizeBits;
     38 
     39     private KeyGeneratorImpl(String algorithm, int defaultKeySizeBits) {
     40         this.algorithm = algorithm;
     41         this.keySizeBits = defaultKeySizeBits;
     42     }
     43 
     44     protected void checkKeySize(int keySize) {
     45         if (keySize <= 0) {
     46             throw new InvalidParameterException("Key size must be positive");
     47         }
     48     }
     49 
     50     @Override
     51     protected void engineInit(SecureRandom secureRandom) {
     52         this.secureRandom = secureRandom;
     53     }
     54 
     55     @Override
     56     protected void engineInit(AlgorithmParameterSpec params, SecureRandom secureRandom)
     57             throws InvalidAlgorithmParameterException {
     58         if (params == null) {
     59             throw new InvalidAlgorithmParameterException("No params provided");
     60         } else {
     61             throw new InvalidAlgorithmParameterException(
     62                     "Unknown param type: " + params.getClass().getName());
     63         }
     64     }
     65 
     66     @Override
     67     protected void engineInit(int keySize, SecureRandom secureRandom) {
     68         checkKeySize(keySize);
     69         this.keySizeBits = keySize;
     70         this.secureRandom = secureRandom;
     71     }
     72 
     73     protected byte[] doKeyGeneration(int keyBytes) {
     74         byte[] keyData = new byte[keyBytes];
     75         secureRandom.nextBytes(keyData);
     76         return keyData;
     77     }
     78 
     79     @Override
     80     protected SecretKey engineGenerateKey() {
     81         if (secureRandom == null) {
     82             secureRandom = new SecureRandom();
     83         }
     84 
     85         return new SecretKeySpec(doKeyGeneration((keySizeBits + 7) / 8), algorithm);
     86     }
     87 
     88     // For HMAC, RFC 2104 recommends using the hash's output length as the key length
     89     public static final class HmacMD5 extends KeyGeneratorImpl {
     90         public HmacMD5() {
     91             super("HmacMD5", 128);
     92         }
     93     }
     94 
     95     public static final class HmacSHA1 extends KeyGeneratorImpl {
     96         public HmacSHA1() {
     97             super("HmacSHA1", 160);
     98         }
     99     }
    100 
    101     public static final class HmacSHA224 extends KeyGeneratorImpl {
    102         public HmacSHA224() {
    103             super("HmacSHA224", 224);
    104         }
    105     }
    106 
    107     public static final class HmacSHA256 extends KeyGeneratorImpl {
    108         public HmacSHA256() {
    109             super("HmacSHA256", 256);
    110         }
    111     }
    112 
    113     public static final class HmacSHA384 extends KeyGeneratorImpl {
    114         public HmacSHA384() {
    115             super("HmacSHA384", 384);
    116         }
    117     }
    118 
    119     public static final class HmacSHA512 extends KeyGeneratorImpl {
    120         public HmacSHA512() {
    121             super("HmacSHA512", 512);
    122         }
    123     }
    124 
    125     public static final class DESEDE extends KeyGeneratorImpl {
    126         public DESEDE() {
    127             super("DESEDE", 192);
    128         }
    129 
    130         @Override
    131         protected void checkKeySize(int keySize) {
    132             if ((keySize != 112) && (keySize != 168)) {
    133                 throw new InvalidParameterException("Key size must be either 112 or 168 bits");
    134             }
    135         }
    136 
    137         @Override
    138         protected byte[] doKeyGeneration(int keyBytes) {
    139             byte[] keyData = new byte[DESedeKeySpec.DES_EDE_KEY_LEN];
    140             secureRandom.nextBytes(keyData);
    141             // Set the parity bit for each byte
    142             for (int i = 0; i < keyData.length; i++) {
    143                 if (Integer.bitCount(keyData[i]) % 2 == 0) {
    144                     keyData[i] = (byte) (keyData[i] ^ 1);
    145                 }
    146             }
    147             if (keyBytes == 14) {
    148                 // The user requested an A-B-A key
    149                 System.arraycopy(keyData, 0, keyData, 16, 8);
    150             }
    151             return keyData;
    152         }
    153     }
    154 
    155     public static final class AES extends KeyGeneratorImpl {
    156         public AES() {
    157             super("AES", 128);
    158         }
    159 
    160         @Override
    161         protected void checkKeySize(int keySize) {
    162             if ((keySize != 128) && (keySize != 192) && (keySize != 256)) {
    163                 throw new InvalidParameterException(
    164                         "Key size must be either 128, 192, or 256 bits");
    165             }
    166         }
    167     }
    168 
    169     public static final class ChaCha20 extends KeyGeneratorImpl {
    170         public ChaCha20() {
    171             super("ChaCha20", 256);
    172         }
    173 
    174         @Override
    175         protected void checkKeySize(int keySize) {
    176             if (keySize != 256) {
    177                 throw new InvalidParameterException("Key size must be 256 bits");
    178             }
    179         }
    180     }
    181 
    182     public static final class ARC4 extends KeyGeneratorImpl {
    183         public ARC4() {
    184             super("ARC4", 128);
    185         }
    186 
    187         @Override
    188         protected void checkKeySize(int keySize) {
    189             if (keySize < 40 || 2048 < keySize) {
    190                 throw new InvalidParameterException("Key size must be between 40 and 2048 bits");
    191             }
    192         }
    193     }
    194 }
    195