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