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