1ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward/*
2ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * Copyright (C) 2012 The Android Open Source Project
3ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward *
4ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * Licensed under the Apache License, Version 2.0 (the "License");
5ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * you may not use this file except in compliance with the License.
6ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * You may obtain a copy of the License at
7ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward *
8ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward *      http://www.apache.org/licenses/LICENSE-2.0
9ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward *
10ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * Unless required by applicable law or agreed to in writing, software
11ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * distributed under the License is distributed on an "AS IS" BASIS,
12ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * See the License for the specific language governing permissions and
14ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * limitations under the License.
15ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward */
16ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
17ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Cowardpackage android.content.pm;
18ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
19ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Cowardimport java.io.FilterInputStream;
20ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Cowardimport java.io.IOException;
21ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Cowardimport java.io.InputStream;
22ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
23ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Cowardimport javax.crypto.Mac;
24ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
25ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward/**
26ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * An input stream filter that applies a MAC to the data passing through it. At
27ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * the end of the data that should be authenticated, the tag can be calculated.
28ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * After that, the stream should not be used.
29ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward *
30ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * @hide
31ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward */
32ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Cowardpublic class MacAuthenticatedInputStream extends FilterInputStream {
33ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    private final Mac mMac;
34ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
35ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    public MacAuthenticatedInputStream(InputStream in, Mac mac) {
36ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        super(in);
37ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
38ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        mMac = mac;
39ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    }
40ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
41ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    public boolean isTagEqual(byte[] tag) {
42ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        final byte[] actualTag = mMac.doFinal();
43ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
44ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        if (tag == null || actualTag == null || tag.length != actualTag.length) {
45ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward            return false;
46ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        }
47ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
48ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        /*
49ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward         * Attempt to prevent timing attacks by doing the same amount of work
50ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward         * whether the first byte matches or not. Do not change this to a loop
51ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward         * that exits early when a byte does not match.
52ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward         */
53ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        int value = 0;
54ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        for (int i = 0; i < tag.length; i++) {
55ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward            value |= tag[i] ^ actualTag[i];
56ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        }
57ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
58ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        return value == 0;
59ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    }
60ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
61ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    @Override
62ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    public int read() throws IOException {
63ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        final int b = super.read();
64ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        if (b >= 0) {
65ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward            mMac.update((byte) b);
66ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        }
67ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        return b;
68ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    }
69ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
70ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    @Override
71ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    public int read(byte[] buffer, int offset, int count) throws IOException {
72ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        int numRead = super.read(buffer, offset, count);
73ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        if (numRead > 0) {
74ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward            mMac.update(buffer, offset, numRead);
75ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        }
76ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        return numRead;
77ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    }
78ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward}
79