• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96;
20 
21 import android.annotation.Nullable;
22 import android.net.IpSecAlgorithm;
23 import android.net.ipsec.ike.SaProposal;
24 import android.util.SparseArray;
25 
26 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
27 
28 import java.security.GeneralSecurityException;
29 import java.util.Arrays;
30 
31 import javax.crypto.Cipher;
32 import javax.crypto.Mac;
33 
34 /**
35  * IkeMacIntegrity represents a negotiated integrity algorithm.
36  *
37  * <p>For integrity algorithms based on encryption algorithm, all operations will be done by a
38  * {@link Cipher}. Otherwise, all operations will be done by a {@link Mac}.
39  *
40  * <p>@see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296, Internet Key
41  * Exchange Protocol Version 2 (IKEv2)</a>
42  */
43 public class IkeMacIntegrity extends IkeMac {
44     // Map IKE algorithm numbers to IPsec algorithm names
45     private static final SparseArray<String> IKE_ALGO_TO_IPSEC_ALGO;
46 
47     static {
48         IKE_ALGO_TO_IPSEC_ALGO = new SparseArray<>();
IKE_ALGO_TO_IPSEC_ALGO.put( SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96, IpSecAlgorithm.AUTH_HMAC_SHA1)49         IKE_ALGO_TO_IPSEC_ALGO.put(
50                 SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96, IpSecAlgorithm.AUTH_HMAC_SHA1);
IKE_ALGO_TO_IPSEC_ALGO.put( SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96, IpSecAlgorithm.AUTH_AES_XCBC)51         IKE_ALGO_TO_IPSEC_ALGO.put(
52                 SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96, IpSecAlgorithm.AUTH_AES_XCBC);
IKE_ALGO_TO_IPSEC_ALGO.put( SaProposal.INTEGRITY_ALGORITHM_AES_CMAC_96, IpSecAlgorithm.AUTH_AES_CMAC)53         IKE_ALGO_TO_IPSEC_ALGO.put(
54                 SaProposal.INTEGRITY_ALGORITHM_AES_CMAC_96, IpSecAlgorithm.AUTH_AES_CMAC);
IKE_ALGO_TO_IPSEC_ALGO.put( SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, IpSecAlgorithm.AUTH_HMAC_SHA256)55         IKE_ALGO_TO_IPSEC_ALGO.put(
56                 SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, IpSecAlgorithm.AUTH_HMAC_SHA256);
IKE_ALGO_TO_IPSEC_ALGO.put( SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, IpSecAlgorithm.AUTH_HMAC_SHA384)57         IKE_ALGO_TO_IPSEC_ALGO.put(
58                 SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, IpSecAlgorithm.AUTH_HMAC_SHA384);
IKE_ALGO_TO_IPSEC_ALGO.put( SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, IpSecAlgorithm.AUTH_HMAC_SHA512)59         IKE_ALGO_TO_IPSEC_ALGO.put(
60                 SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, IpSecAlgorithm.AUTH_HMAC_SHA512);
61     }
62 
63     private final int mChecksumLength;
64 
IkeMacIntegrity( @aProposal.IntegrityAlgorithm int algorithmId, int keyLength, String algorithmName, boolean isJceSupported, int checksumLength)65     private IkeMacIntegrity(
66             @SaProposal.IntegrityAlgorithm int algorithmId,
67             int keyLength,
68             String algorithmName,
69             boolean isJceSupported,
70             int checksumLength) {
71         super(algorithmId, keyLength, algorithmName, isJceSupported);
72         mChecksumLength = checksumLength;
73     }
74 
75     /**
76      * Construct an instance of IkeMacIntegrity.
77      *
78      * @param integrityTransform the valid negotiated IntegrityTransform.
79      * @return an instance of IkeMacIntegrity.
80      */
create(IntegrityTransform integrityTransform)81     public static IkeMacIntegrity create(IntegrityTransform integrityTransform) {
82         int algorithmId = integrityTransform.id;
83 
84         int keyLength = 0;
85         String algorithmName = "";
86         boolean isJceSupported = true;
87         int checksumLength = 0;
88 
89         switch (algorithmId) {
90             case SaProposal.INTEGRITY_ALGORITHM_NONE:
91                 throw new IllegalArgumentException("Integrity algorithm is not found.");
92             case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96:
93                 keyLength = 20;
94                 algorithmName = "HmacSHA1";
95                 checksumLength = 12;
96                 break;
97             case SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96:
98                 keyLength = 16;
99                 isJceSupported = false;
100                 algorithmName = ALGO_NAME_JCE_UNSUPPORTED;
101                 checksumLength = 12;
102                 break;
103             case SaProposal.INTEGRITY_ALGORITHM_AES_CMAC_96:
104                 keyLength = 16;
105                 algorithmName = "AESCMAC";
106                 checksumLength = 12;
107                 break;
108             case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128:
109                 keyLength = 32;
110                 algorithmName = "HmacSHA256";
111                 checksumLength = 16;
112                 break;
113             case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192:
114                 keyLength = 48;
115                 algorithmName = "HmacSHA384";
116                 checksumLength = 24;
117                 break;
118             case SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256:
119                 keyLength = 64;
120                 algorithmName = "HmacSHA512";
121                 checksumLength = 32;
122                 break;
123             default:
124                 throw new IllegalArgumentException(
125                         "Unrecognized Integrity Algorithm ID: " + algorithmId);
126         }
127 
128         return new IkeMacIntegrity(
129                 algorithmId, keyLength, algorithmName, isJceSupported, checksumLength);
130     }
131 
132     @Override
signBytes(byte[] keyBytes, byte[] dataToSign)133     public byte[] signBytes(byte[] keyBytes, byte[] dataToSign) {
134         if (getAlgorithmId() == INTEGRITY_ALGORITHM_AES_XCBC_96) {
135             try {
136                 return new AesXCbcImpl().mac(keyBytes, dataToSign, true /*needTruncation*/);
137             } catch (GeneralSecurityException | IllegalStateException e) {
138                 throw new IllegalArgumentException("Failed to generate MAC: ", e);
139             }
140         } else {
141             return super.signBytes(keyBytes, dataToSign);
142         }
143     }
144 
145     /**
146      * Gets integrity checksum length (in bytes).
147      *
148      * <p>IKE defines a fixed truncation length for each integirty algorithm as its checksum length.
149      *
150      * @return the integrity checksum length (in bytes).
151      */
getChecksumLen()152     public int getChecksumLen() {
153         return mChecksumLength;
154     }
155 
156     /**
157      * Signs the bytes to generate an integrity checksum.
158      *
159      * @param keyBytes the negotiated integrity key.
160      * @param dataToAuthenticate the data to authenticate.
161      * @return the integrity checksum.
162      */
generateChecksum(byte[] keyBytes, byte[] dataToAuthenticate)163     public byte[] generateChecksum(byte[] keyBytes, byte[] dataToAuthenticate) {
164         if (getKeyLength() != keyBytes.length) {
165             throw new IllegalArgumentException(
166                     "Expected key length: "
167                             + getKeyLength()
168                             + " Received key length: "
169                             + keyBytes.length);
170         }
171 
172         byte[] signedBytes = signBytes(keyBytes, dataToAuthenticate);
173         return Arrays.copyOfRange(signedBytes, 0, mChecksumLength);
174     }
175 
176     /**
177      * Returns the IPsec algorithm name defined in {@link IpSecAlgorithm} given the IKE algorithm
178      * ID.
179      *
180      * <p>Returns null if there is no corresponding IPsec algorithm given the IKE algorithm ID.
181      */
182     @Nullable
getIpSecAlgorithmName(int ikeAlgoId)183     public static String getIpSecAlgorithmName(int ikeAlgoId) {
184         return IKE_ALGO_TO_IPSEC_ALGO.get(ikeAlgoId);
185     }
186 
187     /**
188      * Build IpSecAlgorithm from this IkeMacIntegrity.
189      *
190      * <p>Build IpSecAlgorithm that represents the same integrity algorithm with this
191      * IkeMacIntegrity instance with provided integrity key.
192      *
193      * @param key the integrity key in byte array.
194      * @return the IpSecAlgorithm.
195      */
buildIpSecAlgorithmWithKey(byte[] key)196     public IpSecAlgorithm buildIpSecAlgorithmWithKey(byte[] key) {
197         if (key.length != getKeyLength()) {
198             throw new IllegalArgumentException(
199                     "Expected key with length of : "
200                             + getKeyLength()
201                             + " Received key with length of : "
202                             + key.length);
203         }
204         if (getIpSecAlgorithmName(getAlgorithmId()) == null) {
205             throw new IllegalStateException(
206                     "Unsupported algorithm " + getAlgorithmId() + " in IPsec");
207         }
208         return new IpSecAlgorithm(
209                 getIpSecAlgorithmName(getAlgorithmId()), key, mChecksumLength * 8);
210     }
211 
212     /**
213      * Returns algorithm type as a String.
214      *
215      * @return the algorithm type as a String.
216      */
217     @Override
getTypeString()218     public String getTypeString() {
219         return "Integrity Algorithm.";
220     }
221 }
222