• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.locksettings;
18 
19 import java.io.ByteArrayInputStream;
20 import java.io.ByteArrayOutputStream;
21 import java.io.DataInputStream;
22 import java.io.DataOutputStream;
23 import java.io.IOException;
24 import java.security.InvalidAlgorithmParameterException;
25 import java.security.InvalidKeyException;
26 import java.security.NoSuchAlgorithmException;
27 import java.util.Objects;
28 
29 import javax.crypto.BadPaddingException;
30 import javax.crypto.Cipher;
31 import javax.crypto.IllegalBlockSizeException;
32 import javax.crypto.NoSuchPaddingException;
33 import javax.crypto.SecretKey;
34 import javax.crypto.spec.GCMParameterSpec;
35 
36 class AesEncryptionUtil {
37     /** The algorithm used for the encryption of the key blob. */
38     private static final String CIPHER_ALGO = "AES/GCM/NoPadding";
39 
AesEncryptionUtil()40     private AesEncryptionUtil() {}
41 
decrypt(SecretKey key, DataInputStream cipherStream)42     static byte[] decrypt(SecretKey key, DataInputStream cipherStream) throws IOException {
43         Objects.requireNonNull(key);
44         Objects.requireNonNull(cipherStream);
45 
46         int ivSize = cipherStream.readInt();
47         if (ivSize < 0 || ivSize > 32) {
48             throw new IOException("IV out of range: " + ivSize);
49         }
50         byte[] iv = new byte[ivSize];
51         cipherStream.readFully(iv);
52 
53         int rawCipherTextSize = cipherStream.readInt();
54         if (rawCipherTextSize < 0) {
55             throw new IOException("Invalid cipher text size: " + rawCipherTextSize);
56         }
57 
58         byte[] rawCipherText = new byte[rawCipherTextSize];
59         cipherStream.readFully(rawCipherText);
60 
61         final byte[] plainText;
62         try {
63             Cipher c = Cipher.getInstance(CIPHER_ALGO);
64             c.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(128, iv));
65             plainText = c.doFinal(rawCipherText);
66         } catch (NoSuchAlgorithmException | InvalidKeyException | BadPaddingException
67                 | IllegalBlockSizeException | NoSuchPaddingException
68                 | InvalidAlgorithmParameterException e) {
69             throw new IOException("Could not decrypt cipher text", e);
70         }
71 
72         return plainText;
73     }
74 
decrypt(SecretKey key, byte[] cipherText)75     static byte[] decrypt(SecretKey key, byte[] cipherText) throws IOException {
76         Objects.requireNonNull(key);
77         Objects.requireNonNull(cipherText);
78 
79         DataInputStream cipherStream = new DataInputStream(new ByteArrayInputStream(cipherText));
80         return decrypt(key, cipherStream);
81     }
82 
encrypt(SecretKey key, byte[] plainText)83     static byte[] encrypt(SecretKey key, byte[] plainText) throws IOException {
84         Objects.requireNonNull(key);
85         Objects.requireNonNull(plainText);
86 
87         ByteArrayOutputStream bos = new ByteArrayOutputStream();
88         DataOutputStream dos = new DataOutputStream(bos);
89 
90         final byte[] cipherText;
91         final byte[] iv;
92         try {
93             Cipher cipher = Cipher.getInstance(CIPHER_ALGO);
94             cipher.init(Cipher.ENCRYPT_MODE, key);
95             cipherText = cipher.doFinal(plainText);
96             iv = cipher.getIV();
97         } catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException
98                 | NoSuchPaddingException | InvalidKeyException e) {
99             throw new IOException("Could not encrypt input data", e);
100         }
101 
102         dos.writeInt(iv.length);
103         dos.write(iv);
104         dos.writeInt(cipherText.length);
105         dos.write(cipherText);
106 
107         return bos.toByteArray();
108     }
109 }
110