blob: e7b6b33291475d0ad045a6442db9a981f581bdb1 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed 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.
*/
package org.conscrypt;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidParameterException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.KeyGeneratorSpi;
import javax.crypto.SecretKey;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.SecretKeySpec;
/**
* An implementation of {@link javax.crypto.KeyGenerator} suitable for use with other Conscrypt
* algorithms.
*/
@Internal
public abstract class KeyGeneratorImpl extends KeyGeneratorSpi {
private final String algorithm;
protected SecureRandom secureRandom;
private int keySizeBits;
private KeyGeneratorImpl(String algorithm, int defaultKeySizeBits) {
this.algorithm = algorithm;
this.keySizeBits = defaultKeySizeBits;
}
protected void checkKeySize(int keySize) {
if (keySize <= 0) {
throw new InvalidParameterException("Key size must be positive");
}
}
@Override
protected void engineInit(SecureRandom secureRandom) {
this.secureRandom = secureRandom;
}
@Override
protected void engineInit(AlgorithmParameterSpec params, SecureRandom secureRandom)
throws InvalidAlgorithmParameterException {
if (params == null) {
throw new InvalidAlgorithmParameterException("No params provided");
} else {
throw new InvalidAlgorithmParameterException(
"Unknown param type: " + params.getClass().getName());
}
}
@Override
protected void engineInit(int keySize, SecureRandom secureRandom) {
checkKeySize(keySize);
this.keySizeBits = keySize;
this.secureRandom = secureRandom;
}
protected byte[] doKeyGeneration(int keyBytes) {
byte[] keyData = new byte[keyBytes];
secureRandom.nextBytes(keyData);
return keyData;
}
@Override
protected SecretKey engineGenerateKey() {
if (secureRandom == null) {
secureRandom = new SecureRandom();
}
return new SecretKeySpec(doKeyGeneration((keySizeBits + 7) / 8), algorithm);
}
// For HMAC, RFC 2104 recommends using the hash's output length as the key length
public static final class HmacMD5 extends KeyGeneratorImpl {
public HmacMD5() {
super("HmacMD5", 128);
}
}
public static final class HmacSHA1 extends KeyGeneratorImpl {
public HmacSHA1() {
super("HmacSHA1", 160);
}
}
public static final class HmacSHA224 extends KeyGeneratorImpl {
public HmacSHA224() {
super("HmacSHA224", 224);
}
}
public static final class HmacSHA256 extends KeyGeneratorImpl {
public HmacSHA256() {
super("HmacSHA256", 256);
}
}
public static final class HmacSHA384 extends KeyGeneratorImpl {
public HmacSHA384() {
super("HmacSHA384", 384);
}
}
public static final class HmacSHA512 extends KeyGeneratorImpl {
public HmacSHA512() {
super("HmacSHA512", 512);
}
}
public static final class DESEDE extends KeyGeneratorImpl {
public DESEDE() {
super("DESEDE", 192);
}
@Override
protected void checkKeySize(int keySize) {
if ((keySize != 112) && (keySize != 168)) {
throw new InvalidParameterException("Key size must be either 112 or 168 bits");
}
}
@Override
protected byte[] doKeyGeneration(int keyBytes) {
byte[] keyData = new byte[DESedeKeySpec.DES_EDE_KEY_LEN];
secureRandom.nextBytes(keyData);
// Set the parity bit for each byte
for (int i = 0; i < keyData.length; i++) {
if (Integer.bitCount(keyData[i]) % 2 == 0) {
keyData[i] = (byte) (keyData[i] ^ 1);
}
}
if (keyBytes == 14) {
// The user requested an A-B-A key
System.arraycopy(keyData, 0, keyData, 16, 8);
}
return keyData;
}
}
public static final class AES extends KeyGeneratorImpl {
public AES() {
super("AES", 128);
}
@Override
protected void checkKeySize(int keySize) {
if ((keySize != 128) && (keySize != 192) && (keySize != 256)) {
throw new InvalidParameterException(
"Key size must be either 128, 192, or 256 bits");
}
}
}
public static final class ChaCha20 extends KeyGeneratorImpl {
public ChaCha20() {
super("ChaCha20", 256);
}
@Override
protected void checkKeySize(int keySize) {
if (keySize != 256) {
throw new InvalidParameterException("Key size must be 256 bits");
}
}
}
public static final class ARC4 extends KeyGeneratorImpl {
public ARC4() {
super("ARC4", 128);
}
@Override
protected void checkKeySize(int keySize) {
if (keySize < 40 || 2048 < keySize) {
throw new InvalidParameterException("Key size must be between 40 and 2048 bits");
}
}
}
}