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.ipsec.ike.SaProposal; 20 21 import com.android.internal.net.crypto.KeyGenerationUtils; 22 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform; 23 24 import java.nio.ByteBuffer; 25 import java.util.Arrays; 26 27 import javax.crypto.Cipher; 28 import javax.crypto.Mac; 29 30 /** 31 * IkeMacPrf represents a negotiated pseudorandom function. 32 * 33 * <p>Pseudorandom function is usually used for IKE SA authentication and generating keying 34 * materials. 35 * 36 * <p>For pseudorandom functions based on integrity algorithms, all operations will be done by a 37 * {@link Mac}. For pseudorandom functions based on encryption algorithms, all operations will be 38 * done by a {@link Cipher}. 39 * 40 * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296, Internet Key Exchange 41 * Protocol Version 2 (IKEv2)</a> 42 */ 43 public class IkeMacPrf extends IkeMac { 44 // STOPSHIP: b/130190639 Catch unchecked exceptions, notify users and close the IKE session. 45 private static final int PSEUDORANDOM_FUNCTION_AES128_XCBC_KEY_LEN = 16; 46 IkeMacPrf( @aProposal.PseudorandomFunction int algorithmId, int keyLength, String algorithmName, boolean isEncryptAlgo)47 private IkeMacPrf( 48 @SaProposal.PseudorandomFunction int algorithmId, 49 int keyLength, 50 String algorithmName, 51 boolean isEncryptAlgo) { 52 super(algorithmId, keyLength, algorithmName, isEncryptAlgo); 53 } 54 55 /** 56 * Construct an instance of IkeMacPrf. 57 * 58 * @param prfTransform the valid negotiated PrfTransform. 59 * @return an instance of IkeMacPrf. 60 */ create(PrfTransform prfTransform)61 public static IkeMacPrf create(PrfTransform prfTransform) { 62 int algorithmId = prfTransform.id; 63 64 int keyLength = 0; 65 String algorithmName = ""; 66 boolean isEncryptAlgo = false; 67 68 switch (algorithmId) { 69 case SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1: 70 keyLength = 20; 71 algorithmName = "HmacSHA1"; 72 break; 73 case SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC: 74 keyLength = 16; 75 isEncryptAlgo = true; 76 algorithmName = "AES_128/CBC/NoPadding"; 77 break; 78 case SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256: 79 keyLength = 32; 80 algorithmName = "HmacSHA256"; 81 break; 82 case SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384: 83 keyLength = 48; 84 algorithmName = "HmacSHA384"; 85 break; 86 case SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512: 87 keyLength = 64; 88 algorithmName = "HmacSHA512"; 89 break; 90 default: 91 throw new IllegalArgumentException("Unrecognized PRF ID: " + algorithmId); 92 } 93 94 return new IkeMacPrf(algorithmId, keyLength, algorithmName, isEncryptAlgo); 95 } 96 97 /** 98 * Generates SKEYSEED based on the nonces and shared DH secret. 99 * 100 * @param nonceInit the IKE initiator nonce. 101 * @param nonceResp the IKE responder nonce. 102 * @param sharedDhKey the DH shared key. 103 * @return the byte array of SKEYSEED. 104 */ generateSKeySeed(byte[] nonceInit, byte[] nonceResp, byte[] sharedDhKey)105 public byte[] generateSKeySeed(byte[] nonceInit, byte[] nonceResp, byte[] sharedDhKey) { 106 ByteBuffer keyBuffer = null; 107 if (getAlgorithmId() == SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC) { 108 keyBuffer = ByteBuffer.allocate(PSEUDORANDOM_FUNCTION_AES128_XCBC_KEY_LEN); 109 // When generating initial keys, use 8 bytes each from initiator and responder nonces as 110 // per RFC 7296 111 keyBuffer 112 .put(Arrays.copyOfRange(nonceInit, 0, 8)) 113 .put(Arrays.copyOfRange(nonceResp, 0, 8)); 114 } else { 115 keyBuffer = ByteBuffer.allocate(nonceInit.length + nonceResp.length); 116 keyBuffer.put(nonceInit).put(nonceResp); 117 } 118 119 return signBytes(keyBuffer.array(), sharedDhKey); 120 } 121 122 /** 123 * Generates a rekey SKEYSEED based on the nonces and shared DH secret. 124 * 125 * @param skD the secret for deriving new keys 126 * @param nonceInit the IKE initiator nonce. 127 * @param nonceResp the IKE responder nonce. 128 * @param sharedDhKey the DH shared key. 129 * @return the byte array of SKEYSEED. 130 */ generateRekeyedSKeySeed( byte[] skD, byte[] nonceInit, byte[] nonceResp, byte[] sharedDhKey)131 public byte[] generateRekeyedSKeySeed( 132 byte[] skD, byte[] nonceInit, byte[] nonceResp, byte[] sharedDhKey) { 133 ByteBuffer dataToSign = 134 ByteBuffer.allocate(sharedDhKey.length + nonceInit.length + nonceResp.length); 135 dataToSign.put(sharedDhKey).put(nonceInit).put(nonceResp); 136 137 return signBytes(skD, dataToSign.array()); 138 } 139 140 /** 141 * Derives keying materials from IKE/Child SA negotiation. 142 * 143 * <p>prf+(K, S) outputs a pseudorandom stream by using negotiated PRF iteratively. In this way 144 * it can generate long enough keying material containing all the keys for this IKE/Child SA. 145 * 146 * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.13">RFC 7296 Internet Key 147 * Exchange Protocol Version 2 (IKEv2) 2.13. Generating Keying Material </a> 148 * @param keyBytes the key to sign data. SKEYSEED is used for generating KEYMAT for IKE SA. SK_d 149 * is used for generating KEYMAT for Child SA. 150 * @param dataToSign the data to be signed. 151 * @param keyMaterialLen the length of keying materials. 152 * @return the byte array of keying materials 153 */ generateKeyMat(byte[] keyBytes, byte[] dataToSign, int keyMaterialLen)154 public byte[] generateKeyMat(byte[] keyBytes, byte[] dataToSign, int keyMaterialLen) { 155 return KeyGenerationUtils.prfPlus(this, keyBytes, dataToSign, keyMaterialLen); 156 } 157 158 /** 159 * Returns algorithm type as a String. 160 * 161 * @return the algorithm type as a String. 162 */ 163 @Override getTypeString()164 public String getTypeString() { 165 return "Pseudorandom Function"; 166 } 167 } 168