CryptoHelper.java revision 7881228736fd5f3f4ecf25d4808dc004c03b54d1
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 Kwanimport java.security.SecureRandom; 147881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport java.util.Arrays; 157881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 167881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport javax.crypto.Cipher; 177881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport javax.crypto.KeyGenerator; 187881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport javax.crypto.Mac; 197881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport javax.crypto.SecretKey; 207881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport javax.crypto.spec.IvParameterSpec; 217881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwanimport javax.crypto.spec.SecretKeySpec; 227881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 237881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan/** 247881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan * A crypto helper for encrypting and decrypting bundle with in-memory symmetric 257881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan * key for {@link AccountManagerService}. 267881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan */ 277881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan/* default */ class CryptoHelper { 287881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static final String TAG = "Account"; 297881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 307881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static final String KEY_CIPHER = "cipher"; 317881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static final String KEY_MAC = "mac"; 327881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static final String KEY_ALGORITHM = "AES"; 337881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding"; 347881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static final String MAC_ALGORITHM = "HMACSHA256"; 357881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static final int IV_LENGTH = 16; 367881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 377881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private static CryptoHelper sInstance; 387881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan // Keys used for encrypting and decrypting data returned in a Bundle. 397881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private final SecretKeySpec mCipherKeySpec; 407881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private final SecretKeySpec mMacKeySpec; 417881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private final IvParameterSpec mIv; 427881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 437881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan /* default */ synchronized static CryptoHelper getInstance() throws NoSuchAlgorithmException { 447881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan if (sInstance == null) { 457881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan sInstance = new CryptoHelper(); 467881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 477881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan return sInstance; 487881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 497881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 507881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private CryptoHelper() throws NoSuchAlgorithmException { 517881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM); 527881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan SecretKey skey = kgen.generateKey(); 537881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan mCipherKeySpec = new SecretKeySpec(skey.getEncoded(), KEY_ALGORITHM); 547881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 557881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan kgen = KeyGenerator.getInstance(MAC_ALGORITHM); 567881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan skey = kgen.generateKey(); 577881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan mMacKeySpec = new SecretKeySpec(skey.getEncoded(), MAC_ALGORITHM); 587881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 597881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan // Create random iv 607881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan byte[] iv = new byte[IV_LENGTH]; 617881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan SecureRandom secureRandom = new SecureRandom(); 627881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan secureRandom.nextBytes(iv); 637881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan mIv = new IvParameterSpec(iv); 647881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 657881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 667881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan @NonNull 677881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan /* default */ Bundle encryptBundle(@NonNull Bundle bundle) throws GeneralSecurityException { 687881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Preconditions.checkNotNull(bundle, "Cannot encrypt null bundle."); 697881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Parcel parcel = Parcel.obtain(); 707881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan bundle.writeToParcel(parcel, 0); 717881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan byte[] bytes = parcel.marshall(); 727881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan parcel.recycle(); 737881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 747881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Bundle encryptedBundle = new Bundle(); 757881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 767881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan byte[] cipher = encrypt(bytes); 777881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan byte[] mac = createMac(cipher); 787881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 797881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan encryptedBundle.putByteArray(KEY_CIPHER, cipher); 807881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan encryptedBundle.putByteArray(KEY_MAC, mac); 817881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 827881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan return encryptedBundle; 837881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 847881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 857881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan @Nullable 867881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan /* default */ Bundle decryptBundle(@NonNull Bundle bundle) throws GeneralSecurityException { 877881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Preconditions.checkNotNull(bundle, "Cannot decrypt null bundle."); 887881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan byte[] cipherArray = bundle.getByteArray(KEY_CIPHER); 897881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan byte[] macArray = bundle.getByteArray(KEY_MAC); 907881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 917881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan if (!verifyMac(cipherArray, macArray)) { 927881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan if (Log.isLoggable(TAG, Log.VERBOSE)) { 937881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Log.v(TAG, "Escrow mac mismatched!"); 947881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 957881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan return null; 967881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 977881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 987881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); 997881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan cipher.init(Cipher.DECRYPT_MODE, mCipherKeySpec, mIv); 1007881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan byte[] decryptedBytes = cipher.doFinal(cipherArray); 1017881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 1027881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Parcel decryptedParcel = Parcel.obtain(); 1037881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan decryptedParcel.unmarshall(decryptedBytes, 0, decryptedBytes.length); 1047881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan decryptedParcel.setDataPosition(0); 1057881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Bundle decryptedBundle = new Bundle(); 1067881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan decryptedBundle.readFromParcel(decryptedParcel); 1077881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan decryptedParcel.recycle(); 1087881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan return decryptedBundle; 1097881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 1107881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 1117881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private boolean verifyMac(@Nullable byte[] cipherArray, @Nullable byte[] macArray) 1127881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan throws GeneralSecurityException { 1137881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 1147881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan if (cipherArray == null || cipherArray.length == 0 || macArray == null 1157881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan || macArray.length == 0) { 1167881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan if (Log.isLoggable(TAG, Log.VERBOSE)) { 1177881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Log.v(TAG, "Cipher or MAC is empty!"); 1187881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 1197881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan return false; 1207881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 1217881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Mac mac = Mac.getInstance(MAC_ALGORITHM); 1227881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan mac.init(mMacKeySpec); 1237881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan mac.update(cipherArray); 1247881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan return Arrays.equals(macArray, mac.doFinal()); 1257881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 1267881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 1277881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan @NonNull 1287881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private byte[] encrypt(@NonNull byte[] data) throws GeneralSecurityException { 1297881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); 1307881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan cipher.init(Cipher.ENCRYPT_MODE, mCipherKeySpec, mIv); 1317881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan return cipher.doFinal(data); 1327881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 1337881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan 1347881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan @NonNull 1357881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan private byte[] createMac(@NonNull byte[] cipher) throws GeneralSecurityException { 1367881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan Mac mac = Mac.getInstance(MAC_ALGORITHM); 1377881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan mac.init(mMacKeySpec); 1387881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan return mac.doFinal(cipher); 1397881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan } 1407881228736fd5f3f4ecf25d4808dc004c03b54d1Sandra Kwan} 141