/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.motorolamobility.studio.android.certmanager.packaging.sign; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; import java.util.jar.Attributes; import java.util.jar.Manifest; import com.motorola.studio.android.common.log.StudioLogger; /** * This class is a Manifest digester. * It generates digested hashes for each entry in the manifest file. */ public class ManifestDigester { private final Manifest manifest; private HashMap<String, ManifestEntry> entries = null; /** * Create a new manifest digester with the given manifest * @param manifest */ public ManifestDigester(final Manifest manifest) { this.manifest = manifest; initialize(); } /** * Initialize the digester creating internal entries for each manifest entry */ private void initialize() { Map<String, Attributes> manifestEntries = manifest.getEntries(); // initialize internal entries list entries = new HashMap<String, ManifestEntry>(manifestEntries.size()); for (String entryName : manifestEntries.keySet()) { entries.put(entryName, new ManifestEntry(entryName, manifestEntries.get(entryName))); } } /** * Get this Manifest file digested * @throws IOException if some error occurs during entries encoding */ public String getDigestedString() throws IOException { StringBuilder builder = new StringBuilder(); for (ManifestEntry entry : entries.values()) { builder.append(entry.toDigestedManifestEntry()); builder.append(ManifestEntry.MANIFEST_NEW_LINE); } return builder.toString(); } public HashMap<String, ManifestEntry> getEntries() { return entries; } /** * Computes the digest for the main manifest attributes * * @return the digest of the main manifest attributes or null otherwise * @throws SignException * if a processing error occurs when computing the digest */ public byte[] getDigestedManifestMainAttributes() throws SignException { // create an auxiliary manifest that contain only the main attributes // of the original manifest Manifest auxManifest = new Manifest(); byte[] result; Attributes auxMainAttributes = auxManifest.getMainAttributes(); Attributes mainAttributes = manifest.getMainAttributes(); for (Object attributeKey : mainAttributes.keySet()) { String name = attributeKey.toString(); String value = mainAttributes.getValue(name); auxMainAttributes.putValue(name, value); } result = getDigestedManifest(auxManifest); StudioLogger.info(SignatureFile.class, "Created digest for main manifest attributes"); return result; } /** * Get this Manifest digested * @return * @throws SignException */ public byte[] getDigestedManifest() throws SignException { return getDigestedManifest(manifest); } /** * Computes the digest for the manifest * * @param manifest * the manifest to be digested * @return the digest of the entire manifest or null otherwise * @throws SignException * if a processing error occurs when computing the digest */ public static byte[] getDigestedManifest(Manifest manifest) throws SignException { byte[] digestedManifestBytes = null; ByteArrayOutputStream baos = null; try { MessageDigest messageDigest = MessageDigest.getInstance(ISignConstants.SHA1); baos = new ByteArrayOutputStream(); manifest.write(baos); messageDigest.reset(); digestedManifestBytes = messageDigest.digest(baos.toByteArray()); } catch (IOException e) { StudioLogger.error(SignatureFile.class, "I/O error encoding manifest digest: " + e.getMessage()); throw new SignException("I/O error encoding manifest digest", e); } catch (NoSuchAlgorithmException e) { StudioLogger.error(SignatureFile.class, "Error getting message digester"); throw new SignException("Could digest the manifest"); } finally { try { if (baos != null) { baos.close(); } } catch (IOException e) { //do nothing } } if (digestedManifestBytes == null) { StudioLogger.error(SignatureFile.class, "Error encoding manifest digest"); throw new SignException("Could not encode manifest digest"); } StudioLogger.info(SignatureFile.class, "Created manifest digest"); return digestedManifestBytes; } }