1 /* 2 * Copyright (C) 2019 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 17 package com.android.internal.net.ipsec.ike.crypto; 18 19 import android.net.IpSecAlgorithm; 20 import android.net.ipsec.ike.SaProposal; 21 22 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform; 23 24 import java.security.NoSuchAlgorithmException; 25 import java.security.SecureRandom; 26 27 import javax.crypto.Cipher; 28 import javax.crypto.NoSuchPaddingException; 29 30 /** 31 * IkeCipher contains common information of normal and combined mode encryption algorithms. 32 * 33 * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296, Internet Key Exchange 34 * Protocol Version 2 (IKEv2)</a> 35 */ 36 public abstract class IkeCipher extends IkeCrypto { 37 private static final int KEY_LEN_3DES = 24; 38 39 private static final int IV_LEN_3DES = 8; 40 private static final int IV_LEN_AES_CBC = 16; 41 private static final int IV_LEN_AES_GCM = 8; 42 43 private final boolean mIsAead; 44 private final int mIvLen; 45 46 protected final Cipher mCipher; 47 IkeCipher( int algorithmId, int keyLength, int ivLength, String algorithmName, boolean isAead)48 protected IkeCipher( 49 int algorithmId, int keyLength, int ivLength, String algorithmName, boolean isAead) { 50 super(algorithmId, keyLength, algorithmName); 51 mIvLen = ivLength; 52 mIsAead = isAead; 53 54 try { 55 mCipher = Cipher.getInstance(getAlgorithmName()); 56 } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { 57 throw new IllegalArgumentException("Failed to construct " + getTypeString(), e); 58 } 59 } 60 61 /** 62 * Contruct an instance of IkeCipher. 63 * 64 * @param encryptionTransform the valid negotiated EncryptionTransform. 65 * @return an instance of IkeCipher. 66 */ create(EncryptionTransform encryptionTransform)67 public static IkeCipher create(EncryptionTransform encryptionTransform) { 68 int algorithmId = encryptionTransform.id; 69 70 // Use specifiedKeyLength for algorithms with variable key length. Since 71 // specifiedKeyLength are encoded in bits, it needs to be converted to bytes. 72 switch (algorithmId) { 73 case SaProposal.ENCRYPTION_ALGORITHM_3DES: 74 return new IkeNormalModeCipher( 75 algorithmId, KEY_LEN_3DES, IV_LEN_3DES, "DESede/CBC/NoPadding"); 76 case SaProposal.ENCRYPTION_ALGORITHM_AES_CBC: 77 return new IkeNormalModeCipher( 78 algorithmId, 79 encryptionTransform.getSpecifiedKeyLength() / 8, 80 IV_LEN_AES_CBC, 81 "AES/CBC/NoPadding"); 82 case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8: 83 // Fall through 84 case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12: 85 // Fall through 86 case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16: 87 // Fall through 88 return new IkeCombinedModeCipher( 89 algorithmId, 90 encryptionTransform.getSpecifiedKeyLength() / 8, 91 IV_LEN_AES_GCM, 92 "AES/GCM/NoPadding"); 93 default: 94 throw new IllegalArgumentException( 95 "Unrecognized Encryption Algorithm ID: " + algorithmId); 96 } 97 } 98 99 /** 100 * Check if this encryption algorithm is a combined-mode/AEAD algorithm. 101 * 102 * @return if this encryption algorithm is a combined-mode/AEAD algorithm. 103 */ isAead()104 public boolean isAead() { 105 return mIsAead; 106 } 107 108 /** 109 * Get the block size (in bytes). 110 * 111 * @return the block size (in bytes). 112 */ getBlockSize()113 public int getBlockSize() { 114 // Currently all supported encryption algorithms are block ciphers. So the return value will 115 // not be zero. 116 return mCipher.getBlockSize(); 117 } 118 119 /** 120 * Get initialization vector (IV) length. 121 * 122 * @return the IV length. 123 */ getIvLen()124 public int getIvLen() { 125 return mIvLen; 126 } 127 128 /** 129 * Generate initialization vector (IV). 130 * 131 * @return the initialization vector (IV). 132 */ generateIv()133 public byte[] generateIv() { 134 byte[] iv = new byte[getIvLen()]; 135 new SecureRandom().nextBytes(iv); 136 return iv; 137 } 138 validateKeyLenOrThrow(byte[] key)139 protected void validateKeyLenOrThrow(byte[] key) { 140 if (key.length != getKeyLength()) { 141 throw new IllegalArgumentException( 142 "Expected key with length of : " 143 + getKeyLength() 144 + " Received key with length of : " 145 + key.length); 146 } 147 } 148 149 /** 150 * Build IpSecAlgorithm from this IkeCipher. 151 * 152 * <p>Build IpSecAlgorithm that represents the same encryption algorithm with this IkeCipher 153 * instance with provided encryption key. 154 * 155 * @param key the encryption key in byte array. 156 * @return the IpSecAlgorithm. 157 */ buildIpSecAlgorithmWithKey(byte[] key)158 public abstract IpSecAlgorithm buildIpSecAlgorithmWithKey(byte[] key); 159 160 /** 161 * Returns algorithm type as a String. 162 * 163 * @return the algorithm type as a String. 164 */ 165 @Override getTypeString()166 public String getTypeString() { 167 return "Encryption Algorithm"; 168 } 169 } 170