1/*
2 * Copyright (C) 2017 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 */
16package android.net;
17
18import android.annotation.StringDef;
19import android.os.Parcel;
20import android.os.Parcelable;
21import java.lang.annotation.Retention;
22import java.lang.annotation.RetentionPolicy;
23
24/**
25 * IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to
26 * RFC 4301.
27 *
28 * @hide
29 */
30public final class IpSecAlgorithm implements Parcelable {
31
32    /**
33     * AES-CBC Encryption/Ciphering Algorithm.
34     *
35     * <p>Valid lengths for this key are {128, 192, 256}.
36     */
37    public static final String CRYPT_AES_CBC = "cbc(aes)";
38
39    /**
40     * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in new
41     * applications and is provided for legacy compatibility with 3gpp infrastructure.
42     *
43     * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 128.
44     */
45    public static final String AUTH_HMAC_MD5 = "hmac(md5)";
46
47    /**
48     * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in
49     * new applications and is provided for legacy compatibility with 3gpp infrastructure.
50     *
51     * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 160.
52     */
53    public static final String AUTH_HMAC_SHA1 = "hmac(sha1)";
54
55    /**
56     * SHA256 HMAC Authentication/Integrity Algorithm.
57     *
58     * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 256.
59     */
60    public static final String AUTH_HMAC_SHA256 = "hmac(sha256)";
61
62    /**
63     * SHA384 HMAC Authentication/Integrity Algorithm.
64     *
65     * <p>Valid truncation lengths are multiples of 8 bits from 192 to (default) 384.
66     */
67    public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
68    /**
69     * SHA512 HMAC Authentication/Integrity Algorithm
70     *
71     * <p>Valid truncation lengths are multiples of 8 bits from 256 to (default) 512.
72     */
73    public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
74
75    /** @hide */
76    @StringDef({
77        CRYPT_AES_CBC,
78        AUTH_HMAC_MD5,
79        AUTH_HMAC_SHA1,
80        AUTH_HMAC_SHA256,
81        AUTH_HMAC_SHA512
82    })
83    @Retention(RetentionPolicy.SOURCE)
84    public @interface AlgorithmName {}
85
86    private final String mName;
87    private final byte[] mKey;
88    private final int mTruncLenBits;
89
90    /**
91     * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the
92     * algorithm
93     *
94     * @param algorithm type for IpSec.
95     * @param key non-null Key padded to a multiple of 8 bits.
96     */
97    public IpSecAlgorithm(String algorithm, byte[] key) {
98        this(algorithm, key, key.length * 8);
99    }
100
101    /**
102     * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the
103     * algorithm
104     *
105     * @param algoName precise name of the algorithm to be used.
106     * @param key non-null Key padded to a multiple of 8 bits.
107     * @param truncLenBits the number of bits of output hash to use; only meaningful for
108     *     Authentication.
109     */
110    public IpSecAlgorithm(@AlgorithmName String algoName, byte[] key, int truncLenBits) {
111        if (!isTruncationLengthValid(algoName, truncLenBits)) {
112            throw new IllegalArgumentException("Unknown algorithm or invalid length");
113        }
114        mName = algoName;
115        mKey = key.clone();
116        mTruncLenBits = Math.min(truncLenBits, key.length * 8);
117    }
118
119    /** Retrieve the algorithm name */
120    public String getName() {
121        return mName;
122    }
123
124    /** Retrieve the key for this algorithm */
125    public byte[] getKey() {
126        return mKey.clone();
127    }
128
129    /**
130     * Retrieve the truncation length, in bits, for the key in this algo. By default this will be
131     * the length in bits of the key.
132     */
133    public int getTruncationLengthBits() {
134        return mTruncLenBits;
135    }
136
137    /* Parcelable Implementation */
138    public int describeContents() {
139        return 0;
140    }
141
142    /** Write to parcel */
143    public void writeToParcel(Parcel out, int flags) {
144        out.writeString(mName);
145        out.writeByteArray(mKey);
146        out.writeInt(mTruncLenBits);
147    }
148
149    /** Parcelable Creator */
150    public static final Parcelable.Creator<IpSecAlgorithm> CREATOR =
151            new Parcelable.Creator<IpSecAlgorithm>() {
152                public IpSecAlgorithm createFromParcel(Parcel in) {
153                    return new IpSecAlgorithm(in);
154                }
155
156                public IpSecAlgorithm[] newArray(int size) {
157                    return new IpSecAlgorithm[size];
158                }
159            };
160
161    private IpSecAlgorithm(Parcel in) {
162        mName = in.readString();
163        mKey = in.createByteArray();
164        mTruncLenBits = in.readInt();
165    }
166
167    private static boolean isTruncationLengthValid(String algo, int truncLenBits) {
168        switch (algo) {
169            case CRYPT_AES_CBC:
170                return (truncLenBits == 128 || truncLenBits == 192 || truncLenBits == 256);
171            case AUTH_HMAC_MD5:
172                return (truncLenBits >= 96 && truncLenBits <= 128);
173            case AUTH_HMAC_SHA1:
174                return (truncLenBits >= 96 && truncLenBits <= 160);
175            case AUTH_HMAC_SHA256:
176                return (truncLenBits >= 96 && truncLenBits <= 256);
177            case AUTH_HMAC_SHA384:
178                return (truncLenBits >= 192 && truncLenBits <= 384);
179            case AUTH_HMAC_SHA512:
180                return (truncLenBits >= 256 && truncLenBits <= 512);
181            default:
182                return false;
183        }
184    }
185};
186