MediaDrm API update
Clarify offline usage of sessions and keys and implement
implement CryptoSession to support additional crypto use
cases.
Change-Id: Id3f8c706e9e3034b09af8e2a6a2f26bd74a49f93
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 4561d3f..3cdf261 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -28,8 +28,8 @@
import android.util.Log;
/**
- * MediaDrm class can be used in conjunction with {@link android.media.MediaCrypto}
- * to obtain licenses for decoding encrypted media data.
+ * MediaDrm can be used in conjunction with {@link android.media.MediaCrypto}
+ * to obtain keys for decrypting protected media data.
*
* Crypto schemes are assigned 16 byte UUIDs,
* the method {@link #isCryptoSchemeSupported} can be used to query if a given
@@ -131,11 +131,15 @@
void onEvent(MediaDrm md, byte[] sessionId, int event, int extra, byte[] data);
}
+ public static final int MEDIA_DRM_EVENT_PROVISION_REQUIRED = 1;
+ public static final int MEDIA_DRM_EVENT_KEY_REQUIRED = 2;
+ public static final int MEDIA_DRM_EVENT_KEY_EXPIRED = 3;
+ public static final int MEDIA_DRM_EVENT_VENDOR_DEFINED = 4;
+
/* Do not change these values without updating their counterparts
* in include/media/mediadrm.h!
*/
private static final int DRM_EVENT = 200;
-
private class EventHandler extends Handler
{
private MediaDrm mMediaDrm;
@@ -197,68 +201,88 @@
public native byte[] openSession() throws MediaDrmException;
/**
- * Close a session on the MediaDrm object.
+ * Close a session on the MediaDrm object that was previously opened
+ * with {@link #openSession}.
*/
public native void closeSession(byte[] sessionId) throws MediaDrmException;
- public static final int MEDIA_DRM_LICENSE_TYPE_STREAMING = 1;
- public static final int MEDIA_DRM_LICENSE_TYPE_OFFLINE = 2;
+ public static final int MEDIA_DRM_KEY_TYPE_STREAMING = 1;
+ public static final int MEDIA_DRM_KEY_TYPE_OFFLINE = 2;
- public final class LicenseRequest {
- public LicenseRequest() {}
+ public final class KeyRequest {
+ public KeyRequest() {}
public byte[] data;
public String defaultUrl;
};
/**
- * A license request/response exchange occurs between the app and a License
- * Server to obtain the keys required to decrypt the content. getLicenseRequest()
- * is used to obtain an opaque license request byte array that is delivered to the
- * license server. The opaque license request byte array is returned in
- * LicenseReqeust.data. The recommended URL to deliver the license request to is
- * returned in LicenseRequest.defaultUrl
+ * A key request/response exchange occurs between the app and a license
+ * server to obtain the keys to decrypt encrypted content. getKeyRequest()
+ * is used to obtain an opaque key request byte array that is delivered to the
+ * license server. The opaque key request byte array is returned in
+ * KeyRequest.data. The recommended URL to deliver the key request to is
+ * returned in KeyRequest.defaultUrl.
+ *
+ * After the app has received the key request response from the server,
+ * it should deliver to the response to the DRM engine plugin using the method
+ * {@link #provideKeyResponse}.
*
* @param sessonId the session ID for the drm session
* @param init container-specific data, its meaning is interpreted based on the
* mime type provided in the mimeType parameter. It could contain, for example,
* the content ID, key ID or other data obtained from the content metadata that is
- * required in generating the license request.
+ * required in generating the key request.
* @param mimeType identifies the mime type of the content
- * @param licenseType specifes if the license is for streaming or offline content
- * @param optionalParameters are included in the license server request message to
+ * @param keyType specifes if the request is for streaming or offline content
+ * @param optionalParameters are included in the key request message to
* allow a client application to provide additional message parameters to the server.
*/
- public native LicenseRequest getLicenseRequest( byte[] sessionId, byte[] init,
- String mimeType, int licenseType,
- HashMap<String, String> optionalParameters )
+ public native KeyRequest getKeyRequest(byte[] sessionId, byte[] init,
+ String mimeType, int keyType,
+ HashMap<String, String> optionalParameters)
throws MediaDrmException;
/**
- * After a license response is received by the app, it is provided to the DRM plugin
- * using provideLicenseResponse.
+ * A key response is received from the license server by the app, then it is
+ * provided to the DRM engine plugin using provideKeyResponse. The byte array
+ * returned is a keySetId that can be used to later restore the keys to a new
+ * session with the method {@link restoreKeys}, enabling offline key use.
*
* @param sessionId the session ID for the DRM session
* @param response the byte array response from the server
*/
- public native void provideLicenseResponse( byte[] sessionId, byte[] response )
+ public native byte[] provideKeyResponse(byte[] sessionId, byte[] response)
throws MediaDrmException;
/**
- * Remove the keys associated with a license for a session
+ * Restore persisted offline keys into a new session. keySetId identifies the
+ * keys to load, obtained from a prior call to {@link provideKeyResponse}.
+ *
* @param sessionId the session ID for the DRM session
+ * @param keySetId identifies the saved key set to restore
*/
- public native void removeLicense( byte[] sessionId ) throws MediaDrmException;
+ public native void restoreKeys(byte[] sessionId, byte[] keySetId)
+ throws MediaDrmException;
/**
- * Request an informative description of the license for the session. The status is
+ * Remove the persisted keys associated with an offline license. Keys are persisted
+ * when {@link provideKeyResponse} is called with keys obtained from the method
+ * {@link getKeyRequest} using keyType = MEDIA_DRM_KEY_TYPE_OFFLINE.
+ *
+ * @param keySetId identifies the saved key set to remove
+ */
+ public native void removeKeys(byte[] keySetId) throws MediaDrmException;
+
+ /**
+ * Request an informative description of the key status for the session. The status is
* in the form of {name, value} pairs. Since DRM license policies vary by vendor,
* the specific status field names are determined by each DRM vendor. Refer to your
* DRM provider documentation for definitions of the field names for a particular
- * DrmEngine.
+ * DRM engine plugin.
*
* @param sessionId the session ID for the DRM session
*/
- public native HashMap<String, String> queryLicenseStatus( byte[] sessionId )
+ public native HashMap<String, String> queryKeyStatus(byte[] sessionId)
throws MediaDrmException;
public final class ProvisionRequest {
@@ -269,22 +293,23 @@
/**
* A provision request/response exchange occurs between the app and a provisioning
- * server to retrieve a device certificate. getProvisionRequest is used to obtain
- * an opaque license request byte array that is delivered to the provisioning server.
- * The opaque provision request byte array is returned in ProvisionRequest.data
- * The recommended URL to deliver the license request to is returned in
- * ProvisionRequest.defaultUrl.
+ * server to retrieve a device certificate. If provisionining is required, the
+ * MEDIA_DRM_EVENT_PROVISION_REQUIRED event will be sent to the event handler.
+ * getProvisionRequest is used to obtain the opaque provision request byte array that
+ * should be delivered to the provisioning server. The provision request byte array
+ * is returned in ProvisionRequest.data. The recommended URL to deliver the provision
+ * request to is returned in ProvisionRequest.defaultUrl.
*/
public native ProvisionRequest getProvisionRequest() throws MediaDrmException;
/**
* After a provision response is received by the app, it is provided to the DRM
- * plugin using this method.
+ * engine plugin using this method.
*
* @param response the opaque provisioning response byte array to provide to the
- * DrmEngine.
+ * DRM engine plugin.
*/
- public native void provideProvisionResponse( byte[] response )
+ public native void provideProvisionResponse(byte[] response)
throws MediaDrmException;
/**
@@ -314,38 +339,140 @@
*
* @param ssRelease the server response indicating which secure stops to release
*/
- public native void releaseSecureStops( byte[] ssRelease )
+ public native void releaseSecureStops(byte[] ssRelease)
throws MediaDrmException;
/**
- * Read a Drm plugin property value, given the property name string. There are several
- * forms of property access functions, depending on the data type returned.
+ * Read a DRM engine plugin property value, given the property name string. There are
+ * several forms of property access functions, depending on the data type returned.
*
* Standard fields names are:
- * vendor String - identifies the maker of the plugin
- * version String - identifies the version of the plugin
- * description String - describes the plugin
+ * vendor String - identifies the maker of the DRM engine plugin
+ * version String - identifies the version of the DRM engine plugin
+ * description String - describes the DRM engine plugin
* deviceUniqueId byte[] - The device unique identifier is established during device
- * provisioning and provides a means of uniquely identifying
- * each device
+ * provisioning and provides a means of uniquely identifying
+ * each device
+ * algorithms String - a comma-separate list of cipher and mac algorithms supported
+ * by CryptoSession. The list may be empty if the DRM engine
+ * plugin does not support CryptoSession operations.
*/
- public native String getPropertyString( String propertyName )
+ public native String getPropertyString(String propertyName)
throws MediaDrmException;
- public native byte[] getPropertyByteArray( String propertyName )
+ public native byte[] getPropertyByteArray(String propertyName)
throws MediaDrmException;
/**
- * Write a Drm plugin property value. There are several forms of property setting
- * functions, depending on the data type being set.
+ * Write a DRM engine plugin property value. There are several forms of
+ * property setting functions, depending on the data type being set.
*/
- public native void setPropertyString( String propertyName, String value )
+ public native void setPropertyString(String propertyName, String value)
throws MediaDrmException;
- public native void setPropertyByteArray( String propertyName, byte[] value )
+ public native void setPropertyByteArray(String propertyName, byte[] value)
throws MediaDrmException;
+ /**
+ * In addition to supporting decryption of DASH Common Encrypted Media, the
+ * MediaDrm APIs provide the ability to securely deliver session keys from
+ * an operator's session key server to a client device, based on the factory-installed
+ * root of trust, and provide the ability to do encrypt, decrypt, sign and verify
+ * with the session key on arbitrary user data.
+ *
+ * The CryptoSession class implements generic encrypt/decrypt/sign/verify methods
+ * based on the established session keys. These keys are exchanged using the
+ * getKeyRequest/provideKeyResponse methods.
+ *
+ * Applications of this capability could include securing various types of
+ * purchased or private content, such as applications, books and other media,
+ * photos or media delivery protocols.
+ *
+ * Operators can create session key servers that are functionally similar to a
+ * license key server, except that instead of receiving license key requests and
+ * providing encrypted content keys which are used specifically to decrypt A/V media
+ * content, the session key server receives session key requests and provides
+ * encrypted session keys which can be used for general purpose crypto operations.
+ */
+
+ private static final native void setCipherAlgorithmNative(MediaDrm drm, byte[] sessionId,
+ String algorithm);
+
+ private static final native void setMacAlgorithmNative(MediaDrm drm, byte[] sessionId,
+ String algorithm);
+
+ private static final native byte[] encryptNative(MediaDrm drm, byte[] sessionId,
+ byte[] keyId, byte[] input, byte[] iv);
+
+ private static final native byte[] decryptNative(MediaDrm drm, byte[] sessionId,
+ byte[] keyId, byte[] input, byte[] iv);
+
+ private static final native byte[] signNative(MediaDrm drm, byte[] sessionId,
+ byte[] keyId, byte[] message);
+
+ private static final native boolean verifyNative(MediaDrm drm, byte[] sessionId,
+ byte[] keyId, byte[] message,
+ byte[] signature);
+
+ public final class CryptoSession {
+ private MediaDrm mDrm;
+ private byte[] mSessionId;
+
+ /**
+ * Construct a CryptoSession which can be used to encrypt, decrypt,
+ * sign and verify messages or data using the session keys established
+ * for the session using methods {@link getKeyRequest} and
+ * {@link provideKeyResponse} using a session key server.
+ *
+ * @param sessionId the session ID for the session containing keys
+ * to be used for encrypt, decrypt, sign and/or verify
+ *
+ * @param cipherAlgorithm the algorithm to use for encryption and
+ * decryption ciphers. The algorithm string conforms to JCA Standard
+ * Names for Cipher Transforms and is case insensitive. For example
+ * "AES/CBC/PKCS5Padding".
+ *
+ * @param macAlgorithm the algorithm to use for sign and verify
+ * The algorithm string conforms to JCA Standard Names for Mac
+ * Algorithms and is case insensitive. For example "HmacSHA256".
+ *
+ * The list of supported algorithms for a DRM engine plugin can be obtained
+ * using the method {@link getPropertyString("algorithms")}
+ */
+
+ public CryptoSession(MediaDrm drm, byte[] sessionId,
+ String cipherAlgorithm, String macAlgorithm)
+ throws MediaDrmException {
+ mSessionId = sessionId;
+ mDrm = drm;
+ setCipherAlgorithmNative(drm, sessionId, cipherAlgorithm);
+ setMacAlgorithmNative(drm, sessionId, macAlgorithm);
+ }
+
+ public byte[] encrypt(byte[] keyid, byte[] input, byte[] iv) {
+ return encryptNative(mDrm, mSessionId, keyid, input, iv);
+ }
+
+ public byte[] decrypt(byte[] keyid, byte[] input, byte[] iv) {
+ return decryptNative(mDrm, mSessionId, keyid, input, iv);
+ }
+
+ public byte[] sign(byte[] keyid, byte[] message) {
+ return signNative(mDrm, mSessionId, keyid, message);
+ }
+ public boolean verify(byte[] keyid, byte[] message, byte[] signature) {
+ return verifyNative(mDrm, mSessionId, keyid, message, signature);
+ }
+ };
+
+ public CryptoSession getCryptoSession(byte[] sessionId,
+ String cipherAlgorithm,
+ String macAlgorithm)
+ throws MediaDrmException {
+ return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm);
+ }
+
@Override
protected void finalize() {
native_finalize();
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 9938f76..1618edf 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -76,7 +76,7 @@
struct fields_t {
jfieldID context;
- RequestFields licenseRequest;
+ RequestFields keyRequest;
RequestFields provisionRequest;
ArrayListFields arraylist;
HashmapFields hashmap;
@@ -204,6 +204,7 @@
}
return result;
}
+
/*
import java.util.HashMap;
import java.util.Set;
@@ -329,9 +330,9 @@
FIND_CLASS(clazz, "android/media/MediaDrm");
GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "I");
- FIND_CLASS(clazz, "android/media/MediaDrm$LicenseRequest");
- GET_FIELD_ID(gFields.licenseRequest.data, clazz, "data", "[B");
- GET_FIELD_ID(gFields.licenseRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
+ FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
+ GET_FIELD_ID(gFields.keyRequest.data, clazz, "data", "[B");
+ GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
GET_FIELD_ID(gFields.provisionRequest.data, clazz, "data", "[B");
@@ -451,9 +452,9 @@
throwExceptionAsNecessary(env, err, "Failed to close session");
}
-static jobject android_media_MediaDrm_getLicenseRequest(
+static jobject android_media_MediaDrm_getKeyRequest(
JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
- jstring jmimeType, jint jlicenseType, jobject joptParams) {
+ jstring jmimeType, jint jkeyType, jobject joptParams) {
sp<IDrm> drm = GetDrm(env, thiz);
if (!CheckSession(env, drm, jsessionId)) {
@@ -472,7 +473,7 @@
mimeType = JStringToString8(env, jmimeType);
}
- DrmPlugin::LicenseType licenseType = (DrmPlugin::LicenseType)jlicenseType;
+ DrmPlugin::KeyType keyType = (DrmPlugin::KeyType)jkeyType;
KeyedVector<String8, String8> optParams;
if (joptParams != NULL) {
@@ -482,68 +483,94 @@
Vector<uint8_t> request;
String8 defaultUrl;
- status_t err = drm->getLicenseRequest(sessionId, initData, mimeType,
- licenseType, optParams, request, defaultUrl);
+ status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
+ keyType, optParams, request, defaultUrl);
- if (throwExceptionAsNecessary(env, err, "Failed to get license request")) {
+ if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
return NULL;
}
// Fill out return obj
jclass clazz;
- FIND_CLASS(clazz, "android/media/MediaDrm$LicenseRequest");
+ FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
- jobject licenseObj = NULL;
+ jobject keyObj = NULL;
if (clazz) {
- licenseObj = env->AllocObject(clazz);
+ keyObj = env->AllocObject(clazz);
jbyteArray jrequest = VectorToJByteArray(env, request);
- env->SetObjectField(licenseObj, gFields.licenseRequest.data, jrequest);
+ env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
- env->SetObjectField(licenseObj, gFields.licenseRequest.defaultUrl, jdefaultUrl);
+ env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
}
- return licenseObj;
+ return keyObj;
}
-static void android_media_MediaDrm_provideLicenseResponse(
+static jbyteArray android_media_MediaDrm_provideKeyResponse(
JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
sp<IDrm> drm = GetDrm(env, thiz);
if (!CheckSession(env, drm, jsessionId)) {
- return;
+ return NULL;
}
Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
if (jresponse == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return;
+ return NULL;
}
Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
+ Vector<uint8_t> keySetId;
- status_t err = drm->provideLicenseResponse(sessionId, response);
+ status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
- throwExceptionAsNecessary(env, err, "Failed to handle license response");
+ throwExceptionAsNecessary(env, err, "Failed to handle key response");
+ return VectorToJByteArray(env, keySetId);
}
-static void android_media_MediaDrm_removeLicense(
- JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
+static void android_media_MediaDrm_removeKeys(
+ JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (jkeysetId == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
+
+ status_t err = drm->removeKeys(keySetId);
+
+ throwExceptionAsNecessary(env, err, "Failed to remove keys");
+}
+
+static void android_media_MediaDrm_restoreKeys(
+ JNIEnv *env, jobject thiz, jbyteArray jsessionId,
+ jbyteArray jkeysetId) {
+
sp<IDrm> drm = GetDrm(env, thiz);
if (!CheckSession(env, drm, jsessionId)) {
return;
}
+ if (jkeysetId == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+ Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
- status_t err = drm->removeLicense(sessionId);
+ status_t err = drm->restoreKeys(sessionId, keySetId);
- throwExceptionAsNecessary(env, err, "Failed to remove license");
+ throwExceptionAsNecessary(env, err, "Failed to restore keys");
}
-static jobject android_media_MediaDrm_queryLicenseStatus(
+static jobject android_media_MediaDrm_queryKeyStatus(
JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
sp<IDrm> drm = GetDrm(env, thiz);
@@ -554,9 +581,9 @@
KeyedVector<String8, String8> infoMap;
- status_t err = drm->queryLicenseStatus(sessionId, infoMap);
+ status_t err = drm->queryKeyStatus(sessionId, infoMap);
- if (throwExceptionAsNecessary(env, err, "Failed to query license")) {
+ if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
return NULL;
}
@@ -752,6 +779,162 @@
throwExceptionAsNecessary(env, err, "Failed to set property");
}
+static void android_media_MediaDrm_setCipherAlgorithmNative(
+ JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+ jstring jalgorithm) {
+
+ sp<IDrm> drm = GetDrm(env, jdrm);
+
+ if (!CheckSession(env, drm, jsessionId)) {
+ return;
+ }
+
+ if (jalgorithm == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+ String8 algorithm = JStringToString8(env, jalgorithm);
+
+ status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
+
+ throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
+}
+
+static void android_media_MediaDrm_setMacAlgorithmNative(
+ JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+ jstring jalgorithm) {
+
+ sp<IDrm> drm = GetDrm(env, jdrm);
+
+ if (!CheckSession(env, drm, jsessionId)) {
+ return;
+ }
+
+ if (jalgorithm == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+ String8 algorithm = JStringToString8(env, jalgorithm);
+
+ status_t err = drm->setMacAlgorithm(sessionId, algorithm);
+
+ throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
+}
+
+
+static jbyteArray android_media_MediaDrm_encryptNative(
+ JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+ jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
+
+ sp<IDrm> drm = GetDrm(env, jdrm);
+
+ if (!CheckSession(env, drm, jsessionId)) {
+ return NULL;
+ }
+
+ if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return NULL;
+ }
+
+ Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+ Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
+ Vector<uint8_t> input(JByteArrayToVector(env, jinput));
+ Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
+ Vector<uint8_t> output;
+
+ status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
+
+ throwExceptionAsNecessary(env, err, "Failed to encrypt");
+
+ return VectorToJByteArray(env, output);
+}
+
+static jbyteArray android_media_MediaDrm_decryptNative(
+ JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+ jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
+
+ sp<IDrm> drm = GetDrm(env, jdrm);
+
+ if (!CheckSession(env, drm, jsessionId)) {
+ return NULL;
+ }
+
+ if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return NULL;
+ }
+
+ Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+ Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
+ Vector<uint8_t> input(JByteArrayToVector(env, jinput));
+ Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
+ Vector<uint8_t> output;
+
+ status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
+ throwExceptionAsNecessary(env, err, "Failed to decrypt");
+
+ return VectorToJByteArray(env, output);
+}
+
+static jbyteArray android_media_MediaDrm_signNative(
+ JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+ jbyteArray jkeyId, jbyteArray jmessage) {
+
+ sp<IDrm> drm = GetDrm(env, jdrm);
+
+ if (!CheckSession(env, drm, jsessionId)) {
+ return NULL;
+ }
+
+ if (jkeyId == NULL || jmessage == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return NULL;
+ }
+
+ Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+ Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
+ Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
+ Vector<uint8_t> signature;
+
+ status_t err = drm->sign(sessionId, keyId, message, signature);
+
+ throwExceptionAsNecessary(env, err, "Failed to sign");
+
+ return VectorToJByteArray(env, signature);
+}
+
+static jboolean android_media_MediaDrm_verifyNative(
+ JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+ jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
+
+ sp<IDrm> drm = GetDrm(env, jdrm);
+
+ if (!CheckSession(env, drm, jsessionId)) {
+ return false;
+ }
+
+ if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return false;
+ }
+
+ Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+ Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
+ Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
+ Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
+ bool match;
+
+ status_t err = drm->verify(sessionId, keyId, message, signature, match);
+
+ throwExceptionAsNecessary(env, err, "Failed to verify");
+ return match;
+}
+
static JNINativeMethod gMethods[] = {
{ "release", "()V", (void *)android_media_MediaDrm_release },
@@ -772,18 +955,21 @@
{ "closeSession", "([B)V",
(void *)android_media_MediaDrm_closeSession },
- { "getLicenseRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
- "Landroid/media/MediaDrm$LicenseRequest;",
- (void *)android_media_MediaDrm_getLicenseRequest },
+ { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
+ "Landroid/media/MediaDrm$KeyRequest;",
+ (void *)android_media_MediaDrm_getKeyRequest },
- { "provideLicenseResponse", "([B[B)V",
- (void *)android_media_MediaDrm_provideLicenseResponse },
+ { "provideKeyResponse", "([B[B)[B",
+ (void *)android_media_MediaDrm_provideKeyResponse },
- { "removeLicense", "([B)V",
- (void *)android_media_MediaDrm_removeLicense },
+ { "removeKeys", "([B)V",
+ (void *)android_media_MediaDrm_removeKeys },
- { "queryLicenseStatus", "([B)Ljava/util/HashMap;",
- (void *)android_media_MediaDrm_queryLicenseStatus },
+ { "restoreKeys", "([B[B)V",
+ (void *)android_media_MediaDrm_restoreKeys },
+
+ { "queryKeyStatus", "([B)Ljava/util/HashMap;",
+ (void *)android_media_MediaDrm_queryKeyStatus },
{ "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
(void *)android_media_MediaDrm_getProvisionRequest },
@@ -808,6 +994,26 @@
{ "setPropertyByteArray", "(Ljava/lang/String;[B)V",
(void *)android_media_MediaDrm_setPropertyByteArray },
+
+ { "setCipherAlgorithmNative",
+ "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
+ (void *)android_media_MediaDrm_setCipherAlgorithmNative },
+
+ { "setMacAlgorithmNative",
+ "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
+ (void *)android_media_MediaDrm_setMacAlgorithmNative },
+
+ { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
+ (void *)android_media_MediaDrm_encryptNative },
+
+ { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
+ (void *)android_media_MediaDrm_decryptNative },
+
+ { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
+ (void *)android_media_MediaDrm_signNative },
+
+ { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
+ (void *)android_media_MediaDrm_verifyNative },
};
int register_android_media_Drm(JNIEnv *env) {