diff options
11 files changed, 208 insertions, 26 deletions
diff --git a/src/java/com/android/ike/ikev2/message/IkeKePayload.java b/src/java/com/android/ike/ikev2/message/IkeKePayload.java index 106bd234..5516ac52 100644 --- a/src/java/com/android/ike/ikev2/message/IkeKePayload.java +++ b/src/java/com/android/ike/ikev2/message/IkeKePayload.java @@ -120,19 +120,31 @@ public final class IkeKePayload extends IkePayload { } /** - * Encode KE payload to byte array. + * Encode KE payload to ByteBuffer. * * @param nextPayload type of payload that follows this payload. - * @return encoded KE payload + * @param byteBuffer destination ByteBuffer that stores encoded payload. */ @Override - byte[] encode(@PayloadType int nextPayload) { + protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) { throw new UnsupportedOperationException( "It is not supported to encode a " + getTypeString()); // TODO: Implement encoding KE payload. } /** + * Get entire payload length. + * + * @return entire payload length. + */ + @Override + protected int getPayloadLength() { + throw new UnsupportedOperationException( + "It is not supported to get payload length of " + getTypeString()); + // TODO: Implement this method for KE payload. + } + + /** * Construct an instance of IkeKePayload according to its {@link DhGroup}. * * @param dh the Dh-Group. It should be in {@link DhGroup} @@ -164,7 +176,8 @@ public final class IkeKePayload extends IkePayload { DHParameterSpec dhParams = new DHParameterSpec(prime, baseGen); KeyPairGenerator dhKeyPairGen = - KeyPairGenerator.getInstance(KEY_EXCHANGE_ALGORITHM, IkeMessage.getProvider()); + KeyPairGenerator.getInstance( + KEY_EXCHANGE_ALGORITHM, IkeMessage.getSecurityProvider()); // By default SecureRandom uses AndroidOpenSSL provided SHA1PRNG Algorithm, which takes // /dev/urandom as seed source. dhKeyPairGen.initialize(dhParams, new SecureRandom()); @@ -199,13 +212,13 @@ public final class IkeKePayload extends IkePayload { DHPublicKeySpec publicKeySpec = new DHPublicKeySpec(publicKeyValue, primeValue, baseGenValue); KeyFactory dhKeyFactory = - KeyFactory.getInstance(KEY_EXCHANGE_ALGORITHM, IkeMessage.getProvider()); + KeyFactory.getInstance(KEY_EXCHANGE_ALGORITHM, IkeMessage.getSecurityProvider()); DHPublicKey publicKey = (DHPublicKey) dhKeyFactory.generatePublic(publicKeySpec); DHPrivateKey privateKey = (DHPrivateKey) dhKeyFactory.generatePrivate(privateKeySpec); // Calculate shared secret KeyAgreement dhKeyAgreement = - KeyAgreement.getInstance(KEY_EXCHANGE_ALGORITHM, IkeMessage.getProvider()); + KeyAgreement.getInstance(KEY_EXCHANGE_ALGORITHM, IkeMessage.getSecurityProvider()); dhKeyAgreement.init(privateKey); dhKeyAgreement.doPhase(publicKey, true/** Last phase */); diff --git a/src/java/com/android/ike/ikev2/message/IkeMessage.java b/src/java/com/android/ike/ikev2/message/IkeMessage.java index 69c1bbdb..118e2f0f 100644 --- a/src/java/com/android/ike/ikev2/message/IkeMessage.java +++ b/src/java/com/android/ike/ikev2/message/IkeMessage.java @@ -106,7 +106,36 @@ public final class IkeMessage { return new IkeMessage(header, supportedPayloadList); } - static Provider getProvider() { + static Provider getSecurityProvider() { return SECURITY_PROVIDER; } + + /** + * Encode all payloads to a byte array. + * + * @return byte array contains all encoded payloads + */ + public byte[] encodePayloads() { + if (ikePayloadList.isEmpty()) { + return new byte[0]; + } + + int payloadLengthSum = 0; + for (IkePayload payload : ikePayloadList) { + payloadLengthSum += payload.getPayloadLength(); + } + + ByteBuffer byteBuffer = ByteBuffer.allocate(payloadLengthSum); + + for (int i = 0; i < ikePayloadList.size() - 1; i++) { + ikePayloadList + .get(i) + .encodeToByteBuffer(ikePayloadList.get(i + 1).payloadType, byteBuffer); + } + ikePayloadList + .get(ikePayloadList.size() - 1) + .encodeToByteBuffer(IkePayload.PAYLOAD_TYPE_NO_NEXT, byteBuffer); + + return byteBuffer.array(); + } } diff --git a/src/java/com/android/ike/ikev2/message/IkeNoncePayload.java b/src/java/com/android/ike/ikev2/message/IkeNoncePayload.java index 156935cb..3792e938 100644 --- a/src/java/com/android/ike/ikev2/message/IkeNoncePayload.java +++ b/src/java/com/android/ike/ikev2/message/IkeNoncePayload.java @@ -19,6 +19,7 @@ package com.android.ike.ikev2.message; import com.android.ike.ikev2.exceptions.IkeException; import com.android.ike.ikev2.exceptions.InvalidSyntaxException; +import java.nio.ByteBuffer; import java.security.SecureRandom; /** @@ -71,16 +72,27 @@ public final class IkeNoncePayload extends IkePayload { } /** - * Encode Nonce payload to byte array. + * Encode Nonce payload to ByteBuffer. * * @param nextPayload type of payload that follows this payload. - * @return encoded Nonce payload + * @param byteBuffer destination ByteBuffer that stores encoded payload. */ @Override - byte[] encode(@PayloadType int nextPayload) { - throw new UnsupportedOperationException( - "It is not supported to encode a " + getTypeString()); - // TODO: Implement encoding Nonce payload. + protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) { + int payloadLength = GENERIC_HEADER_LENGTH + nonceData.length; + + encodePayloadHeaderToByteBuffer(nextPayload, payloadLength, byteBuffer); + byteBuffer.put(nonceData); + } + + /** + * Get entire payload length. + * + * @return entire payload length. + */ + @Override + protected int getPayloadLength() { + return GENERIC_HEADER_LENGTH + nonceData.length; } /** diff --git a/src/java/com/android/ike/ikev2/message/IkeNotifyPayload.java b/src/java/com/android/ike/ikev2/message/IkeNotifyPayload.java index 9476b69b..369a034d 100644 --- a/src/java/com/android/ike/ikev2/message/IkeNotifyPayload.java +++ b/src/java/com/android/ike/ikev2/message/IkeNotifyPayload.java @@ -125,20 +125,33 @@ public final class IkeNotifyPayload extends IkePayload { notifyData = new byte[payloadBody.length - NOTIFY_HEADER_LEN]; inputBuffer.get(notifyData); } + /** - * Encode Notify payload to byte array. + * Encode Notify payload to ByteBuffer. * * @param nextPayload type of payload that follows this payload. - * @return encoded Notify payload + * @param byteBuffer destination ByteBuffer that stores encoded payload. */ @Override - byte[] encode(@PayloadType int nextPayload) { + protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) { throw new UnsupportedOperationException( "It is not supported to encode a " + getTypeString()); // TODO: Implement encoding Notify payload. } /** + * Get entire payload length. + * + * @return entire payload length. + */ + @Override + protected int getPayloadLength() { + throw new UnsupportedOperationException( + "It is not supported to get payload length of " + getTypeString()); + // TODO: Implement this method for Notify payload. + } + + /** * Return the payload type as a String. * * @return the payload type as a String. diff --git a/src/java/com/android/ike/ikev2/message/IkePayload.java b/src/java/com/android/ike/ikev2/message/IkePayload.java index 5333ed6f..2a591063 100644 --- a/src/java/com/android/ike/ikev2/message/IkePayload.java +++ b/src/java/com/android/ike/ikev2/message/IkePayload.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.nio.ByteBuffer; /** * IkePayload is an abstract class that represents the common information for all IKE payload types. @@ -31,6 +32,8 @@ import java.lang.annotation.RetentionPolicy; * Protocol Version 2 (IKEv2). */ public abstract class IkePayload { + // Critical bit and following reserved 7 bits in payload generic header must all be zero + private static final byte PAYLOAD_HEADER_CRITICAL_BIT_UNSET = 0; /** Length of a generic IKE payload header */ public static final int GENERIC_HEADER_LENGTH = 4; @@ -108,12 +111,34 @@ public abstract class IkePayload { } /** - * Encode payload to byte array. + * Encode generic payload header to ByteBuffer. * * @param nextPayload type of payload that follows this payload. - * @return encoded payload + * @param payloadLength length of the entire payload + * @param byteBuffer destination ByteBuffer that stores encoded payload header */ - abstract byte[] encode(@PayloadType int nextPayload); + protected void encodePayloadHeaderToByteBuffer( + @PayloadType int nextPayload, int payloadLength, ByteBuffer byteBuffer) { + byteBuffer + .put((byte) nextPayload) + .put(PAYLOAD_HEADER_CRITICAL_BIT_UNSET) + .putShort((short) payloadLength); + } + + /** + * Encode payload to ByteBuffer. + * + * @param nextPayload type of payload that follows this payload. + * @param byteBuffer destination ByteBuffer that stores encoded payload. + */ + protected abstract void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer); + + /** + * Get entire payload length. + * + * @return entire payload length. + */ + protected abstract int getPayloadLength(); /** * Return the payload type as a String. diff --git a/src/java/com/android/ike/ikev2/message/IkeSaPayload.java b/src/java/com/android/ike/ikev2/message/IkeSaPayload.java index 8734797f..e3ded360 100644 --- a/src/java/com/android/ike/ikev2/message/IkeSaPayload.java +++ b/src/java/com/android/ike/ikev2/message/IkeSaPayload.java @@ -299,19 +299,31 @@ public final class IkeSaPayload extends IkePayload { } /** - * Encode SA payload to byte array. + * Encode SA payload to ByteBUffer. * * @param nextPayload type of payload that follows this payload. - * @return encoded SA payload + * @param byteBuffer destination ByteBuffer that stores encoded payload. */ @Override - byte[] encode(@PayloadType int nextPayload) { + protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) { throw new UnsupportedOperationException( "It is not supported to encode a " + getTypeString()); // TODO: Implement encoding SA payload. } /** + * Get entire payload length. + * + * @return entire payload length. + */ + @Override + protected int getPayloadLength() { + throw new UnsupportedOperationException( + "It is not supported to get payload length of " + getTypeString()); + // TODO: Implement this method for SA payload. + } + + /** * Return the payload type as a String. * * @return the payload type as a String. diff --git a/src/java/com/android/ike/ikev2/message/IkeUnsupportedPayload.java b/src/java/com/android/ike/ikev2/message/IkeUnsupportedPayload.java index 17c07702..4b581cc8 100644 --- a/src/java/com/android/ike/ikev2/message/IkeUnsupportedPayload.java +++ b/src/java/com/android/ike/ikev2/message/IkeUnsupportedPayload.java @@ -16,6 +16,7 @@ package com.android.ike.ikev2.message; +import java.nio.ByteBuffer; /** * IkeUnsupportedPayload represents anunsupported payload. * @@ -41,12 +42,23 @@ final class IkeUnsupportedPayload extends IkePayload { * @throws UnsupportedOperationException for this payload. */ @Override - byte[] encode(@PayloadType int nextPayload) { + protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) { throw new UnsupportedOperationException( "It is not supported to encode a " + getTypeString()); } /** + * Throw an Exception when trying to get payload length + * + * @throws UnsupportedOperationException for this payload. + */ + @Override + protected int getPayloadLength() { + throw new UnsupportedOperationException( + "It is not supported to get payload length of " + getTypeString()); + } + + /** * Return the payload type as a String. * * @return the payload type as a String. diff --git a/src/java/com/android/ike/ikev2/message/IkeVendorPayload.java b/src/java/com/android/ike/ikev2/message/IkeVendorPayload.java index 5fabfc1a..ee224e9a 100644 --- a/src/java/com/android/ike/ikev2/message/IkeVendorPayload.java +++ b/src/java/com/android/ike/ikev2/message/IkeVendorPayload.java @@ -16,6 +16,8 @@ package com.android.ike.ikev2.message; +import java.nio.ByteBuffer; + /** * IkeVendorPayload represents a Vendor ID payload * @@ -47,12 +49,22 @@ public final class IkeVendorPayload extends IkePayload { * @throws UnsupportedOperationException for this payload. */ @Override - byte[] encode(@PayloadType int nextPayload) { + protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) { throw new UnsupportedOperationException( "It is not supported to encode a " + getTypeString()); } /** + * Get entire payload length. + * + * @return entire payload length. + */ + @Override + protected int getPayloadLength() { + return GENERIC_HEADER_LENGTH + vendorId.length; + } + + /** * Return the payload type as a String. * * @return the payload type as a String. diff --git a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeMessageTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeMessageTest.java index b7ecc3d6..05c59607 100644 --- a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeMessageTest.java +++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeMessageTest.java @@ -29,6 +29,8 @@ import com.android.ike.ikev2.exceptions.UnsupportedCriticalPayloadException; import org.junit.Before; import org.junit.Test; +import java.nio.ByteBuffer; + public final class IkeMessageTest { private static final String IKE_SA_INIT_RAW_PACKET = "8f54bf6d8b48e6e100000000000000002120220800000000" @@ -80,12 +82,18 @@ public final class IkeMessageTest { } @Override - byte[] encode(@PayloadType int nextPayload) { + protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) { throw new UnsupportedOperationException( "It is not supported to encode " + getTypeString()); } @Override + protected int getPayloadLength() { + throw new UnsupportedOperationException( + "It is not supported to get payload length of " + getTypeString()); + } + + @Override public String getTypeString() { return "Test Payload"; } diff --git a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeNoncePayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeNoncePayloadTest.java new file mode 100644 index 00000000..a15507c5 --- /dev/null +++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeNoncePayloadTest.java @@ -0,0 +1,47 @@ +/* + * 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 org.junit.Test; + +import java.nio.ByteBuffer; + +public final class IkeNoncePayloadTest { + + private static final String NONCE_PAYLOAD_RAW_HEX_STRING = + "29000024c39b7f368f4681b89fa9b7be6465abd7c5f68b6ed5d3b4c72cb4240eb5c46412"; + private static final String NONCE_DATA_RAW_HEX_STRING = + "c39b7f368f4681b89fa9b7be6465abd7c5f68b6ed5d3b4c72cb4240eb5c46412"; + + @IkePayload.PayloadType + private static final int NEXT_PAYLOAD_TYPE = IkePayload.PAYLOAD_TYPE_NOTIFY; + + @Test + public void testEncode() throws Exception { + byte[] inputPacket = TestUtils.hexStringToByteArray(NONCE_DATA_RAW_HEX_STRING); + IkeNoncePayload payload = new IkeNoncePayload(false, inputPacket); + + ByteBuffer byteBuffer = ByteBuffer.allocate(payload.getPayloadLength()); + payload.encodeToByteBuffer(NEXT_PAYLOAD_TYPE, byteBuffer); + + byte[] expectedNoncePayload = + TestUtils.hexStringToByteArray(NONCE_PAYLOAD_RAW_HEX_STRING); + assertArrayEquals(expectedNoncePayload, byteBuffer.array()); + } +} diff --git a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeNotifyPayloadTest.java b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeNotifyPayloadTest.java index 4968826c..382f04b1 100644 --- a/tests/iketests/src/java/com/android/ike/ikev2/message/IkeNotifyPayloadTest.java +++ b/tests/iketests/src/java/com/android/ike/ikev2/message/IkeNotifyPayloadTest.java @@ -33,7 +33,6 @@ public final class IkeNotifyPayloadTest { private static final int EXPECTED_NOTIFY_TYPE = IkeNotifyPayload.NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP; - private static final int EXPECTED_SPI = 0; private static final int EXPECTED_NOTIFY_DATA_LEN = 20; private static final int POS_PROTOCOL_ID = 0; |