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