Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 01e3a48d authored by Mykola Kondratenko's avatar Mykola Kondratenko Committed by Rubin Xu
Browse files

Fix AES encryption for SP

Synthetic password is double encrypted by both a random auth-bound
keymaster key and a secret derived from user password.

The value 256 (AES_KEY_LENGTH) is declared as default key size for
secret derived from user password.

Auth-bound keymaster key is not a KeyStore-backed secret key
but is one that is PRNG created by JCA classes and stored
into KeyStore through import key material routine,
constraining particular purpose (only PURPOSE_DECRYPT).

Size for random auth-bound keymaster key is not set.

The default size of the AES key generated by KeyGenerator
(if keysize is not set) is 128.

Following fix is aiming to:

* Ensures that both wrapping keys are using the same key size (=256).

* Ensures that GCM encryption parameters generated by the provider are
the same (tag size equals 128).

How to verify:
Check the synthetic_password_X keystore blob size diff (479 -> 495) at
/data/misc/keystore/user_XX

Bug: 124030743
Test: Manual - see issue
Change-Id: I44346b8c1d98773ef1c168d63b03bc5d2bf0f746
parent c49800f1
Loading
Loading
Loading
Loading
+15 −5
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.spec.InvalidParameterSpecException;
import java.util.Arrays;

import javax.crypto.BadPaddingException;
@@ -43,6 +44,7 @@ import javax.crypto.spec.SecretKeySpec;

public class SyntheticPasswordCrypto {
    private static final int PROFILE_KEY_IV_SIZE = 12;
    private static final int DEFAULT_TAG_LENGTH_BITS = 128;
    private static final int AES_KEY_LENGTH = 32; // 256-bit AES key
    private static final byte[] APPLICATION_ID_PERSONALIZATION = "application-id".getBytes();
    // Time between the user credential is verified with GK and the decryption of synthetic password
@@ -60,13 +62,14 @@ public class SyntheticPasswordCrypto {
        byte[] ciphertext = Arrays.copyOfRange(blob, PROFILE_KEY_IV_SIZE, blob.length);
        Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
                + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE);
        cipher.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(128, iv));
        cipher.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(DEFAULT_TAG_LENGTH_BITS, iv));
        return cipher.doFinal(ciphertext);
    }

    private static byte[] encrypt(SecretKey key, byte[] blob)
            throws IOException, NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
            InvalidKeyException, IllegalBlockSizeException, BadPaddingException,
            InvalidParameterSpecException {
        if (blob == null) {
            return null;
        }
@@ -79,6 +82,11 @@ public class SyntheticPasswordCrypto {
        if (iv.length != PROFILE_KEY_IV_SIZE) {
            throw new RuntimeException("Invalid iv length: " + iv.length);
        }
        final GCMParameterSpec spec = cipher.getParameters().getParameterSpec(
                GCMParameterSpec.class);
        if (spec.getTLen() != DEFAULT_TAG_LENGTH_BITS) {
            throw new RuntimeException("Invalid tag length: " + spec.getTLen());
        }
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        outputStream.write(iv);
        outputStream.write(ciphertext);
@@ -92,7 +100,8 @@ public class SyntheticPasswordCrypto {
        try {
            return encrypt(key, message);
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException
                | IllegalBlockSizeException | BadPaddingException | IOException e) {
                | IllegalBlockSizeException | BadPaddingException | IOException
                | InvalidParameterSpecException e) {
            e.printStackTrace();
            return null;
        }
@@ -147,7 +156,7 @@ public class SyntheticPasswordCrypto {
    public static byte[] createBlob(String keyAlias, byte[] data, byte[] applicationId, long sid) {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
            keyGenerator.init(new SecureRandom());
            keyGenerator.init(AES_KEY_LENGTH * 8, new SecureRandom());
            SecretKey secretKey = keyGenerator.generateKey();
            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
            keyStore.load(null);
@@ -169,7 +178,8 @@ public class SyntheticPasswordCrypto {
        } catch (CertificateException | IOException | BadPaddingException
                | IllegalBlockSizeException
                | KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException
                | InvalidKeyException e) {
                | InvalidKeyException
                | InvalidParameterSpecException e) {
            e.printStackTrace();
            throw new RuntimeException("Failed to encrypt blob", e);
        }