All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.android.app.blob.BlobHandle Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * Copyright 2020 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 android.app.blob;

import static android.app.blob.XmlTags.ATTR_ALGO;
import static android.app.blob.XmlTags.ATTR_DIGEST;
import static android.app.blob.XmlTags.ATTR_EXPIRY_TIME;
import static android.app.blob.XmlTags.ATTR_LABEL;
import static android.app.blob.XmlTags.ATTR_TAG;

import android.annotation.CurrentTimeMillisLong;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Base64;
import android.util.IndentingPrintWriter;

import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;

import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;

/**
 * An identifier to represent a blob.
 */
// TODO: use datagen tool?
public final class BlobHandle implements Parcelable {
    /** @hide */
    public static final String ALGO_SHA_256 = "SHA-256";

    private static final String[] SUPPORTED_ALGOS = {
            ALGO_SHA_256
    };

    private static final int LIMIT_BLOB_TAG_LENGTH = 128; // characters
    private static final int LIMIT_BLOB_LABEL_LENGTH = 100; // characters

    /**
     * Cyrptographically secure hash algorithm used to generate hash of the blob this handle is
     * representing.
     *
     * @hide
     */
    @NonNull public final String algorithm;

    /**
     * Hash of the blob this handle is representing using {@link #algorithm}.
     *
     * @hide
     */
    @NonNull public final byte[] digest;

    /**
     * Label of the blob that can be surfaced to the user.
     * @hide
     */
    @NonNull public final CharSequence label;

    /**
     * Time in milliseconds after which the blob should be invalidated and not
     * allowed to be accessed by any other app, in {@link System#currentTimeMillis()} timebase.
     *
     * @hide
     */
    @CurrentTimeMillisLong public final long expiryTimeMillis;

    /**
     * An opaque {@link String} associated with the blob.
     *
     * @hide
     */
    @NonNull public final String tag;

    private BlobHandle(String algorithm, byte[] digest, CharSequence label, long expiryTimeMillis,
            String tag) {
        this.algorithm = algorithm;
        this.digest = digest;
        this.label = label;
        this.expiryTimeMillis = expiryTimeMillis;
        this.tag = tag;
    }

    private BlobHandle(Parcel in) {
        this.algorithm = in.readString();
        this.digest = in.createByteArray();
        this.label = in.readCharSequence();
        this.expiryTimeMillis = in.readLong();
        this.tag = in.readString();
    }

    /** @hide */
    public static @NonNull BlobHandle create(@NonNull String algorithm, @NonNull byte[] digest,
            @NonNull CharSequence label, @CurrentTimeMillisLong long expiryTimeMillis,
            @NonNull String tag) {
        final BlobHandle handle = new BlobHandle(algorithm, digest, label, expiryTimeMillis, tag);
        handle.assertIsValid();
        return handle;
    }

    /**
     * Create a new blob identifier.
     *
     * 

For two objects of {@link BlobHandle} to be considered equal, the following arguments * must be equal: *

    *
  • {@code digest} *
  • {@code label} *
  • {@code expiryTimeMillis} *
  • {@code tag} *
* * @param digest the SHA-256 hash of the blob this is representing. * @param label a label indicating what the blob is, that can be surfaced to the user. * The length of the label cannot be more than 100 characters. It is recommended * to keep this brief. This may be truncated and ellipsized if it is too long * to be displayed to the user. * @param expiryTimeMillis the time in secs after which the blob should be invalidated and not * allowed to be accessed by any other app, * in {@link System#currentTimeMillis()} timebase or {@code 0} to * indicate that there is no expiry time associated with this blob. * @param tag an opaque {@link String} associated with the blob. The length of the tag * cannot be more than 128 characters. * * @return a new instance of {@link BlobHandle} object. */ public static @NonNull BlobHandle createWithSha256(@NonNull byte[] digest, @NonNull CharSequence label, @CurrentTimeMillisLong long expiryTimeMillis, @NonNull String tag) { return create(ALGO_SHA_256, digest, label, expiryTimeMillis, tag); } /** * Returns the SHA-256 hash of the blob that this object is representing. * * @see #createWithSha256(byte[], CharSequence, long, String) */ public @NonNull byte[] getSha256Digest() { return digest; } /** * Returns the label associated with the blob that this object is representing. * * @see #createWithSha256(byte[], CharSequence, long, String) */ public @NonNull CharSequence getLabel() { return label; } /** * Returns the expiry time in milliseconds of the blob that this object is representing, in * {@link System#currentTimeMillis()} timebase. * * @see #createWithSha256(byte[], CharSequence, long, String) */ public @CurrentTimeMillisLong long getExpiryTimeMillis() { return expiryTimeMillis; } /** * Returns the opaque {@link String} associated with the blob this object is representing. * * @see #createWithSha256(byte[], CharSequence, long, String) */ public @NonNull String getTag() { return tag; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString(algorithm); dest.writeByteArray(digest); dest.writeCharSequence(label); dest.writeLong(expiryTimeMillis); dest.writeString(tag); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || !(obj instanceof BlobHandle)) { return false; } final BlobHandle other = (BlobHandle) obj; return this.algorithm.equals(other.algorithm) && Arrays.equals(this.digest, other.digest) && this.label.toString().equals(other.label.toString()) && this.expiryTimeMillis == other.expiryTimeMillis && this.tag.equals(other.tag); } @Override public int hashCode() { return Objects.hash(algorithm, Arrays.hashCode(digest), label, expiryTimeMillis, tag); } /** @hide */ public void dump(IndentingPrintWriter fout, boolean dumpFull) { if (dumpFull) { fout.println("algo: " + algorithm); fout.println("digest: " + (dumpFull ? encodeDigest(digest) : safeDigest(digest))); fout.println("label: " + label); fout.println("expiryMs: " + expiryTimeMillis); fout.println("tag: " + tag); } else { fout.println(toString()); } } /** @hide */ public void assertIsValid() { Preconditions.checkArgumentIsSupported(SUPPORTED_ALGOS, algorithm); Preconditions.checkByteArrayNotEmpty(digest, "digest"); Preconditions.checkStringNotEmpty(label, "label must not be null"); Preconditions.checkArgument(label.length() <= LIMIT_BLOB_LABEL_LENGTH, "label too long"); Preconditions.checkArgumentNonnegative(expiryTimeMillis, "expiryTimeMillis must not be negative"); Preconditions.checkStringNotEmpty(tag, "tag must not be null"); Preconditions.checkArgument(tag.length() <= LIMIT_BLOB_TAG_LENGTH, "tag too long"); } @Override public String toString() { return "BlobHandle {" + "algo:" + algorithm + "," + "digest:" + safeDigest(digest) + "," + "label:" + label + "," + "expiryMs:" + expiryTimeMillis + "," + "tag:" + tag + "}"; } /** @hide */ public static String safeDigest(@NonNull byte[] digest) { final String digestStr = encodeDigest(digest); return digestStr.substring(0, 2) + ".." + digestStr.substring(digestStr.length() - 2); } private static String encodeDigest(@NonNull byte[] digest) { return Base64.encodeToString(digest, Base64.NO_WRAP); } /** @hide */ public boolean isExpired() { return expiryTimeMillis != 0 && expiryTimeMillis < System.currentTimeMillis(); } public static final @NonNull Creator CREATOR = new Creator() { @Override public @NonNull BlobHandle createFromParcel(@NonNull Parcel source) { return new BlobHandle(source); } @Override public @NonNull BlobHandle[] newArray(int size) { return new BlobHandle[size]; } }; /** @hide */ public void writeToXml(@NonNull XmlSerializer out) throws IOException { XmlUtils.writeStringAttribute(out, ATTR_ALGO, algorithm); XmlUtils.writeByteArrayAttribute(out, ATTR_DIGEST, digest); XmlUtils.writeStringAttribute(out, ATTR_LABEL, label); XmlUtils.writeLongAttribute(out, ATTR_EXPIRY_TIME, expiryTimeMillis); XmlUtils.writeStringAttribute(out, ATTR_TAG, tag); } /** @hide */ @NonNull public static BlobHandle createFromXml(@NonNull XmlPullParser in) throws IOException { final String algo = XmlUtils.readStringAttribute(in, ATTR_ALGO); final byte[] digest = XmlUtils.readByteArrayAttribute(in, ATTR_DIGEST); final CharSequence label = XmlUtils.readStringAttribute(in, ATTR_LABEL); final long expiryTimeMs = XmlUtils.readLongAttribute(in, ATTR_EXPIRY_TIME); final String tag = XmlUtils.readStringAttribute(in, ATTR_TAG); return BlobHandle.create(algo, digest, label, expiryTimeMs, tag); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy