• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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 android.ext.services.displayhash;
18 
19 import android.graphics.Rect;
20 import android.os.Build;
21 import android.os.Parcel;
22 import android.util.Log;
23 
24 import androidx.annotation.RequiresApi;
25 
26 import java.security.InvalidKeyException;
27 import java.security.NoSuchAlgorithmException;
28 import java.util.Arrays;
29 
30 import javax.crypto.Mac;
31 import javax.crypto.spec.SecretKeySpec;
32 
33 @RequiresApi(Build.VERSION_CODES.S)
34 class HmacKeyManager {
35     private static final String TAG = DisplayHashingServiceImpl.TAG;
36     private static final String ALGORITHM = "HmacSHA256";
37 
HmacKeyManager()38     HmacKeyManager() { }
39 
generateHmac(byte[] salt, long timestamp, Rect bounds, int hashAlgorithm, byte[] imageHash)40     byte[] generateHmac(byte[] salt, long timestamp, Rect bounds, int hashAlgorithm,
41             byte[] imageHash) {
42         try {
43             Mac mac = Mac.getInstance(ALGORITHM);
44             SecretKeySpec keySpec = new SecretKeySpec(salt, ALGORITHM);
45             mac.init(keySpec);
46 
47             final VerificationObject object = new VerificationObject(timestamp, bounds,
48                     hashAlgorithm, imageHash);
49             mac.update(object.convertToBytes());
50 
51             return mac.doFinal();
52         } catch (NoSuchAlgorithmException | InvalidKeyException e) {
53             Log.e(TAG, "Failed to generate HMAC", e);
54             return null;
55         }
56     }
57 
verifyHmac(byte[] salt, long timestamp, Rect bounds, int hashAlgorithm, byte[] imageHash, byte[] hmac)58     boolean verifyHmac(byte[] salt, long timestamp, Rect bounds,
59             int hashAlgorithm, byte[] imageHash, byte[] hmac) {
60         if (hmac == null || hmac.length != 32) {
61             return false;
62         }
63 
64         byte[] calculatedHmac = generateHmac(salt, timestamp, bounds, hashAlgorithm,
65                 imageHash);
66         return Arrays.equals(hmac, calculatedHmac);
67     }
68 
69     private static class VerificationObject {
70         private final long mTimestamp;
71         private final Rect mBounds;
72         private final int mHashAlgorithm;
73         private final byte[] mImageHash;
74 
VerificationObject(long timestamp, Rect bounds, int hashAlgorithm, byte[] imageHash)75         VerificationObject(long timestamp, Rect bounds, int hashAlgorithm, byte[] imageHash) {
76             mTimestamp = timestamp;
77             mBounds = bounds;
78             mHashAlgorithm = hashAlgorithm;
79             mImageHash = imageHash;
80         }
81 
convertToBytes()82         byte[] convertToBytes() {
83             Parcel parcel = Parcel.obtain();
84             parcel.writeLong(mTimestamp);
85             parcel.writeParcelable(mBounds, 0);
86             parcel.writeInt(mHashAlgorithm);
87             parcel.writeByteArray(mImageHash);
88             byte[] bytes = parcel.marshall();
89             parcel.recycle();
90             return bytes;
91         }
92     }
93 }
94