MediaDrm.java revision 3b6ec30bff1749766a0d25770aa42d3a013c09d3
1/*
2 * Copyright (C) 2013 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
17package android.media;
18
19import java.lang.ref.WeakReference;
20import java.util.UUID;
21import java.util.HashMap;
22import java.util.List;
23import android.os.Binder;
24import android.os.Debug;
25import android.os.Handler;
26import android.os.Looper;
27import android.os.Message;
28import android.os.Parcel;
29import android.util.Log;
30
31/**
32 * MediaDrm can be used to obtain keys for decrypting protected media streams, in
33 * conjunction with {@link android.media.MediaCrypto}.  The MediaDrm APIs
34 * are designed to support the ISO/IEC 23001-7: Common Encryption standard, but
35 * may also be used to implement other encryption schemes.
36 * <p>
37 * Encrypted content is prepared using an encryption server and stored in a content
38 * library. The encrypted content is streamed or downloaded from the content library to
39 * client devices via content servers.  Licenses to view the content are obtained from
40 * a License Server.
41 * <p>
42 * <p><img src="../../../images/mediadrm_overview.png"
43 *      alt="MediaDrm Overview diagram"
44 *      border="0" /></p>
45 * <p>
46 * Keys are requested from the license server using a key request. The key
47 * response is delivered to the client app, which provides the response to the
48 * MediaDrm API.
49 * <p>
50 * A Provisioning server may be required to distribute device-unique credentials to
51 * the devices.
52 * <p>
53 * Enforcing requirements related to the number of devices that may play content
54 * simultaneously can be performed either through key renewal or using the secure
55 * stop methods.
56 * <p>
57 * The following sequence diagram shows the interactions between the objects
58 * involved while playing back encrypted content:
59 * <p>
60 * <p><img src="../../../images/mediadrm_decryption_sequence.png"
61 *         alt="MediaDrm Overview diagram"
62 *         border="0" /></p>
63 * <p>
64 * The app first constructs {@link android.media.MediaExtractor} and
65 * {@link android.media.MediaCodec} objects. It accesses the DRM-scheme-identifying UUID,
66 * typically from metadata in the content, and uses this UUID to construct an instance
67 * of a MediaDrm object that is able to support the DRM scheme required by the content.
68 * Crypto schemes are assigned 16 byte UUIDs.  The method {@link #isCryptoSchemeSupported}
69 * can be used to query if a given scheme is supported on the device.
70 * <p>
71 * The app calls {@link #openSession} to generate a sessionId that will uniquely identify
72 * the session in subsequent interactions. The app next uses the MediaDrm object to
73 * obtain a key request message and send it to the license server, then provide
74 * the server's response to the MediaDrm object.
75 * <p>
76 * Once the app has a sessionId, it can construct a MediaCrypto object from the UUID and
77 * sessionId.  The MediaCrypto object is registered with the MediaCodec in the
78 * {@link MediaCodec.#configure} method to enable the codec to decrypt content.
79 * <p>
80 * When the app has constructed {@link android.media.MediaExtractor},
81 * {@link android.media.MediaCodec} and {@link android.media.MediaCrypto} objects,
82 * it proceeds to pull samples from the extractor and queue them into the decoder.  For
83 * encrypted content, the samples returned from the extractor remain encrypted, they
84 * are only decrypted when the samples are delivered to the decoder.
85 * <p>
86 * <a name="Callbacks"></a>
87 * <h3>Callbacks</h3>
88 * <p>Applications should register for informational events in order
89 * to be informed of key state updates during playback or streaming.
90 * Registration for these events is done via a call to
91 * {@link #setOnEventListener}. In order to receive the respective
92 * callback associated with this listener, applications are required to create
93 * MediaDrm objects on a thread with its own Looper running (main UI
94 * thread by default has a Looper running).
95 */
96public final class MediaDrm {
97
98    private final static String TAG = "MediaDrm";
99
100    private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES;
101
102    private EventHandler mEventHandler;
103    private OnEventListener mOnEventListener;
104
105    private long mNativeContext;
106
107    /**
108     * Specify no certificate type
109     *
110     * @hide - not part of the public API at this time
111     */
112    public static final int CERTIFICATE_TYPE_NONE = 0;
113
114    /**
115     * Specify X.509 certificate type
116     *
117     * @hide - not part of the public API at this time
118     */
119    public static final int CERTIFICATE_TYPE_X509 = 1;
120
121    /**
122     * Query if the given scheme identified by its UUID is supported on
123     * this device.
124     * @param uuid The UUID of the crypto scheme.
125     */
126    public static final boolean isCryptoSchemeSupported(UUID uuid) {
127        return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid), null);
128    }
129
130    /**
131     * Query if the given scheme identified by its UUID is supported on
132     * this device, and whether the drm plugin is able to handle the
133     * media container format specified by mimeType.
134     * @param uuid The UUID of the crypto scheme.
135     * @param mimeType The MIME type of the media container, e.g. "video/mp4"
136     *   or "video/webm"
137     */
138    public static final boolean isCryptoSchemeSupported(UUID uuid, String mimeType) {
139        return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid), mimeType);
140    }
141
142    private static final byte[] getByteArrayFromUUID(UUID uuid) {
143        long msb = uuid.getMostSignificantBits();
144        long lsb = uuid.getLeastSignificantBits();
145
146        byte[] uuidBytes = new byte[16];
147        for (int i = 0; i < 8; ++i) {
148            uuidBytes[i] = (byte)(msb >>> (8 * (7 - i)));
149            uuidBytes[8 + i] = (byte)(lsb >>> (8 * (7 - i)));
150        }
151
152        return uuidBytes;
153    }
154
155    private static final native boolean isCryptoSchemeSupportedNative(byte[] uuid,
156            String mimeType);
157
158    /**
159     * Instantiate a MediaDrm object
160     *
161     * @param uuid The UUID of the crypto scheme.
162     *
163     * @throws UnsupportedSchemeException if the device does not support the
164     * specified scheme UUID
165     */
166    public MediaDrm(UUID uuid) throws UnsupportedSchemeException {
167        Looper looper;
168        if ((looper = Looper.myLooper()) != null) {
169            mEventHandler = new EventHandler(this, looper);
170        } else if ((looper = Looper.getMainLooper()) != null) {
171            mEventHandler = new EventHandler(this, looper);
172        } else {
173            mEventHandler = null;
174        }
175
176        /* Native setup requires a weak reference to our object.
177         * It's easier to create it here than in C++.
178         */
179        native_setup(new WeakReference<MediaDrm>(this),
180                getByteArrayFromUUID(uuid));
181    }
182
183    /**
184     * Thrown when an unrecoverable failure occurs during a MediaDrm operation.
185     * Extends java.lang.IllegalStateException with the addition of an error
186     * code that may be useful in diagnosing the failure.
187     */
188    public static final class MediaDrmStateException extends java.lang.IllegalStateException {
189        private final int mErrorCode;
190
191        public MediaDrmStateException(int errorCode, String detailMessage) {
192            super(detailMessage);
193            mErrorCode = errorCode;
194        }
195
196        /**
197         * Retrieve the associated error code
198         */
199        public int getErrorCode() {
200            return mErrorCode;
201        }
202    }
203
204    /**
205     * Register a callback to be invoked when an event occurs
206     *
207     * @param listener the callback that will be run
208     */
209    public void setOnEventListener(OnEventListener listener)
210    {
211        mOnEventListener = listener;
212    }
213
214    /**
215     * Interface definition for a callback to be invoked when a drm event
216     * occurs
217     */
218    public interface OnEventListener
219    {
220        /**
221         * Called when an event occurs that requires the app to be notified
222         *
223         * @param md the MediaDrm object on which the event occurred
224         * @param sessionId the DRM session ID on which the event occurred
225         * @param event indicates the event type
226         * @param extra an secondary error code
227         * @param data optional byte array of data that may be associated with the event
228         */
229        void onEvent(MediaDrm md, byte[] sessionId, int event, int extra, byte[] data);
230    }
231
232    /**
233     * This event type indicates that the app needs to request a certificate from
234     * the provisioning server.  The request message data is obtained using
235     * {@link #getProvisionRequest}
236     */
237    public static final int EVENT_PROVISION_REQUIRED = 1;
238
239    /**
240     * This event type indicates that the app needs to request keys from a license
241     * server.  The request message data is obtained using {@link #getKeyRequest}.
242     */
243    public static final int EVENT_KEY_REQUIRED = 2;
244
245    /**
246     * This event type indicates that the licensed usage duration for keys in a session
247     * has expired.  The keys are no longer valid.
248     */
249    public static final int EVENT_KEY_EXPIRED = 3;
250
251    /**
252     * This event may indicate some specific vendor-defined condition, see your
253     * DRM provider documentation for details
254     */
255    public static final int EVENT_VENDOR_DEFINED = 4;
256
257    private static final int DRM_EVENT = 200;
258
259    private class EventHandler extends Handler
260    {
261        private MediaDrm mMediaDrm;
262
263        public EventHandler(MediaDrm md, Looper looper) {
264            super(looper);
265            mMediaDrm = md;
266        }
267
268        @Override
269        public void handleMessage(Message msg) {
270            if (mMediaDrm.mNativeContext == 0) {
271                Log.w(TAG, "MediaDrm went away with unhandled events");
272                return;
273            }
274            switch(msg.what) {
275
276            case DRM_EVENT:
277                Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");
278
279                if (mOnEventListener != null) {
280                    if (msg.obj != null && msg.obj instanceof Parcel) {
281                        Parcel parcel = (Parcel)msg.obj;
282                        byte[] sessionId = parcel.createByteArray();
283                        if (sessionId.length == 0) {
284                            sessionId = null;
285                        }
286                        byte[] data = parcel.createByteArray();
287                        if (data.length == 0) {
288                            data = null;
289                        }
290                        mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
291                    }
292                }
293                return;
294
295            default:
296                Log.e(TAG, "Unknown message type " + msg.what);
297                return;
298            }
299        }
300    }
301
302    /*
303     * This method is called from native code when an event occurs.  This method
304     * just uses the EventHandler system to post the event back to the main app thread.
305     * We use a weak reference to the original MediaPlayer object so that the native
306     * code is safe from the object disappearing from underneath it.  (This is
307     * the cookie passed to native_setup().)
308     */
309    private static void postEventFromNative(Object mediadrm_ref,
310            int eventType, int extra, Object obj)
311    {
312        MediaDrm md = (MediaDrm)((WeakReference)mediadrm_ref).get();
313        if (md == null) {
314            return;
315        }
316        if (md.mEventHandler != null) {
317            Message m = md.mEventHandler.obtainMessage(DRM_EVENT, eventType, extra, obj);
318            md.mEventHandler.sendMessage(m);
319        }
320    }
321
322    /**
323     * Open a new session with the MediaDrm object.  A session ID is returned.
324     *
325     * @throws NotProvisionedException if provisioning is needed
326     * @throws ResourceBusyException if required resources are in use
327     */
328    public native byte[] openSession() throws NotProvisionedException,
329            ResourceBusyException;
330
331    /**
332     * Close a session on the MediaDrm object that was previously opened
333     * with {@link #openSession}.
334     */
335    public native void closeSession(byte[] sessionId);
336
337    /**
338     * This key request type species that the keys will be for online use, they will
339     * not be saved to the device for subsequent use when the device is not connected
340     * to a network.
341     */
342    public static final int KEY_TYPE_STREAMING = 1;
343
344    /**
345     * This key request type specifies that the keys will be for offline use, they
346     * will be saved to the device for use when the device is not connected to a network.
347     */
348    public static final int KEY_TYPE_OFFLINE = 2;
349
350    /**
351     * This key request type specifies that previously saved offline keys should be released.
352     */
353    public static final int KEY_TYPE_RELEASE = 3;
354
355    /**
356     * Contains the opaque data an app uses to request keys from a license server
357     */
358    public final static class KeyRequest {
359        private byte[] mData;
360        private String mDefaultUrl;
361
362        KeyRequest() {}
363
364        /**
365         * Get the opaque message data
366         */
367        public byte[] getData() { return mData; }
368
369        /**
370         * Get the default URL to use when sending the key request message to a
371         * server, if known.  The app may prefer to use a different license
372         * server URL from other sources.
373         */
374        public String getDefaultUrl() { return mDefaultUrl; }
375    };
376
377    /**
378     * A key request/response exchange occurs between the app and a license server
379     * to obtain or release keys used to decrypt encrypted content.
380     * <p>
381     * getKeyRequest() is used to obtain an opaque key request byte array that is
382     * delivered to the license server.  The opaque key request byte array is returned
383     * in KeyRequest.data.  The recommended URL to deliver the key request to is
384     * returned in KeyRequest.defaultUrl.
385     * <p>
386     * After the app has received the key request response from the server,
387     * it should deliver to the response to the DRM engine plugin using the method
388     * {@link #provideKeyResponse}.
389     *
390     * @param scope may be a sessionId or a keySetId, depending on the specified keyType.
391     * When the keyType is KEY_TYPE_STREAMING or KEY_TYPE_OFFLINE,
392     * scope should be set to the sessionId the keys will be provided to.  When the keyType
393     * is KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys
394     * being released. Releasing keys from a device invalidates them for all sessions.
395     * @param init container-specific data, its meaning is interpreted based on the
396     * mime type provided in the mimeType parameter.  It could contain, for example,
397     * the content ID, key ID or other data obtained from the content metadata that is
398     * required in generating the key request. init may be null when keyType is
399     * KEY_TYPE_RELEASE.
400     * @param mimeType identifies the mime type of the content
401     * @param keyType specifes the type of the request. The request may be to acquire
402     * keys for streaming or offline content, or to release previously acquired
403     * keys, which are identified by a keySetId.
404     * @param optionalParameters are included in the key request message to
405     * allow a client application to provide additional message parameters to the server.
406     *
407     * @throws NotProvisionedException if reprovisioning is needed, due to a
408     * problem with the certifcate
409     */
410    public native KeyRequest getKeyRequest(byte[] scope, byte[] init,
411            String mimeType, int keyType, HashMap<String, String> optionalParameters)
412            throws NotProvisionedException;
413
414
415    /**
416     * A key response is received from the license server by the app, then it is
417     * provided to the DRM engine plugin using provideKeyResponse.  When the
418     * response is for an offline key request, a keySetId is returned that can be
419     * used to later restore the keys to a new session with the method
420     * {@link #restoreKeys}.
421     * When the response is for a streaming or release request, null is returned.
422     *
423     * @param scope may be a sessionId or keySetId depending on the type of the
424     * response.  Scope should be set to the sessionId when the response is for either
425     * streaming or offline key requests.  Scope should be set to the keySetId when
426     * the response is for a release request.
427     * @param response the byte array response from the server
428     *
429     * @throws NotProvisionedException if the response indicates that
430     * reprovisioning is required
431     * @throws DeniedByServerException if the response indicates that the
432     * server rejected the request
433     * @throws ResourceBusyException if required resources are in use
434     */
435    public native byte[] provideKeyResponse(byte[] scope, byte[] response)
436            throws NotProvisionedException, DeniedByServerException;
437
438
439    /**
440     * Restore persisted offline keys into a new session.  keySetId identifies the
441     * keys to load, obtained from a prior call to {@link #provideKeyResponse}.
442     *
443     * @param sessionId the session ID for the DRM session
444     * @param keySetId identifies the saved key set to restore
445     */
446    public native void restoreKeys(byte[] sessionId, byte[] keySetId);
447
448    /**
449     * Remove the current keys from a session.
450     *
451     * @param sessionId the session ID for the DRM session
452     */
453    public native void removeKeys(byte[] sessionId);
454
455    /**
456     * Request an informative description of the key status for the session.  The status is
457     * in the form of {name, value} pairs.  Since DRM license policies vary by vendor,
458     * the specific status field names are determined by each DRM vendor.  Refer to your
459     * DRM provider documentation for definitions of the field names for a particular
460     * DRM engine plugin.
461     *
462     * @param sessionId the session ID for the DRM session
463     */
464    public native HashMap<String, String> queryKeyStatus(byte[] sessionId);
465
466    /**
467     * Contains the opaque data an app uses to request a certificate from a provisioning
468     * server
469     */
470    public final static class ProvisionRequest {
471        ProvisionRequest() {}
472
473        /**
474         * Get the opaque message data
475         */
476        public byte[] getData() { return mData; }
477
478        /**
479         * Get the default URL to use when sending the provision request
480         * message to a server, if known. The app may prefer to use a different
481         * provisioning server URL obtained from other sources.
482         */
483        public String getDefaultUrl() { return mDefaultUrl; }
484
485        private byte[] mData;
486        private String mDefaultUrl;
487    }
488
489    /**
490     * A provision request/response exchange occurs between the app and a provisioning
491     * server to retrieve a device certificate.  If provisionining is required, the
492     * EVENT_PROVISION_REQUIRED event will be sent to the event handler.
493     * getProvisionRequest is used to obtain the opaque provision request byte array that
494     * should be delivered to the provisioning server. The provision request byte array
495     * is returned in ProvisionRequest.data. The recommended URL to deliver the provision
496     * request to is returned in ProvisionRequest.defaultUrl.
497     */
498    public ProvisionRequest getProvisionRequest() {
499        return getProvisionRequestNative(CERTIFICATE_TYPE_NONE, "");
500    }
501
502    private native ProvisionRequest getProvisionRequestNative(int certType,
503            String certAuthority);
504
505    /**
506     * After a provision response is received by the app, it is provided to the DRM
507     * engine plugin using this method.
508     *
509     * @param response the opaque provisioning response byte array to provide to the
510     * DRM engine plugin.
511     *
512     * @throws DeniedByServerException if the response indicates that the
513     * server rejected the request
514     */
515    public void provideProvisionResponse(byte[] response)
516            throws DeniedByServerException {
517        provideProvisionResponseNative(response);
518    }
519
520    private native Certificate provideProvisionResponseNative(byte[] response)
521            throws DeniedByServerException;
522
523    /**
524     * A means of enforcing limits on the number of concurrent streams per subscriber
525     * across devices is provided via SecureStop. This is achieved by securely
526     * monitoring the lifetime of sessions.
527     * <p>
528     * Information from the server related to the current playback session is written
529     * to persistent storage on the device when each MediaCrypto object is created.
530     * <p>
531     * In the normal case, playback will be completed, the session destroyed and the
532     * Secure Stops will be queried. The app queries secure stops and forwards the
533     * secure stop message to the server which verifies the signature and notifies the
534     * server side database that the session destruction has been confirmed. The persisted
535     * record on the client is only removed after positive confirmation that the server
536     * received the message using releaseSecureStops().
537     */
538    public native List<byte[]> getSecureStops();
539
540
541    /**
542     * Process the SecureStop server response message ssRelease.  After authenticating
543     * the message, remove the SecureStops identified in the response.
544     *
545     * @param ssRelease the server response indicating which secure stops to release
546     */
547    public native void releaseSecureStops(byte[] ssRelease);
548
549
550    /**
551     * String property name: identifies the maker of the DRM engine plugin
552     */
553    public static final String PROPERTY_VENDOR = "vendor";
554
555    /**
556     * String property name: identifies the version of the DRM engine plugin
557     */
558    public static final String PROPERTY_VERSION = "version";
559
560    /**
561     * String property name: describes the DRM engine plugin
562     */
563    public static final String PROPERTY_DESCRIPTION = "description";
564
565    /**
566     * String property name: a comma-separated list of cipher and mac algorithms
567     * supported by CryptoSession.  The list may be empty if the DRM engine
568     * plugin does not support CryptoSession operations.
569     */
570    public static final String PROPERTY_ALGORITHMS = "algorithms";
571
572    /**
573     * Read a DRM engine plugin String property value, given the property name string.
574     * <p>
575     * Standard fields names are:
576     * {@link #PROPERTY_VENDOR}, {@link #PROPERTY_VERSION},
577     * {@link #PROPERTY_DESCRIPTION}, {@link #PROPERTY_ALGORITHMS}
578     */
579    public native String getPropertyString(String propertyName);
580
581
582    /**
583     * Byte array property name: the device unique identifier is established during
584     * device provisioning and provides a means of uniquely identifying each device.
585     */
586    public static final String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
587
588    /**
589     * Read a DRM engine plugin byte array property value, given the property name string.
590     * <p>
591     * Standard fields names are {@link #PROPERTY_DEVICE_UNIQUE_ID}
592     */
593    public native byte[] getPropertyByteArray(String propertyName);
594
595
596    /**
597     * Set a DRM engine plugin String property value.
598     */
599    public native void setPropertyString(String propertyName, String value);
600
601    /**
602     * Set a DRM engine plugin byte array property value.
603     */
604    public native void setPropertyByteArray(String propertyName, byte[] value);
605
606
607    private static final native void setCipherAlgorithmNative(MediaDrm drm, byte[] sessionId,
608            String algorithm);
609
610    private static final native void setMacAlgorithmNative(MediaDrm drm, byte[] sessionId,
611            String algorithm);
612
613    private static final native byte[] encryptNative(MediaDrm drm, byte[] sessionId,
614            byte[] keyId, byte[] input, byte[] iv);
615
616    private static final native byte[] decryptNative(MediaDrm drm, byte[] sessionId,
617            byte[] keyId, byte[] input, byte[] iv);
618
619    private static final native byte[] signNative(MediaDrm drm, byte[] sessionId,
620            byte[] keyId, byte[] message);
621
622    private static final native boolean verifyNative(MediaDrm drm, byte[] sessionId,
623            byte[] keyId, byte[] message, byte[] signature);
624
625    /**
626     * In addition to supporting decryption of DASH Common Encrypted Media, the
627     * MediaDrm APIs provide the ability to securely deliver session keys from
628     * an operator's session key server to a client device, based on the factory-installed
629     * root of trust, and then perform encrypt, decrypt, sign and verify operations
630     * with the session key on arbitrary user data.
631     * <p>
632     * The CryptoSession class implements generic encrypt/decrypt/sign/verify methods
633     * based on the established session keys.  These keys are exchanged using the
634     * getKeyRequest/provideKeyResponse methods.
635     * <p>
636     * Applications of this capability could include securing various types of
637     * purchased or private content, such as applications, books and other media,
638     * photos or media delivery protocols.
639     * <p>
640     * Operators can create session key servers that are functionally similar to a
641     * license key server, except that instead of receiving license key requests and
642     * providing encrypted content keys which are used specifically to decrypt A/V media
643     * content, the session key server receives session key requests and provides
644     * encrypted session keys which can be used for general purpose crypto operations.
645     * <p>
646     * A CryptoSession is obtained using {@link #getCryptoSession}
647     */
648    public final class CryptoSession {
649        private MediaDrm mDrm;
650        private byte[] mSessionId;
651
652        CryptoSession(MediaDrm drm, byte[] sessionId,
653                String cipherAlgorithm, String macAlgorithm)
654        {
655            mSessionId = sessionId;
656            mDrm = drm;
657            setCipherAlgorithmNative(drm, sessionId, cipherAlgorithm);
658            setMacAlgorithmNative(drm, sessionId, macAlgorithm);
659        }
660
661        /**
662         * Encrypt data using the CryptoSession's cipher algorithm
663         *
664         * @param keyid specifies which key to use
665         * @param input the data to encrypt
666         * @param iv the initialization vector to use for the cipher
667         */
668        public byte[] encrypt(byte[] keyid, byte[] input, byte[] iv) {
669            return encryptNative(mDrm, mSessionId, keyid, input, iv);
670        }
671
672        /**
673         * Decrypt data using the CryptoSessions's cipher algorithm
674         *
675         * @param keyid specifies which key to use
676         * @param input the data to encrypt
677         * @param iv the initialization vector to use for the cipher
678         */
679        public byte[] decrypt(byte[] keyid, byte[] input, byte[] iv) {
680            return decryptNative(mDrm, mSessionId, keyid, input, iv);
681        }
682
683        /**
684         * Sign data using the CryptoSessions's mac algorithm.
685         *
686         * @param keyid specifies which key to use
687         * @param message the data for which a signature is to be computed
688         */
689        public byte[] sign(byte[] keyid, byte[] message) {
690            return signNative(mDrm, mSessionId, keyid, message);
691        }
692
693        /**
694         * Verify a signature using the CryptoSessions's mac algorithm. Return true
695         * if the signatures match, false if they do no.
696         *
697         * @param keyid specifies which key to use
698         * @param message the data to verify
699         * @param signature the reference signature which will be compared with the
700         *        computed signature
701         */
702        public boolean verify(byte[] keyid, byte[] message, byte[] signature) {
703            return verifyNative(mDrm, mSessionId, keyid, message, signature);
704        }
705    };
706
707    /**
708     * Obtain a CryptoSession object which can be used to encrypt, decrypt,
709     * sign and verify messages or data using the session keys established
710     * for the session using methods {@link #getKeyRequest} and
711     * {@link #provideKeyResponse} using a session key server.
712     *
713     * @param sessionId the session ID for the session containing keys
714     * to be used for encrypt, decrypt, sign and/or verify
715     * @param cipherAlgorithm the algorithm to use for encryption and
716     * decryption ciphers. The algorithm string conforms to JCA Standard
717     * Names for Cipher Transforms and is case insensitive.  For example
718     * "AES/CBC/NoPadding".
719     * @param macAlgorithm the algorithm to use for sign and verify
720     * The algorithm string conforms to JCA Standard Names for Mac
721     * Algorithms and is case insensitive.  For example "HmacSHA256".
722     * <p>
723     * The list of supported algorithms for a DRM engine plugin can be obtained
724     * using the method {@link #getPropertyString} with the property name
725     * "algorithms".
726     */
727    public CryptoSession getCryptoSession(byte[] sessionId,
728            String cipherAlgorithm, String macAlgorithm)
729    {
730        return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm);
731    }
732
733    /**
734     * Contains the opaque data an app uses to request a certificate from a provisioning
735     * server
736     *
737     * @hide - not part of the public API at this time
738     */
739    public final static class CertificateRequest {
740        private byte[] mData;
741        private String mDefaultUrl;
742
743        CertificateRequest(byte[] data, String defaultUrl) {
744            mData = data;
745            mDefaultUrl = defaultUrl;
746        }
747
748        /**
749         * Get the opaque message data
750         */
751        public byte[] getData() { return mData; }
752
753        /**
754         * Get the default URL to use when sending the certificate request
755         * message to a server, if known. The app may prefer to use a different
756         * certificate server URL obtained from other sources.
757         */
758        public String getDefaultUrl() { return mDefaultUrl; }
759    }
760
761    /**
762     * Generate a certificate request, specifying the certificate type
763     * and authority. The response received should be passed to
764     * provideCertificateResponse.
765     *
766     * @param certType Specifies the certificate type.
767     *
768     * @param certAuthority is passed to the certificate server to specify
769     * the chain of authority.
770     *
771     * @hide - not part of the public API at this time
772     */
773    public CertificateRequest getCertificateRequest(int certType,
774            String certAuthority)
775    {
776        ProvisionRequest provisionRequest = getProvisionRequestNative(certType, certAuthority);
777        return new CertificateRequest(provisionRequest.getData(),
778                provisionRequest.getDefaultUrl());
779    }
780
781    /**
782     * Contains the wrapped private key and public certificate data associated
783     * with a certificate.
784     *
785     * @hide - not part of the public API at this time
786     */
787    public final static class Certificate {
788        Certificate() {}
789
790        /**
791         * Get the wrapped private key data
792         */
793        public byte[] getWrappedPrivateKey() { return mWrappedKey; }
794
795        /**
796         * Get the PEM-encoded certificate chain
797         */
798        public byte[] getContent() { return mCertificateData; }
799
800        private byte[] mWrappedKey;
801        private byte[] mCertificateData;
802    }
803
804
805    /**
806     * Process a response from the certificate server.  The response
807     * is obtained from an HTTP Post to the url provided by getCertificateRequest.
808     * <p>
809     * The public X509 certificate chain and wrapped private key are returned
810     * in the returned Certificate objec.  The certificate chain is in PEM format.
811     * The wrapped private key should be stored in application private
812     * storage, and used when invoking the signRSA method.
813     *
814     * @param response the opaque certificate response byte array to provide to the
815     * DRM engine plugin.
816     *
817     * @throws DeniedByServerException if the response indicates that the
818     * server rejected the request
819     *
820     * @hide - not part of the public API at this time
821     */
822    public Certificate provideCertificateResponse(byte[] response)
823            throws DeniedByServerException {
824        return provideProvisionResponseNative(response);
825    }
826
827    private static final native byte[] signRSANative(MediaDrm drm, byte[] sessionId,
828            String algorithm, byte[] wrappedKey, byte[] message);
829
830    /**
831     * Sign data using an RSA key
832     *
833     * @param sessionId a sessionId obtained from openSession on the MediaDrm object
834     * @param algorithm the signing algorithm to use, e.g. "PKCS1-BlockType1"
835     * @param wrappedKey - the wrapped (encrypted) RSA private key obtained
836     * from provideCertificateResponse
837     * @param message the data for which a signature is to be computed
838     *
839     * @hide - not part of the public API at this time
840     */
841    public byte[] signRSA(byte[] sessionId, String algorithm,
842            byte[] wrappedKey, byte[] message) {
843        return signRSANative(this, sessionId, algorithm, wrappedKey, message);
844    }
845
846    @Override
847    protected void finalize() {
848        native_finalize();
849    }
850
851    public native final void release();
852    private static native final void native_init();
853
854    private native final void native_setup(Object mediadrm_this, byte[] uuid);
855
856    private native final void native_finalize();
857
858    static {
859        System.loadLibrary("media_jni");
860        native_init();
861    }
862}
863