• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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.common.bluetooth.fastpair;
18 
19 import android.annotation.SuppressLint;
20 
21 import java.security.GeneralSecurityException;
22 import java.security.NoSuchAlgorithmException;
23 
24 import javax.crypto.Cipher;
25 import javax.crypto.KeyGenerator;
26 import javax.crypto.spec.SecretKeySpec;
27 
28 /**
29  * Utilities used for encrypting and decrypting Fast Pair packets.
30  */
31 // SuppressLint for ""ecb encryption mode should not be used".
32 // Reasons:
33 //    1. FastPair data is guaranteed to be only 1 AES block in size, ECB is secure.
34 //    2. In each case, the encrypted data is less than 16-bytes and is
35 //       padded up to 16-bytes using random data to fill the rest of the byte array,
36 //       so the plaintext will never be the same.
37 @SuppressLint("GetInstance")
38 public final class AesEcbSingleBlockEncryption {
39 
40     public static final int AES_BLOCK_LENGTH = 16;
41     public static final int KEY_LENGTH = 16;
42 
AesEcbSingleBlockEncryption()43     private AesEcbSingleBlockEncryption() {
44     }
45 
46     /**
47      * Generates a 16-byte AES key.
48      */
generateKey()49     public static byte[] generateKey() throws NoSuchAlgorithmException {
50         KeyGenerator generator = KeyGenerator.getInstance("AES");
51         generator.init(KEY_LENGTH * 8); // Ensure a 16-byte key is always used.
52         return generator.generateKey().getEncoded();
53     }
54 
55     /**
56      * Encrypts data with the provided secret.
57      */
encrypt(byte[] secret, byte[] data)58     public static byte[] encrypt(byte[] secret, byte[] data) throws GeneralSecurityException {
59         return doEncryption(Cipher.ENCRYPT_MODE, secret, data);
60     }
61 
62     /**
63      * Decrypts data with the provided secret.
64      */
decrypt(byte[] secret, byte[] data)65     public static byte[] decrypt(byte[] secret, byte[] data) throws GeneralSecurityException {
66         return doEncryption(Cipher.DECRYPT_MODE, secret, data);
67     }
68 
doEncryption(int mode, byte[] secret, byte[] data)69     private static byte[] doEncryption(int mode, byte[] secret, byte[] data)
70             throws GeneralSecurityException {
71         if (data.length != AES_BLOCK_LENGTH) {
72             throw new IllegalArgumentException("This encrypter only supports 16-byte inputs.");
73         }
74         Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
75         cipher.init(mode, new SecretKeySpec(secret, "AES"));
76         return cipher.doFinal(data);
77     }
78 }
79