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