MockSyntheticPasswordManager.java revision 3bf722a8d54ca7192dfe07ee7b73eac7d25ccac5
17d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang/*
27d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang * Copyright (C) 2017 The Android Open Source Project
37d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang *
47d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang * Licensed under the Apache License, Version 2.0 (the "License");
57d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang * you may not use this file except in compliance with the License.
67d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang * You may obtain a copy of the License at
77d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang *
87d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang *      http://www.apache.org/licenses/LICENSE-2.0
97d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang *
107d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang * Unless required by applicable law or agreed to in writing, software
117d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang * distributed under the License is distributed on an "AS IS" BASIS,
127d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang * See the License for the specific language governing permissions and
147d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang * limitations under the License.
157d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang */
167d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wangpackage com.android.server;
177d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang
187d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wangimport android.util.ArrayMap;
197d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang
207d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wangimport junit.framework.AssertionFailedError;
217d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang
227d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wangimport java.nio.ByteBuffer;
237d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wangimport java.security.NoSuchAlgorithmException;
247d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wangimport java.security.spec.InvalidKeySpecException;
257d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wangimport java.util.Arrays;
267d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang
277d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wangimport javax.crypto.SecretKeyFactory;
287d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wangimport javax.crypto.spec.PBEKeySpec;
297d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang
307d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wangpublic class MockSyntheticPasswordManager extends SyntheticPasswordManager {
317d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang
327d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    private MockGateKeeperService mGateKeeper;
337d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang
347d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    public MockSyntheticPasswordManager(LockSettingsStorage storage,
357d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang            MockGateKeeperService gatekeeper) {
367d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        super(storage);
377d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        mGateKeeper = gatekeeper;
387d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    }
397d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang
407d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    private ArrayMap<String, byte[]> mBlobs = new ArrayMap<>();
417d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang
427d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    @Override
437d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    protected byte[] decryptSPBlob(String blobKeyName, byte[] blob, byte[] applicationId) {
447d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        if (mBlobs.containsKey(blobKeyName) && !Arrays.equals(mBlobs.get(blobKeyName), blob)) {
457d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang            throw new AssertionFailedError("blobKeyName content is overwritten: " + blobKeyName);
467d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        }
477d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        ByteBuffer buffer = ByteBuffer.allocate(blob.length);
487d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        buffer.put(blob, 0, blob.length);
497d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        buffer.flip();
507d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        int len;
517d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        len = buffer.getInt();
527d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        byte[] data = new byte[len];
537d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        buffer.get(data);
547d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        len = buffer.getInt();
557d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        byte[] appId = new byte[len];
567d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        buffer.get(appId);
577d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        long sid = buffer.getLong();
587d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        if (!Arrays.equals(appId, applicationId)) {
597d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang            throw new AssertionFailedError("Invalid application id");
607d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        }
617d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        if (sid != 0 && mGateKeeper.getAuthTokenForSid(sid) == null) {
627d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang            throw new AssertionFailedError("No valid auth token");
637d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        }
647d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        return data;
657d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    }
667d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang
677d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    @Override
687d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    protected byte[] createSPBlob(String blobKeyName, byte[] data, byte[] applicationId, long sid) {
697d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES + data.length + Integer.BYTES
707d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang                + applicationId.length + Long.BYTES);
717d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        buffer.putInt(data.length);
727d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        buffer.put(data);
737d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        buffer.putInt(applicationId.length);
747d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        buffer.put(applicationId);
757d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        buffer.putLong(sid);
767d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        byte[] result = buffer.array();
777d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        mBlobs.put(blobKeyName, result);
787d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        return result;
797d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    }
807d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang
817d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    @Override
827d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    protected void destroySPBlobKey(String keyAlias) {
837d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    }
847d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang
857d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    @Override
867d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    protected long sidFromPasswordHandle(byte[] handle) {
877d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        return new MockGateKeeperService.VerifyHandle(handle).sid;
887d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    }
897d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang
907d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    @Override
917d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    protected byte[] scrypt(String password, byte[] salt, int N, int r, int p, int outLen) {
927d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        try {
937d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang            PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 10, outLen * 8);
947d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang            SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
957d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang            return f.generateSecret(spec).getEncoded();
967d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
977d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang            e.printStackTrace();
987d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang            return null;
997d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang        }
1007d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang    }
1017d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang
1027d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang}
1037d1bbca7d1b6cef9515a3ad672c7ae71ff5ba69bMiao Wang