Merge "Initial OMA DRM forward lock contribution"

This commit is contained in:
Gloria Wang
2011-01-13 10:51:13 -08:00
committed by Android Code Review
27 changed files with 5370 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
#
# Copyright (C) 2010 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
include $(call all-subdir-makefiles)

View File

@@ -0,0 +1,52 @@
#
# Copyright (C) 2010 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
src/MimeTypeUtil.cpp
LOCAL_MODULE := libdrmutility
LOCAL_SHARED_LIBRARIES := \
libutils \
libdl \
libdvm \
libandroid_runtime \
libnativehelper \
liblog
base := frameworks/base
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
$(base)/include \
$(base)/include/drm \
$(base)/include/drm/plugins \
$(LOCAL_PATH)/include
ifneq ($(TARGET_BUILD_VARIANT),user)
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/tools
endif
LOCAL_MODULE_TAGS := optional
include $(BUILD_STATIC_LIBRARY)

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __MIMETYPEUTIL_H__
#define __MIMETYPEUTIL_H__
#include <utils/String8.h>
namespace android {
class MimeTypeUtil {
public:
MimeTypeUtil() {}
virtual ~MimeTypeUtil() {}
/**
* May convert the mimetype if there is a well known
* replacement mimetype otherwise the original mimetype
* is returned.
*
* @param mimeType - mimetype in lower case to convert.
*
* @return mimetype or null.
*/
static String8 convertMimeType(String8& mimeType);
};
};
#endif /* __MIMETYPEUTIL_H__ */

View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __SESSIONMAP_H__
#define __SESSIONMAP_H__
#include <utils/KeyedVector.h>
namespace android {
/**
* A wrapper template class for handling DRM Engine sessions.
*/
template <typename NODE>
class SessionMap {
public:
KeyedVector<int, NODE> map;
SessionMap() {}
virtual ~SessionMap() {
destroyMap();
}
/**
* Adds a new value in the session map table. It expects memory to be allocated already
* for the session object
*
* @param key - key or Session ID
* @param value - session object to add
*
* @return boolean result of adding value. returns false if key is already exist.
*/
bool addValue(int key, NODE value) {
bool result = false;
if (!isCreated(key)) {
map.add(key, value);
result = true;
}
return result;
}
/**
* returns the session object by the key
*
* @param key - key or Session ID
*
* @return session object as per the key
*/
NODE getValue(int key) {
NODE value = NULL;
if (isCreated(key)) {
value = (NODE) map.valueFor(key);
}
return value;
}
/**
* returns the number of objects in the session map table
*
* @return count of number of session objects.
*/
int getSize() {
return map.size();
}
/**
* returns the session object by the index in the session map table
*
* @param index - index of the value required
*
* @return session object as per the index
*/
NODE getValueAt(unsigned int index) {
NODE value = NULL;
if (map.size() > index) {
value = map.valueAt(index);
}
return value;
}
/**
* deletes the object from session map. It also frees up memory for the session object.
*
* @param key - key of the value to be deleted
*
*/
void removeValue(int key) {
deleteValue(getValue(key));
map.removeItem(key);
}
/**
* decides if session is already created.
*
* @param key - key of the value for the session
*
* @return boolean result of whether session is created
*/
bool isCreated(int key) {
return (0 <= map.indexOfKey(key));
}
/**
* empty the entire session table. It releases all the memory for session objects.
*/
void destroyMap() {
int size = map.size();
int i = 0;
for (i = 0; i < size; i++) {
deleteValue(map.valueAt(i));
}
map.clear();
}
/**
* free up the memory for the session object.
* Make sure if any reference to the session object anywhere, otherwise it will be a
* dangle pointer after this call.
*
* @param value - session object to free
*
*/
void deleteValue(NODE value) {
delete value;
}
};
};
#endif /* __SESSIONMAP_H__ */

View File

@@ -0,0 +1,154 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <MimeTypeUtil.h>
#include <utils/Log.h>
namespace android {
#undef LOG_TAG
#define LOG_TAG "MimeTypeUtil"
enum {
MIMETYPE_AUDIO = 0,
MIMETYPE_APPLICATION = 1,
MIMETYPE_IMAGE = 2,
MIMETYPE_VIDEO = 3,
MIMETYPE_LAST = -1,
};
struct MimeGroup{
int type; // Audio, video,.. use the enum values
const char* pGroup; // "audio/", "video/",.. should contain the last "/"
int size; // Number of bytes. e.g. "audio/" = 6 bytes
};
struct MimeTypeList{
int type;
const char* pMimeExt; // Everything after the '/' e.g. audio/x-mpeg -> "x-mpeg"
int size; // Number of bytes. e.g. "x-mpeg" = 6 bytes
const char* pMimeType; // Mimetype that should be returned
};
// Known mimetypes by android
static const char mime_type_audio_mpeg[] = "audio/mpeg";
static const char mime_type_audio_3gpp[] = "audio/3gpp";
static const char mime_type_audio_amr[] = "audio/amr-wb";
static const char mime_type_audio_aac[] = "audio/mp4a-latm";
static const char mime_type_audio_wav[] = "audio/wav";
static const char mime_type_video_mpeg4[] = "video/mpeg4";
static const char mime_type_video_3gpp[] = "video/3gpp";
// Known mimetype groups
static const char mime_group_audio[] = "audio/";
static const char mime_group_application[] = "application/";
static const char mime_group_image[] = "image/";
static const char mime_group_video[] = "video/";
static struct MimeGroup mimeGroup[] = {
{MIMETYPE_AUDIO, mime_group_audio, sizeof(mime_group_audio)-1},
{MIMETYPE_APPLICATION, mime_group_application, sizeof(mime_group_application)-1},
{MIMETYPE_IMAGE, mime_group_image, sizeof(mime_group_image)-1},
{MIMETYPE_VIDEO, mime_group_video, sizeof(mime_group_video)-1},
{MIMETYPE_LAST, NULL, 0} // Must be last entry
};
// List of all mimetypes that should be converted.
static struct MimeTypeList mimeTypeList[] = {
// Mp3 mime types
{MIMETYPE_AUDIO, "mp3", sizeof("mp3")-1, mime_type_audio_mpeg},
{MIMETYPE_AUDIO, "x-mpeg", sizeof("x-mpeg")-1, mime_type_audio_mpeg},
{MIMETYPE_AUDIO, "x-mp3", sizeof("x-mp3")-1, mime_type_audio_mpeg},
{MIMETYPE_AUDIO, "mpg", sizeof("mpg")-1, mime_type_audio_mpeg},
{MIMETYPE_AUDIO, "mpg3", sizeof("mpg")-1, mime_type_audio_mpeg},
{MIMETYPE_AUDIO, "x-mpg", sizeof("x-mpg")-1, mime_type_audio_mpeg},
{MIMETYPE_AUDIO, "x-mpegaudio", sizeof("x-mpegaudio")-1, mime_type_audio_mpeg},
// 3gpp audio mime types
{MIMETYPE_AUDIO, "3gp", sizeof("3gp")-1, mime_type_audio_3gpp},
// Amr audio mime types
{MIMETYPE_AUDIO, "amr", sizeof("amr")-1, mime_type_audio_amr},
// Aac audio mime types
{MIMETYPE_AUDIO, "aac", sizeof("aac")-1, mime_type_audio_aac},
// Wav audio mime types
{MIMETYPE_AUDIO, "x-wav", sizeof("x-wav")-1, mime_type_audio_wav},
// Mpeg4 video mime types
{MIMETYPE_VIDEO, "mpg4", sizeof("mpg4")-1, mime_type_video_mpeg4},
{MIMETYPE_VIDEO, "mp4v-es", sizeof("mp4v-es")-1, mime_type_video_mpeg4},
// 3gpp video mime types
{MIMETYPE_VIDEO, "3gp", sizeof("3gp")-1, mime_type_video_3gpp},
// Must be last entry
{MIMETYPE_LAST, NULL, 0, NULL}
};
/**
* May convert the mimetype if there is a well known
* replacement mimetype otherwise the original mimetype
* is returned.
*
* @param mimeType - mimetype in lower case to convert.
*
* @return mimetype or null.
*/
String8 MimeTypeUtil::convertMimeType(String8& mimeType) {
String8 result = mimeType;
const char* pTmp;
const char* pMimeType;
struct MimeGroup* pGroup;
struct MimeTypeList* pMimeItem;
int len;
pMimeType = mimeType.string();
if (NULL != pMimeType) {
/* Check which group the mimetype is */
pGroup = mimeGroup;
while (MIMETYPE_LAST != pGroup->type) {
if (0 == strncmp(pMimeType, pGroup->pGroup, pGroup->size)) {
break;
}
pGroup++;
}
/* Go through the mimetype list. Only check items of the correct group */
if (MIMETYPE_LAST != pGroup->type) {
pMimeItem = mimeTypeList;
len = strlen (pMimeType+pGroup->size);
while (MIMETYPE_LAST != pMimeItem->type) {
if ((len == pMimeItem->size) &&
(0 == strcmp(pMimeType+pGroup->size, pMimeItem->pMimeExt))) {
result = String8(pMimeItem->pMimeType);
break;
}
pMimeItem++;
}
}
LOGI("convertMimeType got mimetype %s, converted into mimetype %s",
pMimeType, result.string());
}
return result;
}
};

View File

@@ -0,0 +1,16 @@
#
# Copyright (C) 2010 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
include $(call all-subdir-makefiles)

View File

@@ -0,0 +1,67 @@
#
# Copyright (C) 2010 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
base := frameworks/base
# Determine whether the DRM framework uses 64-bit data types for file offsets and do the same.
ifneq ($(shell grep -c 'off64_t offset' $(base)/drm/libdrmframework/plugins/common/include/IDrmEngine.h), 0)
LOCAL_CFLAGS += -DUSE_64BIT_DRM_API
endif
LOCAL_SRC_FILES:= \
src/FwdLockEngine.cpp
LOCAL_MODULE := libfwdlockengine
LOCAL_SHARED_LIBRARIES := \
libicui18n \
libicuuc \
libutils \
libdl \
libandroid_runtime \
libnativehelper \
libcrypto \
libssl \
libdrmframework
LOCAL_STATIC_LIBRARIES := \
libdrmutility \
libdrmframeworkcommon \
libfwdlock-common \
libfwdlock-converter \
libfwdlock-decoder
LOCAL_PRELINK_MODULE := false
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
$(base)/include/drm \
$(base)/drm/libdrmframework/plugins/common/include \
$(base)/drm/libdrmframework/plugins/common/util/include \
$(base)/drm/libdrmframework/plugins/forward-lock/internal-format/common \
$(base)/drm/libdrmframework/plugins/forward-lock/internal-format/converter \
$(base)/drm/libdrmframework/plugins/forward-lock/internal-format/decoder \
$(LOCAL_PATH)/include \
external/openssl/include
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/drm/plugins/native
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)

View File

@@ -0,0 +1,559 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __FWDLOCKENGINE_H__
#define __FWDLOCKENGINE_H__
#include <DrmEngineBase.h>
#include <DrmConstraints.h>
#include <DrmRights.h>
#include <DrmInfo.h>
#include <DrmInfoStatus.h>
#include <DrmConvertedStatus.h>
#include <DrmInfoRequest.h>
#include <DrmSupportInfo.h>
#include <DrmInfoEvent.h>
#include "SessionMap.h"
#include "FwdLockConv.h"
namespace android {
/**
* Forward Lock Engine class.
*/
class FwdLockEngine : public android::DrmEngineBase {
public:
FwdLockEngine();
virtual ~FwdLockEngine();
protected:
/**
* Get constraint information associated with input content.
*
* @param uniqueId Unique identifier for a session
* @param path Path of the protected content
* @param action Actions defined such as,
* Action::DEFAULT, Action::PLAY, etc
* @return DrmConstraints
* key-value pairs of constraint are embedded in it
* @note
* In case of error, return NULL
*/
DrmConstraints* onGetConstraints(int uniqueId, const String8* path, int action);
/**
* Get metadata information associated with input content.
*
* @param uniqueId Unique identifier for a session
* @param path Path of the protected content
* @return DrmMetadata
* For Forward Lock engine, it returns an empty object
* @note
* In case of error, returns NULL
*/
DrmMetadata* onGetMetadata(int uniqueId, const String8* path);
/**
* Initialize plug-in.
*
* @param uniqueId Unique identifier for a session
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
status_t onInitialize(int uniqueId);
/**
* Register a callback to be invoked when the caller required to
* receive necessary information.
*
* @param uniqueId Unique identifier for a session
* @param infoListener Listener
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
status_t onSetOnInfoListener(int uniqueId, const IDrmEngine::OnInfoListener* infoListener);
/**
* Terminate the plug-in and release resources bound to it.
*
* @param uniqueId Unique identifier for a session
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
status_t onTerminate(int uniqueId);
/**
* Get whether the given content can be handled by this plugin or not.
*
* @param uniqueId Unique identifier for a session
* @param path Path to the protected object
* @return bool
* Returns true if this plugin can handle , false in case of not able to handle
*/
bool onCanHandle(int uniqueId, const String8& path);
/**
* Processes the given DRM information as appropriate for its type.
* Not used for Forward Lock Engine.
*
* @param uniqueId Unique identifier for a session
* @param drmInfo Information that needs to be processed
* @return DrmInfoStatus
* instance as a result of processing given input
*/
DrmInfoStatus* onProcessDrmInfo(int uniqueId, const DrmInfo* drmInfo);
/**
* Save DRM rights to specified rights path
* and make association with content path.
*
* @param uniqueId Unique identifier for a session
* @param drmRights DrmRights to be saved
* @param rightsPath File path where rights to be saved
* @param contentPath File path where content was saved
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
status_t onSaveRights(int uniqueId,
const DrmRights& drmRights,
const String8& rightsPath,
const String8& contentPath);
/**
* Retrieves necessary information for registration, unregistration or rights
* acquisition information.
*
* @param uniqueId Unique identifier for a session
* @param drmInfoRequest Request information to retrieve drmInfo
* @return DrmInfo
* instance as a result of processing given input
*/
DrmInfo* onAcquireDrmInfo(int uniqueId,
const DrmInfoRequest* drmInfoRequest);
/**
* Retrieves the mime type embedded inside the original content.
*
* @param uniqueId Unique identifier for a session
* @param path Path of the protected content
* @return String8
* Returns mime-type of the original content, such as "video/mpeg"
*/
String8 onGetOriginalMimeType(int uniqueId, const String8& path);
/**
* Retrieves the type of the protected object (content, rights, etc..)
* using specified path or mimetype. At least one parameter should be non null
* to retrieve DRM object type.
*
* @param uniqueId Unique identifier for a session
* @param path Path of the content or null.
* @param mimeType Mime type of the content or null.
* @return type of the DRM content,
* such as DrmObjectType::CONTENT, DrmObjectType::RIGHTS_OBJECT
*/
int onGetDrmObjectType(int uniqueId,
const String8& path,
const String8& mimeType);
/**
* Check whether the given content has valid rights or not.
*
* @param uniqueId Unique identifier for a session
* @param path Path of the protected content
* @param action Action to perform (Action::DEFAULT, Action::PLAY, etc)
* @return the status of the rights for the protected content,
* such as RightsStatus::RIGHTS_VALID, RightsStatus::RIGHTS_EXPIRED, etc.
*/
int onCheckRightsStatus(int uniqueId,
const String8& path,
int action);
/**
* Consumes the rights for a content.
* If the reserve parameter is true the rights are reserved until the same
* application calls this api again with the reserve parameter set to false.
*
* @param uniqueId Unique identifier for a session
* @param decryptHandle Handle for the decryption session
* @param action Action to perform. (Action::DEFAULT, Action::PLAY, etc)
* @param reserve True if the rights should be reserved.
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
status_t onConsumeRights(int uniqueId,
DecryptHandle* decryptHandle,
int action,
bool reserve);
/**
* Informs the DRM Engine about the playback actions performed on the DRM files.
*
* @param uniqueId Unique identifier for a session
* @param decryptHandle Handle for the decryption session
* @param playbackStatus Playback action (Playback::START, Playback::STOP, Playback::PAUSE)
* @param position Position in the file (in milliseconds) where the start occurs.
* Only valid together with Playback::START.
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
#ifdef USE_64BIT_DRM_API
status_t onSetPlaybackStatus(int uniqueId,
DecryptHandle* decryptHandle,
int playbackStatus,
int64_t position);
#else
status_t onSetPlaybackStatus(int uniqueId,
DecryptHandle* decryptHandle,
int playbackStatus,
int position);
#endif
/**
* Validates whether an action on the DRM content is allowed or not.
*
* @param uniqueId Unique identifier for a session
* @param path Path of the protected content
* @param action Action to validate (Action::PLAY, Action::TRANSFER, etc)
* @param description Detailed description of the action
* @return true if the action is allowed.
*/
bool onValidateAction(int uniqueId,
const String8& path,
int action,
const ActionDescription& description);
/**
* Removes the rights associated with the given protected content.
* Not used for Forward Lock Engine.
*
* @param uniqueId Unique identifier for a session
* @param path Path of the protected content
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
status_t onRemoveRights(int uniqueId, const String8& path);
/**
* Removes all the rights information of each plug-in associated with
* DRM framework. Will be used in master reset but does nothing for
* Forward Lock Engine.
*
* @param uniqueId Unique identifier for a session
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
status_t onRemoveAllRights(int uniqueId);
/**
* Starts the Forward Lock file conversion session.
* Each time the application tries to download a new DRM file
* which needs to be converted, then the application has to
* begin with calling this API. The convertId is used as the conversion session key
* and must not be the same for different convert sessions.
*
* @param uniqueId Unique identifier for a session
* @param convertId Handle for the convert session
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
status_t onOpenConvertSession(int uniqueId, int convertId);
/**
* Accepts and converts the input data which is part of DRM file.
* The resultant converted data and the status is returned in the DrmConvertedInfo
* object. This method will be called each time there is a new block
* of data received by the application.
*
* @param uniqueId Unique identifier for a session
* @param convertId Handle for the convert session
* @param inputData Input Data which need to be converted
* @return Return object contains the status of the data conversion,
* the output converted data and offset. In this case the
* application will ignore the offset information.
*/
DrmConvertedStatus* onConvertData(int uniqueId,
int convertId,
const DrmBuffer* inputData);
/**
* Closes the convert session in case of data supply completed or error occurred.
* Upon successful conversion of the complete data, it returns signature calculated over
* the entire data used over a conversion session. This signature must be copied to the offset
* mentioned in the DrmConvertedStatus. Signature is used for data integrity protection.
*
* @param uniqueId Unique identifier for a session
* @param convertId Handle for the convert session
* @return Return object contains the status of the data conversion,
* the header and body signature data. It also informs
* the application about the file offset at which this
* signature data should be written.
*/
DrmConvertedStatus* onCloseConvertSession(int uniqueId, int convertId);
/**
* Returns the information about the Drm Engine capabilities which includes
* supported MimeTypes and file suffixes.
*
* @param uniqueId Unique identifier for a session
* @return DrmSupportInfo
* instance which holds the capabilities of a plug-in
*/
DrmSupportInfo* onGetSupportInfo(int uniqueId);
/**
* Open the decrypt session to decrypt the given protected content.
*
* @param uniqueId Unique identifier for a session
* @param decryptHandle Handle for the current decryption session
* @param fd File descriptor of the protected content to be decrypted
* @param offset Start position of the content
* @param length The length of the protected content
* @return
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
#ifdef USE_64BIT_DRM_API
status_t onOpenDecryptSession(int uniqueId,
DecryptHandle* decryptHandle,
int fd, off64_t offset, off64_t length);
#else
status_t onOpenDecryptSession(int uniqueId,
DecryptHandle* decryptHandle,
int fd, int offset, int length);
#endif
/**
* Open the decrypt session to decrypt the given protected content.
*
* @param uniqueId Unique identifier for a session
* @param decryptHandle Handle for the current decryption session
* @param uri Path of the protected content to be decrypted
* @return
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
status_t onOpenDecryptSession(int uniqueId,
DecryptHandle* decryptHandle,
const char* uri);
/**
* Close the decrypt session for the given handle.
*
* @param uniqueId Unique identifier for a session
* @param decryptHandle Handle for the decryption session
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
status_t onCloseDecryptSession(int uniqueId,
DecryptHandle* decryptHandle);
/**
* Initialize decryption for the given unit of the protected content.
*
* @param uniqueId Unique identifier for a session
* @param decryptHandle Handle for the decryption session
* @param decryptUnitId ID which specifies decryption unit, such as track ID
* @param headerInfo Information for initializing decryption of this decrypUnit
* @return
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
status_t onInitializeDecryptUnit(int uniqueId,
DecryptHandle* decryptHandle,
int decryptUnitId,
const DrmBuffer* headerInfo);
/**
* Decrypt the protected content buffers for the given unit.
* This method will be called any number of times, based on number of
* encrypted streams received from application.
*
* @param uniqueId Unique identifier for a session
* @param decryptHandle Handle for the decryption session
* @param decryptUnitId ID which specifies decryption unit, such as track ID
* @param encBuffer Encrypted data block
* @param decBuffer Decrypted data block
* @return status_t
* Returns the error code for this API
* DRM_NO_ERROR for success, and one of DRM_ERROR_UNKNOWN, DRM_ERROR_LICENSE_EXPIRED
* DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
* DRM_ERROR_DECRYPT for failure.
*/
status_t onDecrypt(int uniqueId,
DecryptHandle* decryptHandle,
int decryptUnitId,
const DrmBuffer* encBuffer,
DrmBuffer** decBuffer);
/**
* Decrypt the protected content buffers for the given unit.
* This method will be called any number of times, based on number of
* encrypted streams received from application.
*
* @param uniqueId Unique identifier for a session
* @param decryptId Handle for the decryption session
* @param decryptUnitId ID Specifies decryption unit, such as track ID
* @param encBuffer Encrypted data block
* @param decBuffer Decrypted data block
* @param IV Optional buffer
* @return status_t
* Returns the error code for this API
* DRM_NO_ERROR for success, and one of DRM_ERROR_UNKNOWN, DRM_ERROR_LICENSE_EXPIRED
* DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
* DRM_ERROR_DECRYPT for failure.
*/
status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle,
int decryptUnitId, const DrmBuffer* encBuffer,
DrmBuffer** decBuffer, DrmBuffer* IV);
/**
* Finalize decryption for the given unit of the protected content.
*
* @param uniqueId Unique identifier for a session
* @param decryptHandle Handle for the decryption session
* @param decryptUnitId ID Specifies decryption unit, such as track ID
* @return
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
status_t onFinalizeDecryptUnit(int uniqueId,
DecryptHandle* decryptHandle,
int decryptUnitId);
/**
* Reads the specified number of bytes from an open DRM file.
*
* @param uniqueId Unique identifier for a session
* @param decryptHandle Handle for the decryption session
* @param buffer Reference to the buffer that should receive the read data.
* @param numBytes Number of bytes to read.
*
* @return Number of bytes read.
* @retval -1 Failure.
*/
ssize_t onRead(int uniqueId,
DecryptHandle* decryptHandle,
void* pBuffer,
int numBytes);
/**
* Updates the file position within an open DRM file.
*
* @param uniqueId Unique identifier for a session
* @param decryptHandle Handle for the decryption session
* @param offset Offset with which to update the file position.
* @param whence One of SEEK_SET, SEEK_CUR, and SEEK_END.
* These constants are defined in unistd.h.
*
* @return New file position.
* @retval ((off_t)-1) Failure.
*/
#ifdef USE_64BIT_DRM_API
off64_t onLseek(int uniqueId,
DecryptHandle* decryptHandle,
off64_t offset,
int whence);
#else
off_t onLseek(int uniqueId,
DecryptHandle* decryptHandle,
off_t offset,
int whence);
#endif
/**
* Reads the specified number of bytes from an open DRM file.
*
* @param uniqueId Unique identifier for a session
* @param decryptHandle Handle for the decryption session
* @param buffer Reference to the buffer that should receive the read data.
* @param numBytes Number of bytes to read.
* @param offset Offset with which to update the file position.
*
* @return Number of bytes read. Returns -1 for Failure.
*/
#ifdef USE_64BIT_DRM_API
ssize_t onPread(int uniqueId,
DecryptHandle* decryptHandle,
void* buffer,
ssize_t numBytes,
off64_t offset);
#else
ssize_t onPread(int uniqueId,
DecryptHandle* decryptHandle,
void* buffer,
ssize_t numBytes,
off_t offset);
#endif
private:
/**
* Session Class for Forward Lock Conversion. An object of this class is created
* for every conversion.
*/
class ConvertSession {
public :
int uniqueId;
FwdLockConv_Output_t output;
ConvertSession() {
uniqueId = 0;
memset(&output, 0, sizeof(FwdLockConv_Output_t));
}
virtual ~ConvertSession() {}
};
/**
* Session Class for Forward Lock decoder. An object of this class is created
* for every decoding session.
*/
class DecodeSession {
public :
int fileDesc;
off_t offset;
DecodeSession() {
fileDesc = -1;
offset = 0;
}
DecodeSession(int fd) {
fileDesc = fd;
offset = 0;
}
virtual ~DecodeSession() {}
};
/**
* Session Map Tables for Conversion and Decoding of forward lock files.
*/
SessionMap<ConvertSession*> convertSessionMap;
SessionMap<DecodeSession*> decodeSessionMap;
/**
* Converts the error code from Forward Lock Converter to DrmConvertStatus error code.
*
* @param Forward Lock Converter error code
*
* @return Status code from DrmConvertStatus.
*/
static int getConvertedStatus(FwdLockConv_Status_t status);
};
};
#endif /* __FWDLOCKENGINE_H__ */

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __FWDLOCKENGINECONST_H__
#define __FWDLOCKENGINECONST_H__
namespace android {
/**
* Constants for forward Lock Engine used for exposing engine's capabilities.
*/
#define FWDLOCK_EXTENSION_FL ("FL")
#define FWDLOCK_DOTEXTENSION_FL (".fl")
#define FWDLOCK_MIMETYPE_FL ("application/x-android-drm-fl")
#define FWDLOCK_EXTENSION_DM ("DM")
#define FWDLOCK_DOTEXTENSION_DM (".dm")
#define FWDLOCK_MIMETYPE_DM ("application/vnd.oma.drm.message")
#define FWDLOCK_DESCRIPTION ("OMA V1 Forward Lock")
};
#endif /* __FWDLOCKENGINECONST_H__ */

View File

@@ -0,0 +1,628 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "SessionMap.h"
#include "FwdLockEngine.h"
#include <utils/Log.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include "drm_framework_common.h"
#include <fcntl.h>
#include <limits.h>
#include <DrmRights.h>
#include <DrmConstraints.h>
#include <DrmMetadata.h>
#include <DrmInfo.h>
#include <DrmInfoStatus.h>
#include <DrmInfoRequest.h>
#include <DrmSupportInfo.h>
#include <DrmConvertedStatus.h>
#include <utils/String8.h>
#include "FwdLockConv.h"
#include "FwdLockFile.h"
#include "FwdLockGlue.h"
#include "FwdLockEngineConst.h"
#include "MimeTypeUtil.h"
#undef LOG_TAG
#define LOG_TAG "FwdLockEngine"
using namespace android;
// This extern "C" is mandatory to be managed by TPlugInManager
extern "C" IDrmEngine* create() {
return new FwdLockEngine();
}
// This extern "C" is mandatory to be managed by TPlugInManager
extern "C" void destroy(IDrmEngine* plugIn) {
delete plugIn;
}
FwdLockEngine::FwdLockEngine() {
LOGD("FwdLockEngine Construction");
}
FwdLockEngine::~FwdLockEngine() {
LOGD("FwdLockEngine Destruction");
convertSessionMap.destroyMap();
decodeSessionMap.destroyMap();
}
int FwdLockEngine::getConvertedStatus(FwdLockConv_Status_t status) {
int retStatus = DrmConvertedStatus::STATUS_ERROR;
switch(status) {
case FwdLockConv_Status_OK:
retStatus = DrmConvertedStatus::STATUS_OK;
break;
case FwdLockConv_Status_SyntaxError:
case FwdLockConv_Status_InvalidArgument:
case FwdLockConv_Status_UnsupportedFileFormat:
case FwdLockConv_Status_UnsupportedContentTransferEncoding:
LOGD("FwdLockEngine getConvertedStatus: file conversion Error %d. " \
"Returning STATUS_INPUTDATA_ERROR", status);
retStatus = DrmConvertedStatus::STATUS_INPUTDATA_ERROR;
break;
default:
LOGD("FwdLockEngine getConvertedStatus: file conversion Error %d. " \
"Returning STATUS_ERROR", status);
retStatus = DrmConvertedStatus::STATUS_ERROR;
break;
}
return retStatus;
}
DrmConstraints* FwdLockEngine::onGetConstraints(int uniqueId, const String8* path, int action) {
DrmConstraints* drmConstraints = NULL;
LOGD("FwdLockEngine::onGetConstraints");
if (NULL != path &&
(RightsStatus::RIGHTS_VALID == onCheckRightsStatus(uniqueId, *path, action))) {
// Return the empty constraints to show no error condition.
drmConstraints = new DrmConstraints();
}
return drmConstraints;
}
DrmMetadata* FwdLockEngine::onGetMetadata(int uniqueId, const String8* path) {
DrmMetadata* drmMetadata = NULL;
LOGD("FwdLockEngine::onGetMetadata");
if (NULL != path) {
// Returns empty metadata to show no error condition.
drmMetadata = new DrmMetadata();
}
return drmMetadata;
}
android::status_t FwdLockEngine::onInitialize(int uniqueId) {
LOGD("FwdLockEngine::onInitialize");
if (FwdLockGlue_InitializeKeyEncryption()) {
LOGD("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption succeeded");
} else {
LOGD("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption failed:"
"errno = %d", errno);
}
return DRM_NO_ERROR;
}
android::status_t
FwdLockEngine::onSetOnInfoListener(int uniqueId, const IDrmEngine::OnInfoListener* infoListener) {
// Not used
LOGD("FwdLockEngine::onSetOnInfoListener");
return DRM_NO_ERROR;
}
android::status_t FwdLockEngine::onTerminate(int uniqueId) {
LOGD("FwdLockEngine::onTerminate");
return DRM_NO_ERROR;
}
DrmSupportInfo* FwdLockEngine::onGetSupportInfo(int uniqueId) {
DrmSupportInfo* pSupportInfo = new DrmSupportInfo();
LOGD("FwdLockEngine::onGetSupportInfo");
// fill all Forward Lock mimetypes and extensions
if (NULL != pSupportInfo) {
pSupportInfo->addMimeType(String8(FWDLOCK_MIMETYPE_FL));
pSupportInfo->addFileSuffix(String8(FWDLOCK_DOTEXTENSION_FL));
pSupportInfo->addMimeType(String8(FWDLOCK_MIMETYPE_DM));
pSupportInfo->addFileSuffix(String8(FWDLOCK_DOTEXTENSION_DM));
pSupportInfo->setDescription(String8(FWDLOCK_DESCRIPTION));
}
return pSupportInfo;
}
bool FwdLockEngine::onCanHandle(int uniqueId, const String8& path) {
bool result = false;
String8 extString = path.getPathExtension();
extString.toLower();
if ((extString == String8(FWDLOCK_DOTEXTENSION_FL)) ||
(extString == String8(FWDLOCK_DOTEXTENSION_DM))) {
result = true;
}
return result;
}
DrmInfoStatus* FwdLockEngine::onProcessDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
DrmInfoStatus *drmInfoStatus = NULL;
// Nothing to process
drmInfoStatus = new DrmInfoStatus((int)DrmInfoStatus::STATUS_OK, 0, NULL, String8(""));
LOGD("FwdLockEngine::onProcessDrmInfo");
return drmInfoStatus;
}
status_t FwdLockEngine::onSaveRights(
int uniqueId,
const DrmRights& drmRights,
const String8& rightsPath,
const String8& contentPath) {
// No rights to save. Return
LOGD("FwdLockEngine::onSaveRights");
return DRM_ERROR_UNKNOWN;
}
DrmInfo* FwdLockEngine::onAcquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
DrmInfo* drmInfo = NULL;
// Nothing to be done for Forward Lock file
LOGD("FwdLockEngine::onAcquireDrmInfo");
return drmInfo;
}
int FwdLockEngine::onCheckRightsStatus(int uniqueId,
const String8& path,
int action) {
int result = RightsStatus::RIGHTS_INVALID;
LOGD("FwdLockEngine::onCheckRightsStatus");
// Only Transfer action is not allowed for forward Lock files.
if (onCanHandle(uniqueId, path)) {
switch(action) {
case Action::DEFAULT:
case Action::PLAY:
case Action::RINGTONE:
case Action::OUTPUT:
case Action::PREVIEW:
case Action::EXECUTE:
case Action::DISPLAY:
result = RightsStatus::RIGHTS_VALID;
break;
case Action::TRANSFER:
default:
result = RightsStatus::RIGHTS_INVALID;
break;
}
}
return result;
}
status_t FwdLockEngine::onConsumeRights(int uniqueId,
DecryptHandle* decryptHandle,
int action,
bool reserve) {
// No rights consumption
LOGD("FwdLockEngine::onConsumeRights");
return DRM_NO_ERROR;
}
bool FwdLockEngine::onValidateAction(int uniqueId,
const String8& path,
int action,
const ActionDescription& description) {
LOGD("FwdLockEngine::onValidateAction");
// For the forwardlock engine checkRights and ValidateAction are the same.
return (onCheckRightsStatus(uniqueId, path, action) == RightsStatus::RIGHTS_VALID);
}
String8 FwdLockEngine::onGetOriginalMimeType(int uniqueId, const String8& path) {
LOGD("FwdLockEngine::onGetOriginalMimeType");
String8 mimeString = String8("");
int fileDesc = FwdLockFile_open(path.string());
if (-1 < fileDesc) {
const char* pMimeType = FwdLockFile_GetContentType(fileDesc);
if (NULL != pMimeType) {
String8 contentType = String8(pMimeType);
contentType.toLower();
mimeString = MimeTypeUtil::convertMimeType(contentType);
}
FwdLockFile_close(fileDesc);
}
return mimeString;
}
int FwdLockEngine::onGetDrmObjectType(int uniqueId,
const String8& path,
const String8& mimeType) {
String8 mimeStr = String8(mimeType);
LOGD("FwdLockEngine::onGetDrmObjectType");
mimeStr.toLower();
/* Checks whether
* 1. path and mime type both are not empty strings (meaning unavailable) else content is unknown
* 2. if one of them is empty string and if other is known then its a DRM Content Object.
* 3. if both of them are available, then both may be of known type
* (regardless of the relation between them to make it compatible with other DRM Engines)
*/
if (((0 == path.length()) || onCanHandle(uniqueId, path)) &&
((0 == mimeType.length()) || ((mimeStr == String8(FWDLOCK_MIMETYPE_FL)) ||
(mimeStr == String8(FWDLOCK_MIMETYPE_DM)))) && (mimeType != path) ) {
return DrmObjectType::CONTENT;
}
return DrmObjectType::UNKNOWN;
}
status_t FwdLockEngine::onRemoveRights(int uniqueId, const String8& path) {
// No Rights to remove
LOGD("FwdLockEngine::onRemoveRights");
return DRM_NO_ERROR;
}
status_t FwdLockEngine::onRemoveAllRights(int uniqueId) {
// No rights to remove
LOGD("FwdLockEngine::onRemoveAllRights");
return DRM_NO_ERROR;
}
#ifdef USE_64BIT_DRM_API
status_t FwdLockEngine::onSetPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
int playbackStatus, int64_t position) {
#else
status_t FwdLockEngine::onSetPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
int playbackStatus, int position) {
#endif
// Not used
LOGD("FwdLockEngine::onSetPlaybackStatus");
return DRM_NO_ERROR;
}
status_t FwdLockEngine::onOpenConvertSession(int uniqueId,
int convertId) {
status_t result = DRM_ERROR_UNKNOWN;
LOGD("FwdLockEngine::onOpenConvertSession");
if (!convertSessionMap.isCreated(convertId)) {
ConvertSession *newSession = new ConvertSession();
if (FwdLockConv_Status_OK ==
FwdLockConv_OpenSession(&(newSession->uniqueId), &(newSession->output))) {
convertSessionMap.addValue(convertId, newSession);
result = DRM_NO_ERROR;
} else {
LOGD("FwdLockEngine::onOpenConvertSession -- FwdLockConv_OpenSession failed.");
delete newSession;
}
}
return result;
}
DrmConvertedStatus* FwdLockEngine::onConvertData(int uniqueId,
int convertId,
const DrmBuffer* inputData) {
FwdLockConv_Status_t retStatus = FwdLockConv_Status_InvalidArgument;
DrmBuffer *convResult = new DrmBuffer(NULL, 0);
int offset = -1;
if (NULL != inputData && convertSessionMap.isCreated(convertId)) {
ConvertSession *convSession = convertSessionMap.getValue(convertId);
if (NULL != convSession) {
retStatus = FwdLockConv_ConvertData(convSession->uniqueId,
inputData->data,
inputData->length,
&(convSession->output));
if (FwdLockConv_Status_OK == retStatus) {
// return bytes from conversion if available
if (convSession->output.fromConvertData.numBytes > 0) {
convResult->data = new char[convSession->output.fromConvertData.numBytes];
if (NULL != convResult->data) {
convResult->length = convSession->output.fromConvertData.numBytes;
memcpy(convResult->data,
(char *)convSession->output.fromConvertData.pBuffer,
convResult->length);
}
}
} else {
offset = convSession->output.fromConvertData.errorPos;
}
}
}
return new DrmConvertedStatus(getConvertedStatus(retStatus), convResult, offset);
}
DrmConvertedStatus* FwdLockEngine::onCloseConvertSession(int uniqueId,
int convertId) {
FwdLockConv_Status_t retStatus = FwdLockConv_Status_InvalidArgument;
DrmBuffer *convResult = new DrmBuffer(NULL, 0);
int offset = -1;
LOGD("FwdLockEngine::onCloseConvertSession");
if (convertSessionMap.isCreated(convertId)) {
ConvertSession *convSession = convertSessionMap.getValue(convertId);
if (NULL != convSession) {
retStatus = FwdLockConv_CloseSession(convSession->uniqueId, &(convSession->output));
if (FwdLockConv_Status_OK == retStatus) {
offset = convSession->output.fromCloseSession.fileOffset;
convResult->data = new char[FWD_LOCK_SIGNATURES_SIZE];
if (NULL != convResult->data) {
convResult->length = FWD_LOCK_SIGNATURES_SIZE;
memcpy(convResult->data,
(char *)convSession->output.fromCloseSession.signatures,
convResult->length);
}
}
}
convertSessionMap.removeValue(convertId);
}
return new DrmConvertedStatus(getConvertedStatus(retStatus), convResult, offset);
}
#ifdef USE_64BIT_DRM_API
status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
DecryptHandle* decryptHandle,
int fd,
off64_t offset,
off64_t length) {
#else
status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
DecryptHandle* decryptHandle,
int fd,
int offset,
int length) {
#endif
status_t result = DRM_ERROR_CANNOT_HANDLE;
int fileDesc = -1;
LOGD("FwdLockEngine::onOpenDecryptSession");
if ((-1 < fd) &&
(NULL != decryptHandle) &&
(!decodeSessionMap.isCreated(decryptHandle->decryptId))) {
fileDesc = dup(fd);
} else {
LOGD("FwdLockEngine::onOpenDecryptSession parameter error");
return result;
}
if (-1 < fileDesc &&
-1 < ::lseek(fileDesc, offset, SEEK_SET) &&
-1 < FwdLockFile_attach(fileDesc)) {
// check for file integrity. This must be done to protect the content mangling.
int retVal = FwdLockFile_CheckHeaderIntegrity(fileDesc);
DecodeSession* decodeSession = new DecodeSession(fileDesc);
if (retVal && NULL != decodeSession) {
decodeSessionMap.addValue(decryptHandle->decryptId, decodeSession);
const char *pmime= FwdLockFile_GetContentType(fileDesc);
String8 contentType = String8(pmime == NULL ? "" : pmime);
contentType.toLower();
decryptHandle->mimeType = MimeTypeUtil::convertMimeType(contentType);
decryptHandle->decryptApiType = DecryptApiType::CONTAINER_BASED;
decryptHandle->status = RightsStatus::RIGHTS_VALID;
decryptHandle->decryptInfo = NULL;
result = DRM_NO_ERROR;
} else {
LOGD("FwdLockEngine::onOpenDecryptSession Integrity Check failed for the fd");
FwdLockFile_detach(fileDesc);
::close(fileDesc);
delete decodeSession;
}
}
LOGD("FwdLockEngine::onOpenDecryptSession Exit. result = %d", result);
return result;
}
status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
DecryptHandle* decryptHandle,
const char* uri) {
status_t result = DRM_ERROR_CANNOT_HANDLE;
const char fileTag [] = "file://";
if (NULL != decryptHandle && NULL != uri && strlen(uri) > sizeof(fileTag)) {
String8 uriTag = String8(uri);
uriTag.toLower();
if (0 == strncmp(uriTag.string(), fileTag, sizeof(fileTag) - 1)) {
const char *filePath = strchr(uri + sizeof(fileTag) - 1, '/');
if (NULL != filePath && onCanHandle(uniqueId, String8(filePath))) {
int fd = open(filePath, O_RDONLY);
if (-1 < fd) {
// offset is always 0 and length is not used. so any positive size.
result = onOpenDecryptSession(uniqueId, decryptHandle, fd, 0, 1);
// fd is duplicated already if success. closing the file
close(fd);
}
}
}
}
return result;
}
status_t FwdLockEngine::onCloseDecryptSession(int uniqueId,
DecryptHandle* decryptHandle) {
status_t result = DRM_ERROR_UNKNOWN;
LOGD("FwdLockEngine::onCloseDecryptSession");
if (NULL != decryptHandle && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
if (NULL != session && session->fileDesc > -1) {
FwdLockFile_detach(session->fileDesc);
::close(session->fileDesc);
decodeSessionMap.removeValue(decryptHandle->decryptId);
result = DRM_NO_ERROR;
}
}
LOGD("FwdLockEngine::onCloseDecryptSession Exit");
return result;
}
status_t FwdLockEngine::onInitializeDecryptUnit(int uniqueId,
DecryptHandle* decryptHandle,
int decryptUnitId,
const DrmBuffer* headerInfo) {
LOGD("FwdLockEngine::onInitializeDecryptUnit");
return DRM_ERROR_UNKNOWN;
}
status_t FwdLockEngine::onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
LOGD("FwdLockEngine::onDecrypt");
return DRM_ERROR_UNKNOWN;
}
status_t FwdLockEngine::onDecrypt(int uniqueId,
DecryptHandle* decryptHandle,
int decryptUnitId,
const DrmBuffer* encBuffer,
DrmBuffer** decBuffer) {
LOGD("FwdLockEngine::onDecrypt");
return DRM_ERROR_UNKNOWN;
}
status_t FwdLockEngine::onFinalizeDecryptUnit(int uniqueId,
DecryptHandle* decryptHandle,
int decryptUnitId) {
LOGD("FwdLockEngine::onFinalizeDecryptUnit");
return DRM_ERROR_UNKNOWN;
}
ssize_t FwdLockEngine::onRead(int uniqueId,
DecryptHandle* decryptHandle,
void* buffer,
int numBytes) {
ssize_t size = -1;
if (NULL != decryptHandle &&
decodeSessionMap.isCreated(decryptHandle->decryptId) &&
NULL != buffer &&
numBytes > -1) {
DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
if (NULL != session && session->fileDesc > -1) {
size = FwdLockFile_read(session->fileDesc, buffer, numBytes);
if (0 > size) {
session->offset = ((off_t)-1);
} else {
session->offset += size;
}
}
}
return size;
}
#ifdef USE_64BIT_DRM_API
off64_t FwdLockEngine::onLseek(int uniqueId, DecryptHandle* decryptHandle,
off64_t offset, int whence) {
#else
off_t FwdLockEngine::onLseek(int uniqueId, DecryptHandle* decryptHandle,
off_t offset, int whence) {
#endif
off_t offval = -1;
if (NULL != decryptHandle && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
if (NULL != session && session->fileDesc > -1) {
offval = FwdLockFile_lseek(session->fileDesc, offset, whence);
session->offset = offval;
}
}
return offval;
}
#ifdef USE_64BIT_DRM_API
ssize_t FwdLockEngine::onPread(int uniqueId,
DecryptHandle* decryptHandle,
void* buffer,
ssize_t numBytes,
off64_t offset) {
#else
ssize_t FwdLockEngine::onPread(int uniqueId,
DecryptHandle* decryptHandle,
void* buffer,
ssize_t numBytes,
off_t offset) {
#endif
ssize_t bytesRead = -1;
DecodeSession* decoderSession = NULL;
if ((NULL != decryptHandle) &&
(NULL != (decoderSession = decodeSessionMap.getValue(decryptHandle->decryptId))) &&
(NULL != buffer) &&
(numBytes > -1) &&
(offset > -1)) {
if (offset != decoderSession->offset) {
decoderSession->offset = onLseek(uniqueId, decryptHandle, offset, SEEK_SET);
}
if (((off_t)-1) != decoderSession->offset) {
bytesRead = onRead(uniqueId, decryptHandle, buffer, numBytes);
if (bytesRead < 0) {
LOGD("FwdLockEngine::onPread error reading");
}
}
} else {
LOGD("FwdLockEngine::onPread decryptId not found");
}
return bytesRead;
}

View File

@@ -0,0 +1,16 @@
#
# Copyright (C) 2010 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
include $(call all-subdir-makefiles)

View File

@@ -0,0 +1,32 @@
#
# Copyright (C) 2010 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
FwdLockGlue.c
LOCAL_C_INCLUDES := \
external/openssl/include
LOCAL_SHARED_LIBRARIES := libcrypto
LOCAL_MODULE := libfwdlock-common
LOCAL_MODULE_TAGS := optional
include $(BUILD_STATIC_LIBRARY)

View File

@@ -0,0 +1,191 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <openssl/aes.h>
#include "FwdLockGlue.h"
#define TRUE 1
#define FALSE 0
#define KEY_SIZE 16
#define KEY_SIZE_IN_BITS (KEY_SIZE * 8)
static int isInitialized = FALSE;
static const char strKeyFilename[] = "/data/drm/fwdlock/kek.dat";
static AES_KEY encryptionRoundKeys;
static AES_KEY decryptionRoundKeys;
/**
* Creates all directories along the fully qualified path of the given file.
*
* @param[in] path A reference to the fully qualified path of a file.
* @param[in] mode The access mode to use for the directories being created.
*
* @return A Boolean value indicating whether the operation was successful.
*/
static int FwdLockGlue_CreateDirectories(const char *path, mode_t mode) {
int result = TRUE;
size_t partialPathLength = strlen(path);
char *partialPath = malloc(partialPathLength + 1);
if (partialPath == NULL) {
result = FALSE;
} else {
size_t i;
for (i = 0; i < partialPathLength; ++i) {
if (path[i] == '/' && i > 0) {
partialPath[i] = '\0';
if (mkdir(partialPath, mode) != 0 && errno != EEXIST) {
result = FALSE;
break;
}
}
partialPath[i] = path[i];
}
free(partialPath);
}
return result;
}
/**
* Initializes the round keys used for encryption and decryption of session keys. First creates a
* device-unique key-encryption key if none exists yet.
*/
static void FwdLockGlue_InitializeRoundKeys() {
unsigned char keyEncryptionKey[KEY_SIZE];
int fileDesc = open(strKeyFilename, O_RDONLY);
if (fileDesc >= 0) {
if (read(fileDesc, keyEncryptionKey, KEY_SIZE) == KEY_SIZE) {
isInitialized = TRUE;
}
(void)close(fileDesc);
} else if (errno == ENOENT &&
FwdLockGlue_GetRandomNumber(keyEncryptionKey, KEY_SIZE) &&
FwdLockGlue_CreateDirectories(strKeyFilename, S_IRWXU)) {
fileDesc = open(strKeyFilename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR);
if (fileDesc >= 0) {
if (write(fileDesc, keyEncryptionKey, KEY_SIZE) == KEY_SIZE) {
isInitialized = TRUE;
}
(void)close(fileDesc);
}
}
if (isInitialized) {
if (AES_set_encrypt_key(keyEncryptionKey, KEY_SIZE_IN_BITS, &encryptionRoundKeys) != 0 ||
AES_set_decrypt_key(keyEncryptionKey, KEY_SIZE_IN_BITS, &decryptionRoundKeys) != 0) {
isInitialized = FALSE;
}
}
memset(keyEncryptionKey, 0, KEY_SIZE); // Zero out key data.
}
/**
* Validates the padding of a decrypted key.
*
* @param[in] pData A reference to the buffer containing the decrypted key and padding.
* @param[in] decryptedKeyLength The length in bytes of the decrypted key.
*
* @return A Boolean value indicating whether the padding was valid.
*/
static int FwdLockGlue_ValidatePadding(const unsigned char *pData, size_t decryptedKeyLength) {
size_t i;
size_t padding = AES_BLOCK_SIZE - (decryptedKeyLength % AES_BLOCK_SIZE);
pData += decryptedKeyLength;
for (i = 0; i < padding; ++i) {
if ((size_t)*pData != padding) {
return FALSE;
}
++pData;
}
return TRUE;
}
int FwdLockGlue_GetRandomNumber(void *pBuffer, size_t numBytes) {
// Generate 'cryptographically secure' random bytes by reading them from "/dev/urandom" (the
// non-blocking version of "/dev/random").
ssize_t numBytesRead = 0;
int fileDesc = open("/dev/urandom", O_RDONLY);
if (fileDesc >= 0) {
numBytesRead = read(fileDesc, pBuffer, numBytes);
(void)close(fileDesc);
}
return numBytesRead >= 0 && (size_t)numBytesRead == numBytes;
}
int FwdLockGlue_InitializeKeyEncryption() {
static pthread_once_t once = PTHREAD_ONCE_INIT;
pthread_once(&once, FwdLockGlue_InitializeRoundKeys);
return isInitialized;
}
size_t FwdLockGlue_GetEncryptedKeyLength(size_t plaintextKeyLength) {
return ((plaintextKeyLength / AES_BLOCK_SIZE) + 2) * AES_BLOCK_SIZE;
}
int FwdLockGlue_EncryptKey(const void *pPlaintextKey,
size_t plaintextKeyLength,
void *pEncryptedKey,
size_t encryptedKeyLength) {
int result = FALSE;
assert(encryptedKeyLength == FwdLockGlue_GetEncryptedKeyLength(plaintextKeyLength));
if (FwdLockGlue_InitializeKeyEncryption()) {
unsigned char initVector[AES_BLOCK_SIZE];
if (FwdLockGlue_GetRandomNumber(initVector, AES_BLOCK_SIZE)) {
size_t padding = AES_BLOCK_SIZE - (plaintextKeyLength % AES_BLOCK_SIZE);
size_t dataLength = encryptedKeyLength - AES_BLOCK_SIZE;
memcpy(pEncryptedKey, pPlaintextKey, plaintextKeyLength);
memset((unsigned char *)pEncryptedKey + plaintextKeyLength, (int)padding, padding);
memcpy((unsigned char *)pEncryptedKey + dataLength, initVector, AES_BLOCK_SIZE);
AES_cbc_encrypt(pEncryptedKey, pEncryptedKey, dataLength, &encryptionRoundKeys,
initVector, AES_ENCRYPT);
result = TRUE;
}
}
return result;
}
int FwdLockGlue_DecryptKey(const void *pEncryptedKey,
size_t encryptedKeyLength,
void *pDecryptedKey,
size_t decryptedKeyLength) {
int result = FALSE;
assert(encryptedKeyLength == FwdLockGlue_GetEncryptedKeyLength(decryptedKeyLength));
if (FwdLockGlue_InitializeKeyEncryption()) {
size_t dataLength = encryptedKeyLength - AES_BLOCK_SIZE;
unsigned char *pData = malloc(dataLength);
if (pData != NULL) {
unsigned char initVector[AES_BLOCK_SIZE];
memcpy(pData, pEncryptedKey, dataLength);
memcpy(initVector, (const unsigned char *)pEncryptedKey + dataLength, AES_BLOCK_SIZE);
AES_cbc_encrypt(pData, pData, dataLength, &decryptionRoundKeys, initVector,
AES_DECRYPT);
memcpy(pDecryptedKey, pData, decryptedKeyLength);
result = FwdLockGlue_ValidatePadding(pData, decryptedKeyLength);
free(pData);
}
}
return result;
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __FWDLOCKGLUE_H__
#define __FWDLOCKGLUE_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* Generates the specified number of cryptographically secure random bytes.
*
* @param[out] pBuffer A reference to the buffer that should receive the random data.
* @param[in] numBytes The number of random bytes to generate.
*
* @return A Boolean value indicating whether the operation was successful.
*/
int FwdLockGlue_GetRandomNumber(void *pBuffer, size_t numBytes);
/**
* Performs initialization of the key-encryption key. Should be called once during startup to
* facilitate encryption and decryption of session keys.
*
* @return A Boolean value indicating whether the operation was successful.
*/
int FwdLockGlue_InitializeKeyEncryption();
/**
* Returns the length of the encrypted key, given the length of the plaintext key.
*
* @param[in] plaintextKeyLength The length in bytes of the plaintext key.
*
* @return The length in bytes of the encrypted key.
*/
size_t FwdLockGlue_GetEncryptedKeyLength(size_t plaintextKeyLength);
/**
* Encrypts the given session key using a key-encryption key unique to this device.
*
* @param[in] pPlaintextKey A reference to the buffer containing the plaintext key.
* @param[in] plaintextKeyLength The length in bytes of the plaintext key.
* @param[out] pEncryptedKey A reference to the buffer containing the encrypted key.
* @param[in] encryptedKeyLength The length in bytes of the encrypted key.
*
* @return A Boolean value indicating whether the operation was successful.
*/
int FwdLockGlue_EncryptKey(const void *pPlaintextKey,
size_t plaintextKeyLength,
void *pEncryptedKey,
size_t encryptedKeyLength);
/**
* Decrypts the given session key using a key-encryption key unique to this device.
*
* @param[in] pEncryptedKey A reference to the buffer containing the encrypted key.
* @param[in] encryptedKeyLength The length in bytes of the encrypted key.
* @param[out] pDecryptedKey A reference to the buffer containing the decrypted key.
* @param[in] decryptedKeyLength The length in bytes of the decrypted key.
*
* @return A Boolean value indicating whether the operation was successful.
*/
int FwdLockGlue_DecryptKey(const void *pEncryptedKey,
size_t encryptedKeyLength,
void *pDecryptedKey,
size_t decryptedKeyLength);
#ifdef __cplusplus
}
#endif
#endif // __FWDLOCKGLUE_H__

View File

@@ -0,0 +1,37 @@
#
# Copyright (C) 2010 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
FwdLockConv.c
LOCAL_C_INCLUDES := \
frameworks/base/drm/libdrmframework/plugins/forward-lock/internal-format/common \
external/openssl/include
LOCAL_SHARED_LIBRARIES := libcrypto
LOCAL_WHOLE_STATIC_LIBRARIES := libfwdlock-common
LOCAL_STATIC_LIBRARIES := libfwdlock-common
LOCAL_MODULE := libfwdlock-converter
LOCAL_MODULE_TAGS := optional
include $(BUILD_STATIC_LIBRARY)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,282 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __FWDLOCKCONV_H__
#define __FWDLOCKCONV_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/types.h>
/**
* The size of the data and header signatures combined. The signatures are adjacent to each other in
* the produced output file.
*/
#define FWD_LOCK_SIGNATURES_SIZE (2 * 20)
/**
* Data type for the output from FwdLockConv_ConvertData.
*/
typedef struct FwdLockConv_ConvertData_Output {
/// The converted data.
void *pBuffer;
/// The size of the converted data.
size_t numBytes;
/// The file position where the error occurred, in the case of a syntax error.
off64_t errorPos;
} FwdLockConv_ConvertData_Output_t;
/**
* Data type for the output from FwdLockConv_CloseSession.
*/
typedef struct FwdLockConv_CloseSession_Output {
/// The final set of signatures.
unsigned char signatures[FWD_LOCK_SIGNATURES_SIZE];
/// The offset in the produced output file where the signatures are located.
off64_t fileOffset;
/// The file position where the error occurred, in the case of a syntax error.
off64_t errorPos;
} FwdLockConv_CloseSession_Output_t;
/**
* Data type for the output from the conversion process.
*/
typedef union FwdLockConv_Output {
FwdLockConv_ConvertData_Output_t fromConvertData;
FwdLockConv_CloseSession_Output_t fromCloseSession;
} FwdLockConv_Output_t;
/**
* Data type for the Posix-style read function used by the converter in pull mode.
*
* @param[in] fileDesc The file descriptor of a file opened for reading.
* @param[out] pBuffer A reference to the buffer that should receive the read data.
* @param[in] numBytes The number of bytes to read.
*
* @return The number of bytes read.
* @retval -1 Failure.
*/
typedef ssize_t FwdLockConv_ReadFunc_t(int fileDesc, void *pBuffer, size_t numBytes);
/**
* Data type for the Posix-style write function used by the converter in pull mode.
*
* @param[in] fileDesc The file descriptor of a file opened for writing.
* @param[in] pBuffer A reference to the buffer containing the data to be written.
* @param[in] numBytes The number of bytes to write.
*
* @return The number of bytes written.
* @retval -1 Failure.
*/
typedef ssize_t FwdLockConv_WriteFunc_t(int fileDesc, const void *pBuffer, size_t numBytes);
/**
* Data type for the Posix-style lseek function used by the converter in pull mode.
*
* @param[in] fileDesc The file descriptor of a file opened for writing.
* @param[in] offset The offset with which to update the file position.
* @param[in] whence One of SEEK_SET, SEEK_CUR, and SEEK_END.
*
* @return The new file position.
* @retval ((off64_t)-1) Failure.
*/
typedef off64_t FwdLockConv_LSeekFunc_t(int fileDesc, off64_t offset, int whence);
/**
* The status codes returned by the converter functions.
*/
typedef enum FwdLockConv_Status {
/// The operation was successful.
FwdLockConv_Status_OK = 0,
/// An actual argument to the function is invalid (a program error on the caller's part).
FwdLockConv_Status_InvalidArgument = 1,
/// There is not enough free dynamic memory to complete the operation.
FwdLockConv_Status_OutOfMemory = 2,
/// An error occurred while opening the input file.
FwdLockConv_Status_FileNotFound = 3,
/// An error occurred while creating the output file.
FwdLockConv_Status_FileCreationFailed = 4,
/// An error occurred while reading from the input file.
FwdLockConv_Status_FileReadError = 5,
/// An error occurred while writing to the output file.
FwdLockConv_Status_FileWriteError = 6,
/// An error occurred while seeking to a new file position within the output file.
FwdLockConv_Status_FileSeekError = 7,
/// The input file is not a syntactically correct OMA DRM v1 Forward Lock file.
FwdLockConv_Status_SyntaxError = 8,
/// Support for this DRM file format has been disabled in the current product configuration.
FwdLockConv_Status_UnsupportedFileFormat = 9,
/// The content transfer encoding is not one of "binary", "base64", "7bit", or "8bit"
/// (case-insensitive).
FwdLockConv_Status_UnsupportedContentTransferEncoding = 10,
/// The generation of a random number failed.
FwdLockConv_Status_RandomNumberGenerationFailed = 11,
/// Key encryption failed.
FwdLockConv_Status_KeyEncryptionFailed = 12,
/// The calculation of a keyed hash for integrity protection failed.
FwdLockConv_Status_IntegrityProtectionFailed = 13,
/// There are too many ongoing sessions for another one to be opened.
FwdLockConv_Status_TooManySessions = 14,
/// An unexpected error occurred.
FwdLockConv_Status_ProgramError = 15
} FwdLockConv_Status_t;
/**
* Opens a session for converting an OMA DRM v1 Forward Lock file to the internal Forward Lock file
* format.
*
* @param[out] pSessionId The session ID.
* @param[out] pOutput The output from the conversion process (initialized).
*
* @return A status code.
* @retval FwdLockConv_Status_OK
* @retval FwdLockConv_Status_InvalidArgument
* @retval FwdLockConv_Status_TooManySessions
*/
FwdLockConv_Status_t FwdLockConv_OpenSession(int *pSessionId, FwdLockConv_Output_t *pOutput);
/**
* Supplies the converter with data to convert. The caller is expected to write the converted data
* to file. Can be called an arbitrary number of times.
*
* @param[in] sessionId The session ID.
* @param[in] pBuffer A reference to a buffer containing the data to convert.
* @param[in] numBytes The number of bytes to convert.
* @param[in,out] pOutput The output from the conversion process (allocated/reallocated).
*
* @return A status code.
* @retval FwdLockConv_Status_OK
* @retval FwdLockConv_Status_InvalidArgument
* @retval FwdLockConv_Status_OutOfMemory
* @retval FwdLockConv_Status_SyntaxError
* @retval FwdLockConv_Status_UnsupportedFileFormat
* @retval FwdLockConv_Status_UnsupportedContentTransferEncoding
* @retval FwdLockConv_Status_RandomNumberGenerationFailed
* @retval FwdLockConv_Status_KeyEncryptionFailed
* @retval FwdLockConv_Status_DataEncryptionFailed
*/
FwdLockConv_Status_t FwdLockConv_ConvertData(int sessionId,
const void *pBuffer,
size_t numBytes,
FwdLockConv_Output_t *pOutput);
/**
* Closes a session for converting an OMA DRM v1 Forward Lock file to the internal Forward Lock
* file format. The caller must update the produced output file at the indicated file offset with
* the final set of signatures.
*
* @param[in] sessionId The session ID.
* @param[in,out] pOutput The output from the conversion process (deallocated and overwritten).
*
* @return A status code.
* @retval FwdLockConv_Status_OK
* @retval FwdLockConv_Status_InvalidArgument
* @retval FwdLockConv_Status_OutOfMemory
* @retval FwdLockConv_Status_IntegrityProtectionFailed
*/
FwdLockConv_Status_t FwdLockConv_CloseSession(int sessionId, FwdLockConv_Output_t *pOutput);
/**
* Converts an open OMA DRM v1 Forward Lock file to the internal Forward Lock file format in pull
* mode.
*
* @param[in] inputFileDesc The file descriptor of the open input file.
* @param[in] fpReadFunc A reference to a read function that can operate on the open input file.
* @param[in] outputFileDesc The file descriptor of the open output file.
* @param[in] fpWriteFunc A reference to a write function that can operate on the open output file.
* @param[in] fpLSeekFunc A reference to an lseek function that can operate on the open output file.
* @param[out] pErrorPos
* The file position where the error occurred, in the case of a syntax error. May be NULL.
*
* @return A status code.
* @retval FwdLockConv_Status_OK
* @retval FwdLockConv_Status_InvalidArgument
* @retval FwdLockConv_Status_OutOfMemory
* @retval FwdLockConv_Status_FileReadError
* @retval FwdLockConv_Status_FileWriteError
* @retval FwdLockConv_Status_FileSeekError
* @retval FwdLockConv_Status_SyntaxError
* @retval FwdLockConv_Status_UnsupportedFileFormat
* @retval FwdLockConv_Status_UnsupportedContentTransferEncoding
* @retval FwdLockConv_Status_RandomNumberGenerationFailed
* @retval FwdLockConv_Status_KeyEncryptionFailed
* @retval FwdLockConv_Status_DataEncryptionFailed
* @retval FwdLockConv_Status_IntegrityProtectionFailed
* @retval FwdLockConv_Status_TooManySessions
*/
FwdLockConv_Status_t FwdLockConv_ConvertOpenFile(int inputFileDesc,
FwdLockConv_ReadFunc_t *fpReadFunc,
int outputFileDesc,
FwdLockConv_WriteFunc_t *fpWriteFunc,
FwdLockConv_LSeekFunc_t *fpLSeekFunc,
off64_t *pErrorPos);
/**
* Converts an OMA DRM v1 Forward Lock file to the internal Forward Lock file format in pull mode.
*
* @param[in] pInputFilename A reference to the input filename.
* @param[in] pOutputFilename A reference to the output filename.
* @param[out] pErrorPos
* The file position where the error occurred, in the case of a syntax error. May be NULL.
*
* @return A status code.
* @retval FwdLockConv_Status_OK
* @retval FwdLockConv_Status_InvalidArgument
* @retval FwdLockConv_Status_OutOfMemory
* @retval FwdLockConv_Status_FileNotFound
* @retval FwdLockConv_Status_FileCreationFailed
* @retval FwdLockConv_Status_FileReadError
* @retval FwdLockConv_Status_FileWriteError
* @retval FwdLockConv_Status_FileSeekError
* @retval FwdLockConv_Status_SyntaxError
* @retval FwdLockConv_Status_UnsupportedFileFormat
* @retval FwdLockConv_Status_UnsupportedContentTransferEncoding
* @retval FwdLockConv_Status_RandomNumberGenerationFailed
* @retval FwdLockConv_Status_KeyEncryptionFailed
* @retval FwdLockConv_Status_DataEncryptionFailed
* @retval FwdLockConv_Status_IntegrityProtectionFailed
* @retval FwdLockConv_Status_TooManySessions
*/
FwdLockConv_Status_t FwdLockConv_ConvertFile(const char *pInputFilename,
const char *pOutputFilename,
off64_t *pErrorPos);
#ifdef __cplusplus
}
#endif
#endif // __FWDLOCKCONV_H__

View File

@@ -0,0 +1,37 @@
#
# Copyright (C) 2010 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
FwdLockFile.c
LOCAL_C_INCLUDES := \
frameworks/base/drm/libdrmframework/plugins/forward-lock/internal-format/common \
external/openssl/include
LOCAL_SHARED_LIBRARIES := libcrypto
LOCAL_WHOLE_STATIC_LIBRARIES := libfwdlock-common
LOCAL_STATIC_LIBRARIES := libfwdlock-common
LOCAL_MODULE := libfwdlock-decoder
LOCAL_MODULE_TAGS := optional
include $(BUILD_STATIC_LIBRARY)

View File

@@ -0,0 +1,447 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openssl/aes.h>
#include <openssl/hmac.h>
#include "FwdLockFile.h"
#include "FwdLockGlue.h"
#define TRUE 1
#define FALSE 0
#define INVALID_OFFSET ((off64_t)-1)
#define INVALID_BLOCK_INDEX ((uint64_t)-1)
#define MAX_NUM_SESSIONS 128
#define KEY_SIZE AES_BLOCK_SIZE
#define KEY_SIZE_IN_BITS (KEY_SIZE * 8)
#define SHA1_HASH_SIZE 20
#define SHA1_BLOCK_SIZE 64
#define FWD_LOCK_VERSION 0
#define FWD_LOCK_SUBFORMAT 0
#define USAGE_RESTRICTION_FLAGS 0
#define CONTENT_TYPE_LENGTH_POS 7
#define TOP_HEADER_SIZE 8
#define SIG_CALC_BUFFER_SIZE (16 * SHA1_BLOCK_SIZE)
/**
* Data type for the per-file state information needed by the decoder.
*/
typedef struct FwdLockFile_Session {
int fileDesc;
unsigned char topHeader[TOP_HEADER_SIZE];
char *pContentType;
size_t contentTypeLength;
void *pEncryptedSessionKey;
size_t encryptedSessionKeyLength;
unsigned char dataSignature[SHA1_HASH_SIZE];
unsigned char headerSignature[SHA1_HASH_SIZE];
off64_t dataOffset;
off64_t filePos;
AES_KEY encryptionRoundKeys;
HMAC_CTX signingContext;
unsigned char keyStream[AES_BLOCK_SIZE];
uint64_t blockIndex;
} FwdLockFile_Session_t;
static FwdLockFile_Session_t *sessionPtrs[MAX_NUM_SESSIONS] = { NULL };
static pthread_mutex_t sessionAcquisitionMutex = PTHREAD_MUTEX_INITIALIZER;
static const unsigned char topHeaderTemplate[] =
{ 'F', 'W', 'L', 'K', FWD_LOCK_VERSION, FWD_LOCK_SUBFORMAT, USAGE_RESTRICTION_FLAGS };
/**
* Acquires an unused file session for the given file descriptor.
*
* @param[in] fileDesc A file descriptor.
*
* @return A session ID.
*/
static int FwdLockFile_AcquireSession(int fileDesc) {
int sessionId = -1;
if (fileDesc < 0) {
errno = EBADF;
} else {
int i;
pthread_mutex_lock(&sessionAcquisitionMutex);
for (i = 0; i < MAX_NUM_SESSIONS; ++i) {
int candidateSessionId = (fileDesc + i) % MAX_NUM_SESSIONS;
if (sessionPtrs[candidateSessionId] == NULL) {
sessionPtrs[candidateSessionId] = malloc(sizeof **sessionPtrs);
if (sessionPtrs[candidateSessionId] != NULL) {
sessionPtrs[candidateSessionId]->fileDesc = fileDesc;
sessionPtrs[candidateSessionId]->pContentType = NULL;
sessionPtrs[candidateSessionId]->pEncryptedSessionKey = NULL;
sessionId = candidateSessionId;
}
break;
}
}
pthread_mutex_unlock(&sessionAcquisitionMutex);
if (i == MAX_NUM_SESSIONS) {
errno = ENFILE;
}
}
return sessionId;
}
/**
* Finds the file session associated to the given file descriptor.
*
* @param[in] fileDesc A file descriptor.
*
* @return A session ID.
*/
static int FwdLockFile_FindSession(int fileDesc) {
int sessionId = -1;
if (fileDesc < 0) {
errno = EBADF;
} else {
int i;
pthread_mutex_lock(&sessionAcquisitionMutex);
for (i = 0; i < MAX_NUM_SESSIONS; ++i) {
int candidateSessionId = (fileDesc + i) % MAX_NUM_SESSIONS;
if (sessionPtrs[candidateSessionId] != NULL &&
sessionPtrs[candidateSessionId]->fileDesc == fileDesc) {
sessionId = candidateSessionId;
break;
}
}
pthread_mutex_unlock(&sessionAcquisitionMutex);
if (i == MAX_NUM_SESSIONS) {
errno = EBADF;
}
}
return sessionId;
}
/**
* Releases a file session.
*
* @param[in] sessionID A session ID.
*/
static void FwdLockFile_ReleaseSession(int sessionId) {
pthread_mutex_lock(&sessionAcquisitionMutex);
assert(0 <= sessionId && sessionId < MAX_NUM_SESSIONS && sessionPtrs[sessionId] != NULL);
free(sessionPtrs[sessionId]->pContentType);
free(sessionPtrs[sessionId]->pEncryptedSessionKey);
memset(sessionPtrs[sessionId], 0, sizeof *sessionPtrs[sessionId]); // Zero out key data.
free(sessionPtrs[sessionId]);
sessionPtrs[sessionId] = NULL;
pthread_mutex_unlock(&sessionAcquisitionMutex);
}
/**
* Derives keys for encryption and signing from the encrypted session key.
*
* @param[in,out] pSession A reference to a file session.
*
* @return A Boolean value indicating whether key derivation was successful.
*/
static int FwdLockFile_DeriveKeys(FwdLockFile_Session_t * pSession) {
int result;
struct FwdLockFile_DeriveKeys_Data {
AES_KEY sessionRoundKeys;
unsigned char value[KEY_SIZE];
unsigned char key[KEY_SIZE];
} *pData = malloc(sizeof *pData);
if (pData == NULL) {
result = FALSE;
} else {
result = FwdLockGlue_DecryptKey(pSession->pEncryptedSessionKey,
pSession->encryptedSessionKeyLength, pData->key, KEY_SIZE);
if (result) {
if (AES_set_encrypt_key(pData->key, KEY_SIZE_IN_BITS, &pData->sessionRoundKeys) != 0) {
result = FALSE;
} else {
// Encrypt the 16-byte value {0, 0, ..., 0} to produce the encryption key.
memset(pData->value, 0, KEY_SIZE);
AES_encrypt(pData->value, pData->key, &pData->sessionRoundKeys);
if (AES_set_encrypt_key(pData->key, KEY_SIZE_IN_BITS,
&pSession->encryptionRoundKeys) != 0) {
result = FALSE;
} else {
// Encrypt the 16-byte value {1, 0, ..., 0} to produce the signing key.
++pData->value[0];
AES_encrypt(pData->value, pData->key, &pData->sessionRoundKeys);
HMAC_CTX_init(&pSession->signingContext);
HMAC_Init_ex(&pSession->signingContext, pData->key, KEY_SIZE, EVP_sha1(), NULL);
}
}
}
if (!result) {
errno = ENOSYS;
}
memset(pData, 0, sizeof pData); // Zero out key data.
free(pData);
}
return result;
}
/**
* Calculates the counter, treated as a 16-byte little-endian number, used to generate the keystream
* for the given block.
*
* @param[in] pNonce A reference to the nonce.
* @param[in] blockIndex The index number of the block.
* @param[out] pCounter A reference to the counter.
*/
static void FwdLockFile_CalculateCounter(const unsigned char *pNonce,
uint64_t blockIndex,
unsigned char *pCounter) {
unsigned char carry = 0;
size_t i = 0;
for (; i < sizeof blockIndex; ++i) {
unsigned char part = pNonce[i] + (unsigned char)(blockIndex >> (i * CHAR_BIT));
pCounter[i] = part + carry;
carry = (part < pNonce[i] || pCounter[i] < part) ? 1 : 0;
}
for (; i < AES_BLOCK_SIZE; ++i) {
pCounter[i] = pNonce[i] + carry;
carry = (pCounter[i] < pNonce[i]) ? 1 : 0;
}
}
/**
* Decrypts the byte at the current file position using AES-128-CTR. In CTR (or "counter") mode,
* encryption and decryption are performed using the same algorithm.
*
* @param[in,out] pSession A reference to a file session.
* @param[in] pByte The byte to decrypt.
*/
void FwdLockFile_DecryptByte(FwdLockFile_Session_t * pSession, unsigned char *pByte) {
uint64_t blockIndex = pSession->filePos / AES_BLOCK_SIZE;
uint64_t blockOffset = pSession->filePos % AES_BLOCK_SIZE;
if (blockIndex != pSession->blockIndex) {
// The first 16 bytes of the encrypted session key is used as the nonce.
unsigned char counter[AES_BLOCK_SIZE];
FwdLockFile_CalculateCounter(pSession->pEncryptedSessionKey, blockIndex, counter);
AES_encrypt(counter, pSession->keyStream, &pSession->encryptionRoundKeys);
pSession->blockIndex = blockIndex;
}
*pByte ^= pSession->keyStream[blockOffset];
}
int FwdLockFile_attach(int fileDesc) {
int sessionId = FwdLockFile_AcquireSession(fileDesc);
if (sessionId >= 0) {
FwdLockFile_Session_t *pSession = sessionPtrs[sessionId];
int isSuccess = FALSE;
if (read(fileDesc, pSession->topHeader, TOP_HEADER_SIZE) == TOP_HEADER_SIZE &&
memcmp(pSession->topHeader, topHeaderTemplate, sizeof topHeaderTemplate) == 0) {
pSession->contentTypeLength = pSession->topHeader[CONTENT_TYPE_LENGTH_POS];
assert(pSession->contentTypeLength <= UCHAR_MAX); // Untaint scalar for code checkers.
pSession->pContentType = malloc(pSession->contentTypeLength + 1);
if (pSession->pContentType != NULL &&
read(fileDesc, pSession->pContentType, pSession->contentTypeLength) ==
(ssize_t)pSession->contentTypeLength) {
pSession->pContentType[pSession->contentTypeLength] = '\0';
pSession->encryptedSessionKeyLength = FwdLockGlue_GetEncryptedKeyLength(KEY_SIZE);
pSession->pEncryptedSessionKey = malloc(pSession->encryptedSessionKeyLength);
if (pSession->pEncryptedSessionKey != NULL &&
read(fileDesc, pSession->pEncryptedSessionKey,
pSession->encryptedSessionKeyLength) ==
(ssize_t)pSession->encryptedSessionKeyLength &&
read(fileDesc, pSession->dataSignature, SHA1_HASH_SIZE) ==
SHA1_HASH_SIZE &&
read(fileDesc, pSession->headerSignature, SHA1_HASH_SIZE) ==
SHA1_HASH_SIZE) {
isSuccess = FwdLockFile_DeriveKeys(pSession);
}
}
}
if (isSuccess) {
pSession->dataOffset = pSession->contentTypeLength +
pSession->encryptedSessionKeyLength + TOP_HEADER_SIZE + 2 * SHA1_HASH_SIZE;
pSession->filePos = 0;
pSession->blockIndex = INVALID_BLOCK_INDEX;
} else {
FwdLockFile_ReleaseSession(sessionId);
sessionId = -1;
}
}
return (sessionId >= 0) ? 0 : -1;
}
int FwdLockFile_open(const char *pFilename) {
int fileDesc = open(pFilename, O_RDONLY);
if (fileDesc >= 0 && FwdLockFile_attach(fileDesc) < 0) {
(void)close(fileDesc);
fileDesc = -1;
}
return fileDesc;
}
ssize_t FwdLockFile_read(int fileDesc, void *pBuffer, size_t numBytes) {
ssize_t numBytesRead;
int sessionId = FwdLockFile_FindSession(fileDesc);
if (sessionId < 0) {
numBytesRead = -1;
} else {
FwdLockFile_Session_t *pSession = sessionPtrs[sessionId];
ssize_t i;
numBytesRead = read(pSession->fileDesc, pBuffer, numBytes);
for (i = 0; i < numBytesRead; ++i) {
FwdLockFile_DecryptByte(pSession, &((unsigned char *)pBuffer)[i]);
++pSession->filePos;
}
}
return numBytesRead;
}
off64_t FwdLockFile_lseek(int fileDesc, off64_t offset, int whence) {
off64_t newFilePos;
int sessionId = FwdLockFile_FindSession(fileDesc);
if (sessionId < 0) {
newFilePos = INVALID_OFFSET;
} else {
FwdLockFile_Session_t *pSession = sessionPtrs[sessionId];
switch (whence) {
case SEEK_SET:
newFilePos = lseek64(pSession->fileDesc, pSession->dataOffset + offset, whence);
break;
case SEEK_CUR:
case SEEK_END:
newFilePos = lseek64(pSession->fileDesc, offset, whence);
break;
default:
errno = EINVAL;
newFilePos = INVALID_OFFSET;
break;
}
if (newFilePos != INVALID_OFFSET) {
if (newFilePos < pSession->dataOffset) {
// The new file position is illegal for an internal Forward Lock file. Restore the
// original file position.
(void)lseek64(pSession->fileDesc, pSession->dataOffset + pSession->filePos,
SEEK_SET);
errno = EINVAL;
newFilePos = INVALID_OFFSET;
} else {
// The return value should be the file position that lseek64() would have returned
// for the embedded content file.
pSession->filePos = newFilePos - pSession->dataOffset;
newFilePos = pSession->filePos;
}
}
}
return newFilePos;
}
int FwdLockFile_detach(int fileDesc) {
int sessionId = FwdLockFile_FindSession(fileDesc);
if (sessionId < 0) {
return -1;
}
HMAC_CTX_cleanup(&sessionPtrs[sessionId]->signingContext);
FwdLockFile_ReleaseSession(sessionId);
return 0;
}
int FwdLockFile_close(int fileDesc) {
return (FwdLockFile_detach(fileDesc) == 0) ? close(fileDesc) : -1;
}
int FwdLockFile_CheckDataIntegrity(int fileDesc) {
int result;
int sessionId = FwdLockFile_FindSession(fileDesc);
if (sessionId < 0) {
result = FALSE;
} else {
struct FwdLockFile_CheckDataIntegrity_Data {
unsigned char signature[SHA1_HASH_SIZE];
unsigned char buffer[SIG_CALC_BUFFER_SIZE];
} *pData = malloc(sizeof *pData);
if (pData == NULL) {
result = FALSE;
} else {
FwdLockFile_Session_t *pSession = sessionPtrs[sessionId];
if (lseek64(pSession->fileDesc, pSession->dataOffset, SEEK_SET) !=
pSession->dataOffset) {
result = FALSE;
} else {
ssize_t numBytesRead;
size_t signatureSize = SHA1_HASH_SIZE;
while ((numBytesRead =
read(pSession->fileDesc, pData->buffer, SIG_CALC_BUFFER_SIZE)) > 0) {
HMAC_Update(&pSession->signingContext, pData->buffer, (size_t)numBytesRead);
}
if (numBytesRead < 0) {
result = FALSE;
} else {
HMAC_Final(&pSession->signingContext, pData->signature, &signatureSize);
assert(signatureSize == SHA1_HASH_SIZE);
result = memcmp(pData->signature, pSession->dataSignature, signatureSize) == 0;
}
HMAC_Init_ex(&pSession->signingContext, NULL, KEY_SIZE, NULL, NULL);
(void)lseek64(pSession->fileDesc, pSession->dataOffset + pSession->filePos,
SEEK_SET);
}
free(pData);
}
}
return result;
}
int FwdLockFile_CheckHeaderIntegrity(int fileDesc) {
int result;
int sessionId = FwdLockFile_FindSession(fileDesc);
if (sessionId < 0) {
result = FALSE;
} else {
FwdLockFile_Session_t *pSession = sessionPtrs[sessionId];
unsigned char signature[SHA1_HASH_SIZE];
size_t signatureSize = SHA1_HASH_SIZE;
HMAC_Update(&pSession->signingContext, pSession->topHeader, TOP_HEADER_SIZE);
HMAC_Update(&pSession->signingContext, (unsigned char *)pSession->pContentType,
pSession->contentTypeLength);
HMAC_Update(&pSession->signingContext, pSession->pEncryptedSessionKey,
pSession->encryptedSessionKeyLength);
HMAC_Update(&pSession->signingContext, pSession->dataSignature, signatureSize);
HMAC_Final(&pSession->signingContext, signature, &signatureSize);
assert(signatureSize == SHA1_HASH_SIZE);
result = memcmp(signature, pSession->headerSignature, signatureSize) == 0;
HMAC_Init_ex(&pSession->signingContext, NULL, KEY_SIZE, NULL, NULL);
}
return result;
}
int FwdLockFile_CheckIntegrity(int fileDesc) {
return FwdLockFile_CheckHeaderIntegrity(fileDesc) && FwdLockFile_CheckDataIntegrity(fileDesc);
}
const char *FwdLockFile_GetContentType(int fileDesc) {
int sessionId = FwdLockFile_FindSession(fileDesc);
if (sessionId < 0) {
return NULL;
}
return sessionPtrs[sessionId]->pContentType;
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __FWDLOCKFILE_H__
#define __FWDLOCKFILE_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/types.h>
/**
* Attaches to an open Forward Lock file. The file position is assumed to be at the beginning of the
* file.
*
* @param[in] fileDesc The file descriptor of an open Forward Lock file.
*
* @return A status code.
* @retval 0 Success.
* @retval -1 Failure.
*/
int FwdLockFile_attach(int fileDesc);
/**
* Opens a Forward Lock file for reading.
*
* @param[in] pFilename A reference to a filename.
*
* @return A file descriptor.
* @retval -1 Failure.
*/
int FwdLockFile_open(const char *pFilename);
/**
* Reads the specified number of bytes from an open Forward Lock file.
*
* @param[in] fileDesc The file descriptor of an open Forward Lock file.
* @param[out] pBuffer A reference to the buffer that should receive the read data.
* @param[in] numBytes The number of bytes to read.
*
* @return The number of bytes read.
* @retval -1 Failure.
*/
ssize_t FwdLockFile_read(int fileDesc, void *pBuffer, size_t numBytes);
/**
* Updates the file position within an open Forward Lock file.
*
* @param[in] fileDesc The file descriptor of an open Forward Lock file.
* @param[in] offset The offset with which to update the file position.
* @param[in] whence One of SEEK_SET, SEEK_CUR, and SEEK_END.
*
* @return The new file position.
* @retval ((off64_t)-1) Failure.
*/
off64_t FwdLockFile_lseek(int fileDesc, off64_t offset, int whence);
/**
* Detaches from an open Forward Lock file.
*
* @param[in] fileDesc The file descriptor of an open Forward Lock file.
*
* @return A status code.
* @retval 0 Success.
* @retval -1 Failure.
*/
int FwdLockFile_detach(int fileDesc);
/**
* Closes an open Forward Lock file.
*
* @param[in] fileDesc The file descriptor of an open Forward Lock file.
*
* @return A status code.
* @retval 0 Success.
* @retval -1 Failure.
*/
int FwdLockFile_close(int fileDesc);
/**
* Checks the data integrity of an open Forward Lock file.
*
* @param[in] fileDesc The file descriptor of an open Forward Lock file.
*
* @return A Boolean value indicating whether the integrity check was successful.
*/
int FwdLockFile_CheckDataIntegrity(int fileDesc);
/**
* Checks the header integrity of an open Forward Lock file.
*
* @param[in] fileDesc The file descriptor of an open Forward Lock file.
*
* @return A Boolean value indicating whether the integrity check was successful.
*/
int FwdLockFile_CheckHeaderIntegrity(int fileDesc);
/**
* Checks both the data and header integrity of an open Forward Lock file.
*
* @param[in] fileDesc The file descriptor of an open Forward Lock file.
*
* @return A Boolean value indicating whether the integrity check was successful.
*/
int FwdLockFile_CheckIntegrity(int fileDesc);
/**
* Returns the content type of an open Forward Lock file.
*
* @param[in] fileDesc The file descriptor of an open Forward Lock file.
*
* @return
* A reference to the content type. The reference remains valid as long as the file is kept open.
*/
const char *FwdLockFile_GetContentType(int fileDesc);
#ifdef __cplusplus
}
#endif
#endif // __FWDLOCKFILE_H__

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB