1 /*
2  * Copyright (C) 2023 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.server.nearby.presence;
18 
19 import android.annotation.IntDef;
20 import android.annotation.Nullable;
21 import android.nearby.DataElement;
22 
23 import androidx.annotation.NonNull;
24 
25 import com.android.internal.util.Preconditions;
26 import com.android.server.nearby.util.ArrayUtils;
27 
28 import java.util.Arrays;
29 
30 /**
31  * Data Element that indicates the presence of extended 16 bytes salt instead of 2 byte salt and to
32  * indicate which encoding scheme (MIC tag or Signature) is used for a section. If present, it must
33  * be the first DE in a section.
34  */
35 public class EncryptionInfo {
36 
37     @IntDef({EncodingScheme.MIC, EncodingScheme.SIGNATURE})
38     public @interface EncodingScheme {
39         int MIC = 0;
40         int SIGNATURE = 1;
41     }
42 
43     // 1st byte : encryption scheme
44     // 2nd to 17th bytes: salt
45     public static final int ENCRYPTION_INFO_LENGTH = 17;
46     private static final int ENCODING_SCHEME_MASK = 0b01111000;
47     private static final int ENCODING_SCHEME_OFFSET = 3;
48     @EncodingScheme
49     private final int mEncodingScheme;
50     private final byte[] mSalt;
51 
52     /**
53      * Constructs a {@link DataElement}.
54      */
EncryptionInfo(@onNull byte[] value)55     public EncryptionInfo(@NonNull byte[] value) {
56         Preconditions.checkArgument(value.length == ENCRYPTION_INFO_LENGTH);
57         mEncodingScheme = (value[0] & ENCODING_SCHEME_MASK) >> ENCODING_SCHEME_OFFSET;
58         Preconditions.checkArgument(isValidEncodingScheme(mEncodingScheme));
59         mSalt = Arrays.copyOfRange(value, 1, ENCRYPTION_INFO_LENGTH);
60     }
61 
isValidEncodingScheme(int scheme)62     private boolean isValidEncodingScheme(int scheme) {
63         return scheme == EncodingScheme.MIC || scheme == EncodingScheme.SIGNATURE;
64     }
65 
66     @EncodingScheme
getEncodingScheme()67     public int getEncodingScheme() {
68         return mEncodingScheme;
69     }
70 
getSalt()71     public byte[] getSalt() {
72         return mSalt;
73     }
74 
75     /** Combines the encoding scheme and salt to a byte array
76      * that represents an {@link EncryptionInfo}.
77      */
78     @Nullable
toByte(@ncodingScheme int encodingScheme, byte[] salt)79     public static byte[] toByte(@EncodingScheme int encodingScheme, byte[] salt) {
80         if (ArrayUtils.isEmpty(salt)) {
81             return null;
82         }
83         if (salt.length != ENCRYPTION_INFO_LENGTH - 1) {
84             return null;
85         }
86         byte schemeByte =
87                 (byte) ((encodingScheme << ENCODING_SCHEME_OFFSET) & ENCODING_SCHEME_MASK);
88         return ArrayUtils.append(schemeByte, salt);
89     }
90 }
91