blob: 1bb0b709a30a28975c1f7a25e41c6621c81bb94c [file] [log] [blame]
/*
* Copyright (C) 2018 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.ike.ikev2.message;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import com.android.ike.ikev2.IkeDhParams;
import com.android.ike.ikev2.SaProposal;
import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
import com.android.ike.ikev2.utils.BigIntegerUtils;
import org.junit.Test;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.Arrays;
import javax.crypto.spec.DHPrivateKeySpec;
public final class IkeKePayloadTest {
private static final String KE_PAYLOAD_GENERIC_HEADER = "28000088";
private static final String KE_PAYLOAD_RAW_PACKET =
"00020000b4a2faf4bb54878ae21d638512ece55d9236fc50"
+ "46ab6cef82220f421f3ce6361faf36564ecb6d28798a94aa"
+ "d7b2b4b603ddeaaa5630adb9ece8ac37534036040610ebdd"
+ "92f46bef84f0be7db860351843858f8acf87056e272377f7"
+ "0c9f2d81e29c7b0ce4f291a3a72476bb0b278fd4b7b0a4c2"
+ "6bbeb08214c7071376079587";
private static final boolean CRITICAL_BIT = false;
@IkePayload.PayloadType
private static final int NEXT_PAYLOAD_TYPE = IkePayload.PAYLOAD_TYPE_NONCE;
private static final int EXPECTED_DH_GROUP = SaProposal.DH_GROUP_1024_BIT_MODP;
private static final int EXPECTED_KE_DATA_LEN = 128;
private static final String KEY_EXCHANGE_DATA_RAW_PACKET =
"b4a2faf4bb54878ae21d638512ece55d9236fc5046ab6cef"
+ "82220f421f3ce6361faf36564ecb6d28798a94aad7b2b4b6"
+ "03ddeaaa5630adb9ece8ac37534036040610ebdd92f46bef"
+ "84f0be7db860351843858f8acf87056e272377f70c9f2d81"
+ "e29c7b0ce4f291a3a72476bb0b278fd4b7b0a4c26bbeb082"
+ "14c7071376079587";
private static final String PRIME_1024_BIT_MODP_160_SUBGROUP =
"B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C6"
+ "9A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C0"
+ "13ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD70"
+ "98488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0"
+ "A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708"
+ "DF1FB2BC2E4A4371";
private static final String GENERATOR_1024_BIT_MODP_160_SUBGROUP =
"A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507F"
+ "D6406CFF14266D31266FEA1E5C41564B777E690F5504F213"
+ "160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1"
+ "909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28A"
+ "D662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24"
+ "855E6EEB22B3B2E5";
private static final String PRIVATE_KEY_LOCAL = "B9A3B3AE8FEFC1A2930496507086F8455D48943E";
private static final String PUBLIC_KEY_REMOTE =
"717A6CB053371FF4A3B932941C1E5663F861A1D6AD34AE66"
+ "576DFB98F6C6CBF9DDD5A56C7833F6BCFDFF095582AD868E"
+ "440E8D09FD769E3CECCDC3D3B1E4CFA057776CAAF9739B6A"
+ "9FEE8E7411F8D6DAC09D6A4EDB46CC2B5D5203090EAE6126"
+ "311E53FD2C14B574E6A3109A3DA1BE41BDCEAA186F5CE067"
+ "16A2B6A07B3C33FE";
private static final String EXPECTED_SHARED_KEY =
"5C804F454D30D9C4DF85271F93528C91DF6B48AB5F80B3B5"
+ "9CAAC1B28F8ACBA9CD3E39F3CB614525D9521D2E644C53B8"
+ "07B810F340062F257D7D6FBFE8D5E8F072E9B6E9AFDA9413"
+ "EAFB2E8B0699B1FB5A0CACEDDEAEAD7E9CFBB36AE2B42083"
+ "5BD83A19FB0B5E96BF8FA4D09E345525167ECD9155416F46"
+ "F408ED31B63C6E6D";
private static final String KEY_EXCHANGE_ALGORITHM = "DH";
@Test
public void testDecodeIkeKePayload() throws Exception {
byte[] inputPacket = TestUtils.hexStringToByteArray(KE_PAYLOAD_RAW_PACKET);
IkeKePayload payload = new IkeKePayload(CRITICAL_BIT, inputPacket);
assertFalse(payload.isOutbound);
assertEquals(EXPECTED_DH_GROUP, payload.dhGroup);
byte[] keyExchangeData = TestUtils.hexStringToByteArray(KEY_EXCHANGE_DATA_RAW_PACKET);
assertEquals(keyExchangeData.length, payload.keyExchangeData.length);
for (int i = 0; i < keyExchangeData.length; i++) {
assertEquals(keyExchangeData[i], payload.keyExchangeData[i]);
}
}
@Test
public void testDecodeIkeKePayloadWithInvalidKeData() throws Exception {
// Cut bytes of KE data from original KE payload
String badKeyPayloadPacket =
KE_PAYLOAD_RAW_PACKET.substring(0, KE_PAYLOAD_RAW_PACKET.length() - 2);
byte[] inputPacket = TestUtils.hexStringToByteArray(badKeyPayloadPacket);
try {
IkeKePayload payload = new IkeKePayload(CRITICAL_BIT, inputPacket);
fail("Expected InvalidSyntaxException: KE data length doesn't match its DH group type");
} catch (InvalidSyntaxException expected) {
}
}
@Test
public void testEncodeIkeKePayload() throws Exception {
byte[] inputPacket = TestUtils.hexStringToByteArray(KE_PAYLOAD_RAW_PACKET);
IkeKePayload payload = new IkeKePayload(CRITICAL_BIT, inputPacket);
ByteBuffer byteBuffer = ByteBuffer.allocate(payload.getPayloadLength());
payload.encodeToByteBuffer(NEXT_PAYLOAD_TYPE, byteBuffer);
byte[] expectedKePayload =
TestUtils.hexStringToByteArray(KE_PAYLOAD_GENERIC_HEADER + KE_PAYLOAD_RAW_PACKET);
assertArrayEquals(expectedKePayload, byteBuffer.array());
}
@Test
public void testGetIkeKePayload() throws Exception {
IkeKePayload payload = new IkeKePayload(SaProposal.DH_GROUP_1024_BIT_MODP);
// Test DHPrivateKeySpec
assertTrue(payload.isOutbound);
DHPrivateKeySpec privateKeySpec = payload.localPrivateKey;
BigInteger primeValue = privateKeySpec.getP();
BigInteger expectedPrimeValue = new BigInteger(IkeDhParams.PRIME_1024_BIT_MODP, 16);
assertEquals(0, expectedPrimeValue.compareTo(primeValue));
BigInteger genValue = privateKeySpec.getG();
BigInteger expectedGenValue = BigInteger.valueOf(IkeDhParams.BASE_GENERATOR_MODP);
assertEquals(0, expectedGenValue.compareTo(genValue));
// Test IkeKePayload
assertEquals(EXPECTED_DH_GROUP, payload.dhGroup);
assertEquals(EXPECTED_KE_DATA_LEN, payload.keyExchangeData.length);
}
// Since we didn't find test data for DH group types supported in current IKE library, we use
// test data for "1024-bit MODP Group with 160-bit Prime Order Subgroup" from RFC 5114. The main
// difference is that it uses weaker Prime and Generator values and requires more complicated
// recipient test in real Key Exchange process. But it is suitable for testing.
@Test
public void testGetSharedkey() throws Exception {
BigInteger primeValue =
BigIntegerUtils.unsignedHexStringToBigInteger(PRIME_1024_BIT_MODP_160_SUBGROUP);
BigInteger baseGenValue =
BigIntegerUtils.unsignedHexStringToBigInteger(GENERATOR_1024_BIT_MODP_160_SUBGROUP);
BigInteger privateKeyValue =
BigIntegerUtils.unsignedHexStringToBigInteger(PRIVATE_KEY_LOCAL);
byte[] remotePublicKey = TestUtils.hexStringToByteArray(PUBLIC_KEY_REMOTE);
DHPrivateKeySpec privateKeySpec =
new DHPrivateKeySpec(privateKeyValue, primeValue, baseGenValue);
byte[] sharedKeyBytes = IkeKePayload.getSharedKey(privateKeySpec, remotePublicKey);
byte[] expectedSharedKeyBytes = TestUtils.hexStringToByteArray(EXPECTED_SHARED_KEY);
assertTrue(Arrays.equals(expectedSharedKeyBytes, sharedKeyBytes));
}
}