17881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanpackage com.android.server.accounts; 27881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 37881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport android.annotation.NonNull; 47881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport android.annotation.Nullable; 57881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport android.os.Bundle; 67881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport android.os.Parcel; 77881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport android.util.Log; 87881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 97881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport com.android.internal.util.Preconditions; 107881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 117881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport java.security.GeneralSecurityException; 127881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport java.security.NoSuchAlgorithmException; 137881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 147881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport javax.crypto.Cipher; 157881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport javax.crypto.KeyGenerator; 167881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport javax.crypto.Mac; 177881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport javax.crypto.SecretKey; 187881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport javax.crypto.spec.IvParameterSpec; 197881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 207881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan/** 217881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan * A crypto helper for encrypting and decrypting bundle with in-memory symmetric 227881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan * key for {@link AccountManagerService}. 237881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan */ 247881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan/* default */ class CryptoHelper { 257881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static final String TAG = "Account"; 267881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 277881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static final String KEY_CIPHER = "cipher"; 287881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static final String KEY_MAC = "mac"; 297881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static final String KEY_ALGORITHM = "AES"; 30766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia private static final String KEY_IV = "iv"; 317881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding"; 327881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static final String MAC_ALGORITHM = "HMACSHA256"; 337881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static final int IV_LENGTH = 16; 347881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 357881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static CryptoHelper sInstance; 367881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan // Keys used for encrypting and decrypting data returned in a Bundle. 37766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia private final SecretKey mEncryptionKey; 38766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia private final SecretKey mMacKey; 397881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 407881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan /* default */ synchronized static CryptoHelper getInstance() throws NoSuchAlgorithmException { 417881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan if (sInstance == null) { 427881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan sInstance = new CryptoHelper(); 437881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 447881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan return sInstance; 457881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 467881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 477881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private CryptoHelper() throws NoSuchAlgorithmException { 487881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM); 49766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia mEncryptionKey = kgen.generateKey(); 50766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia // Use a different key for mac-ing than encryption/decryption. 517881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan kgen = KeyGenerator.getInstance(MAC_ALGORITHM); 52766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia mMacKey = kgen.generateKey(); 537881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 547881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 557881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan @NonNull 567881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan /* default */ Bundle encryptBundle(@NonNull Bundle bundle) throws GeneralSecurityException { 577881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Preconditions.checkNotNull(bundle, "Cannot encrypt null bundle."); 587881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Parcel parcel = Parcel.obtain(); 597881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan bundle.writeToParcel(parcel, 0); 60766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia byte[] clearBytes = parcel.marshall(); 617881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan parcel.recycle(); 627881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 63766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); 64766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia cipher.init(Cipher.ENCRYPT_MODE, mEncryptionKey); 65766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia byte[] encryptedBytes = cipher.doFinal(clearBytes); 66766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia byte[] iv = cipher.getIV(); 67766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia byte[] mac = createMac(encryptedBytes, iv); 687881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 69766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia Bundle encryptedBundle = new Bundle(); 70766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia encryptedBundle.putByteArray(KEY_CIPHER, encryptedBytes); 717881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan encryptedBundle.putByteArray(KEY_MAC, mac); 72766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia encryptedBundle.putByteArray(KEY_IV, iv); 737881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 747881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan return encryptedBundle; 757881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 767881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 777881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan @Nullable 787881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan /* default */ Bundle decryptBundle(@NonNull Bundle bundle) throws GeneralSecurityException { 797881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Preconditions.checkNotNull(bundle, "Cannot decrypt null bundle."); 80766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia byte[] iv = bundle.getByteArray(KEY_IV); 81766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia byte[] encryptedBytes = bundle.getByteArray(KEY_CIPHER); 82766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia byte[] mac = bundle.getByteArray(KEY_MAC); 83766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia if (!verifyMac(encryptedBytes, iv, mac)) { 84766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia Log.w(TAG, "Escrow mac mismatched!"); 857881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan return null; 867881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 877881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 88766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia IvParameterSpec ivSpec = new IvParameterSpec(iv); 897881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); 90766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia cipher.init(Cipher.DECRYPT_MODE, mEncryptionKey, ivSpec); 91766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia byte[] decryptedBytes = cipher.doFinal(encryptedBytes); 927881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 937881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Parcel decryptedParcel = Parcel.obtain(); 947881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan decryptedParcel.unmarshall(decryptedBytes, 0, decryptedBytes.length); 957881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan decryptedParcel.setDataPosition(0); 967881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Bundle decryptedBundle = new Bundle(); 977881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan decryptedBundle.readFromParcel(decryptedParcel); 987881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan decryptedParcel.recycle(); 997881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan return decryptedBundle; 1007881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 1017881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 102766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia private boolean verifyMac(@Nullable byte[] cipherArray, @Nullable byte[] iv, @Nullable byte[] macArray) 1037881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan throws GeneralSecurityException { 1047881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan if (cipherArray == null || cipherArray.length == 0 || macArray == null 1057881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan || macArray.length == 0) { 1067881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan if (Log.isLoggable(TAG, Log.VERBOSE)) { 1077881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Log.v(TAG, "Cipher or MAC is empty!"); 1087881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 1097881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan return false; 1107881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 111766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia return constantTimeArrayEquals(macArray, createMac(cipherArray, iv)); 1127881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 1137881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 1147881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan @NonNull 115766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia private byte[] createMac(@NonNull byte[] cipher, @NonNull byte[] iv) throws GeneralSecurityException { 116766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia Mac mac = Mac.getInstance(MAC_ALGORITHM); 117766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia mac.init(mMacKey); 118766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia mac.update(cipher); 119766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia mac.update(iv); 120766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia return mac.doFinal(); 1217881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 1227881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 123766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia private static boolean constantTimeArrayEquals(byte[] a, byte[] b) { 124766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia if (a == null || b == null) { 125766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia return a == b; 126766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia } 127766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia if (a.length != b.length) { 128766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia return false; 129766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia } 130766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia boolean isEqual = true; 131766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia for (int i = 0; i < b.length; i++) { 132766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia isEqual &= (a[i] == b[i]); 133766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia } 134766b28329326628eaf1ef8009ebd5d611369c490Carlos Valdivia return isEqual; 1357881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 1367881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan} 137