blob: e4904d4f1ffb917a800685eb1f5aaddf24433627 [file] [log] [blame]
/*
* Copyright (C) 2019 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 com.android.internal.net.ipsec.ike.crypto;
import android.net.IpSecAlgorithm;
import android.net.ipsec.ike.SaProposal;
import java.nio.ByteBuffer;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Provider;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* IkeCipher represents a negotiated normal mode encryption algorithm.
*
* @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296, Internet Key Exchange
* Protocol Version 2 (IKEv2)</a>
*/
public final class IkeNormalModeCipher extends IkeCipher {
/** Package private */
IkeNormalModeCipher(
int algorithmId, int keyLength, int ivLength, String algorithmName, Provider provider) {
super(algorithmId, keyLength, ivLength, algorithmName, false /*isAead*/, provider);
}
private byte[] doCipherAction(byte[] data, byte[] keyBytes, byte[] ivBytes, int opmode)
throws IllegalBlockSizeException {
if (getKeyLength() != keyBytes.length) {
throw new IllegalArgumentException(
"Expected key length: "
+ getKeyLength()
+ " Received key length: "
+ keyBytes.length);
}
try {
SecretKeySpec key = new SecretKeySpec(keyBytes, getAlgorithmName());
IvParameterSpec iv = new IvParameterSpec(ivBytes);
mCipher.init(opmode, key, iv);
ByteBuffer inputBuffer = ByteBuffer.wrap(data);
ByteBuffer outputBuffer = ByteBuffer.allocate(data.length);
mCipher.doFinal(inputBuffer, outputBuffer);
return outputBuffer.array();
} catch (InvalidKeyException
| InvalidAlgorithmParameterException
| BadPaddingException
| ShortBufferException e) {
String errorMessage =
Cipher.ENCRYPT_MODE == opmode
? "Failed to encrypt data: "
: "Failed to decrypt data: ";
throw new IllegalArgumentException(errorMessage, e);
}
}
/**
* Encrypt padded data.
*
* @param paddedData the padded data to encrypt.
* @param keyBytes the encryption key.
* @param ivBytes the initialization vector (IV).
* @return the encrypted and padded data.
*/
public byte[] encrypt(byte[] paddedData, byte[] keyBytes, byte[] ivBytes) {
try {
return doCipherAction(paddedData, keyBytes, ivBytes, Cipher.ENCRYPT_MODE);
} catch (IllegalBlockSizeException e) {
throw new IllegalArgumentException("Failed to encrypt data: ", e);
}
}
/**
* Decrypt the encrypted and padded data.
*
* @param encryptedData the encrypted and padded data.
* @param keyBytes the decryption key.
* @param ivBytes the initialization vector (IV).
* @return the decrypted and padded data.
* @throws IllegalBlockSizeException if the total encryptedData length is not a multiple of
* block size.
*/
public byte[] decrypt(byte[] encryptedData, byte[] keyBytes, byte[] ivBytes)
throws IllegalBlockSizeException {
return doCipherAction(encryptedData, keyBytes, ivBytes, Cipher.DECRYPT_MODE);
}
@Override
public IpSecAlgorithm buildIpSecAlgorithmWithKey(byte[] key) {
validateKeyLenOrThrow(key);
switch (getAlgorithmId()) {
case SaProposal.ENCRYPTION_ALGORITHM_3DES:
// TODO: Consider supporting 3DES in IpSecTransform.
throw new UnsupportedOperationException("Do not support 3Des encryption.");
case SaProposal.ENCRYPTION_ALGORITHM_AES_CBC:
return new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, key);
default:
throw new IllegalArgumentException(
"Unrecognized Encryption Algorithm ID: " + getAlgorithmId());
}
}
}