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