blob: 62527045c4841e6a9c872723e59e0704da2a5bf3 [file] [log] [blame]
Alan Viverette3da604b2020-06-10 18:34:39 +00001/*
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
17package com.android.internal.net.ipsec.ike.crypto;
18
19import android.net.ipsec.ike.SaProposal;
20
21import com.android.internal.net.crypto.KeyGenerationUtils;
22import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform;
23
24import java.nio.ByteBuffer;
25import java.util.Arrays;
26
27import javax.crypto.Cipher;
28import 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 */
43public 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
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 */
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 */
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 // Use 8 bytes each from initiator and responder nonces as per RFC 7296
110 keyBuffer
111 .put(Arrays.copyOfRange(nonceInit, 0, 8))
112 .put(Arrays.copyOfRange(nonceResp, 0, 8));
113 } else {
114 keyBuffer = ByteBuffer.allocate(nonceInit.length + nonceResp.length);
115 keyBuffer.put(nonceInit).put(nonceResp);
116 }
117
118 return signBytes(keyBuffer.array(), sharedDhKey);
119 }
120
121 /**
122 * Generates a rekey SKEYSEED based on the nonces and shared DH secret.
123 *
124 * @param skD the secret for deriving new keys
125 * @param nonceInit the IKE initiator nonce.
126 * @param nonceResp the IKE responder nonce.
127 * @param sharedDhKey the DH shared key.
128 * @return the byte array of SKEYSEED.
129 */
130 public byte[] generateRekeyedSKeySeed(
131 byte[] skD, byte[] nonceInit, byte[] nonceResp, byte[] sharedDhKey) {
132 ByteBuffer dataToSign = null;
133 if (getAlgorithmId() == SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC) {
134 dataToSign =
135 ByteBuffer.allocate(
136 sharedDhKey.length + PSEUDORANDOM_FUNCTION_AES128_XCBC_KEY_LEN);
137 // Use 8 bytes each from initiator and responder nonces as per RFC 7296
138 dataToSign
139 .put(sharedDhKey)
140 .put(Arrays.copyOfRange(nonceInit, 0, 8))
141 .put(Arrays.copyOfRange(nonceResp, 0, 8));
142 } else {
143 dataToSign =
144 ByteBuffer.allocate(sharedDhKey.length + nonceInit.length + nonceResp.length);
145 dataToSign.put(sharedDhKey).put(nonceInit).put(nonceResp);
146 }
147
148 return signBytes(skD, dataToSign.array());
149 }
150
151 /**
152 * Derives keying materials from IKE/Child SA negotiation.
153 *
154 * <p>prf+(K, S) outputs a pseudorandom stream by using negotiated PRF iteratively. In this way
155 * it can generate long enough keying material containing all the keys for this IKE/Child SA.
156 *
157 * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.13">RFC 7296 Internet Key
158 * Exchange Protocol Version 2 (IKEv2) 2.13. Generating Keying Material </a>
159 * @param keyBytes the key to sign data. SKEYSEED is used for generating KEYMAT for IKE SA. SK_d
160 * is used for generating KEYMAT for Child SA.
161 * @param dataToSign the data to be signed.
162 * @param keyMaterialLen the length of keying materials.
163 * @return the byte array of keying materials
164 */
165 public byte[] generateKeyMat(byte[] keyBytes, byte[] dataToSign, int keyMaterialLen) {
166 return KeyGenerationUtils.prfPlus(this, keyBytes, dataToSign, keyMaterialLen);
167 }
168
169 /**
170 * Returns algorithm type as a String.
171 *
172 * @return the algorithm type as a String.
173 */
174 @Override
175 public String getTypeString() {
176 return "Pseudorandom Function";
177 }
178}