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.message; 18 19 import android.annotation.Nullable; 20 import android.net.ipsec.ike.exceptions.IkeProtocolException; 21 import android.net.ipsec.ike.exceptions.InvalidSyntaxException; 22 23 import com.android.internal.annotations.VisibleForTesting; 24 import com.android.internal.net.ipsec.ike.crypto.IkeCipher; 25 import com.android.internal.net.ipsec.ike.crypto.IkeMacIntegrity; 26 27 import java.nio.ByteBuffer; 28 import java.security.GeneralSecurityException; 29 30 /** 31 * IkeSkfPayload represents an Encrypted and Authenticated Fragment Payload. 32 * 33 * @see <a href="https://tools.ietf.org/html/rfc7383">RFC 7383, Internet Key Exchange Protocol 34 * Version 2 (IKEv2) Message Fragmentation</a> 35 */ 36 public final class IkeSkfPayload extends IkeSkPayload { 37 public static final int SKF_HEADER_LEN = 4; 38 39 /** Current Fragment message number, starting from 1 */ 40 public final int fragmentNum; 41 /** Number of Fragment messages into which the original message was divided */ 42 public final int totalFragments; 43 44 /** 45 * Construct an instance of IkeSkfPayload by authenticating and decrypting an incoming packet. 46 * 47 * <p>SKF Payload with invalid fragmentNum or invalid totalFragments, or cannot be authenticated 48 * or decrypted MUST be discarded 49 * 50 * @param critical indicates if it is a critical payload. 51 * @param message the byte array contains the whole IKE message. 52 * @param integrityMac the negotiated integrity algorithm. 53 * @param decryptCipher the negotiated encryption algorithm. 54 * @param integrityKey the negotiated integrity algorithm key. 55 * @param decryptionKey the negotiated decryption key. 56 */ IkeSkfPayload( boolean critical, byte[] message, @Nullable IkeMacIntegrity integrityMac, IkeCipher decryptCipher, byte[] integrityKey, byte[] decryptionKey)57 IkeSkfPayload( 58 boolean critical, 59 byte[] message, 60 @Nullable IkeMacIntegrity integrityMac, 61 IkeCipher decryptCipher, 62 byte[] integrityKey, 63 byte[] decryptionKey) 64 throws IkeProtocolException, GeneralSecurityException { 65 super( 66 true /*isSkf*/, 67 critical, 68 IkeHeader.IKE_HEADER_LENGTH + GENERIC_HEADER_LENGTH + SKF_HEADER_LEN, 69 message, 70 integrityMac, 71 decryptCipher, 72 integrityKey, 73 decryptionKey); 74 75 // TODO: Support constructing IkeEncryptedPayloadBody using AEAD. 76 77 ByteBuffer inputBuffer = ByteBuffer.wrap(message); 78 inputBuffer.get(new byte[IkeHeader.IKE_HEADER_LENGTH + GENERIC_HEADER_LENGTH]); 79 80 fragmentNum = Short.toUnsignedInt(inputBuffer.getShort()); 81 totalFragments = Short.toUnsignedInt(inputBuffer.getShort()); 82 83 if (fragmentNum < 1 || totalFragments < 1 || fragmentNum > totalFragments) { 84 throw new InvalidSyntaxException( 85 "Received invalid Fragment Number or Total Fragments Number. Fragment Number: " 86 + fragmentNum 87 + " Total Fragments: " 88 + totalFragments); 89 } 90 } 91 92 /** 93 * Construct an instance of IkeSkfPayload for building outbound packet. 94 * 95 * @param ikeHeader the IKE header. 96 * @param firstPayloadType the type of first payload nested in SkPayload. 97 * @param unencryptedPayloads the encoded payload list to protect. 98 * @param integrityMac the negotiated integrity algorithm. 99 * @param encryptCipher the negotiated encryption algorithm. 100 * @param integrityKey the negotiated integrity algorithm key. 101 * @param encryptionKey the negotiated encryption key. 102 */ IkeSkfPayload( IkeHeader ikeHeader, @PayloadType int firstPayloadType, byte[] unencryptedPayloads, @Nullable IkeMacIntegrity integrityMac, IkeCipher encryptCipher, byte[] integrityKey, byte[] encryptionKey, int fragNum, int totalFrags)103 IkeSkfPayload( 104 IkeHeader ikeHeader, 105 @PayloadType int firstPayloadType, 106 byte[] unencryptedPayloads, 107 @Nullable IkeMacIntegrity integrityMac, 108 IkeCipher encryptCipher, 109 byte[] integrityKey, 110 byte[] encryptionKey, 111 int fragNum, 112 int totalFrags) { 113 super( 114 ikeHeader, 115 firstPayloadType, 116 encodeSkfHeader(fragNum, totalFrags), 117 unencryptedPayloads, 118 integrityMac, 119 encryptCipher, 120 integrityKey, 121 encryptionKey); 122 fragmentNum = fragNum; 123 totalFragments = totalFrags; 124 } 125 126 /** Construct an instance of IkeSkfPayload for testing. */ 127 @VisibleForTesting IkeSkfPayload(IkeEncryptedPayloadBody encryptedPayloadBody, int fragNum, int totalFrags)128 IkeSkfPayload(IkeEncryptedPayloadBody encryptedPayloadBody, int fragNum, int totalFrags) { 129 super(true /*isSkf*/, encryptedPayloadBody); 130 fragmentNum = fragNum; 131 totalFragments = totalFrags; 132 } 133 134 @VisibleForTesting encodeSkfHeader(int fragNum, int totalFrags)135 static byte[] encodeSkfHeader(int fragNum, int totalFrags) { 136 ByteBuffer buffer = ByteBuffer.allocate(SKF_HEADER_LEN); 137 buffer.putShort((short) fragNum).putShort((short) totalFrags); 138 return buffer.array(); 139 } 140 141 /** 142 * Encode this payload to a ByteBuffer. 143 * 144 * @param nextPayload type of payload that follows this payload. 145 * @param byteBuffer destination ByteBuffer that stores encoded payload. 146 */ 147 @Override encodeToByteBuffer(@ayloadType int nextPayload, ByteBuffer byteBuffer)148 protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) { 149 encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer); 150 byteBuffer 151 .putShort((short) fragmentNum) 152 .putShort((short) totalFragments) 153 .put(mIkeEncryptedPayloadBody.encode()); 154 } 155 156 /** 157 * Get entire payload length. 158 * 159 * @return entire payload length. 160 */ 161 @Override getPayloadLength()162 protected int getPayloadLength() { 163 return GENERIC_HEADER_LENGTH + SKF_HEADER_LEN + mIkeEncryptedPayloadBody.getLength(); 164 } 165 166 /** 167 * Return the payload type as a String. 168 * 169 * @return the payload type as a String. 170 */ 171 @Override getTypeString()172 public String getTypeString() { 173 return "SKF"; 174 } 175 } 176