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