MockDrmCryptoPlugin.cpp revision 4c63a239c404af1e055e5f9939939ab0fd09d98a
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "MockDrmCryptoPlugin" 19#include <utils/Log.h> 20 21 22#include "drm/DrmAPI.h" 23#include "MockDrmCryptoPlugin.h" 24#include "media/stagefright/MediaErrors.h" 25 26using namespace android; 27 28// Shared library entry point 29DrmFactory *createDrmFactory() 30{ 31 return new MockDrmFactory(); 32} 33 34// Shared library entry point 35CryptoFactory *createCryptoFactory() 36{ 37 return new MockCryptoFactory(); 38} 39 40const uint8_t mock_uuid[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 41 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}; 42 43namespace android { 44 45 // MockDrmFactory 46 bool MockDrmFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) 47 { 48 return (!memcmp(uuid, mock_uuid, sizeof(uuid))); 49 } 50 51 status_t MockDrmFactory::createDrmPlugin(const uint8_t uuid[16], DrmPlugin **plugin) 52 { 53 *plugin = new MockDrmPlugin(); 54 return OK; 55 } 56 57 // MockCryptoFactory 58 bool MockCryptoFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) const 59 { 60 return (!memcmp(uuid, mock_uuid, sizeof(uuid))); 61 } 62 63 status_t MockCryptoFactory::createPlugin(const uint8_t uuid[16], const void *data, 64 size_t size, CryptoPlugin **plugin) 65 { 66 *plugin = new MockCryptoPlugin(); 67 return OK; 68 } 69 70 71 // MockDrmPlugin methods 72 73 status_t MockDrmPlugin::openSession(Vector<uint8_t> &sessionId) 74 { 75 const size_t kSessionIdSize = 8; 76 77 Mutex::Autolock lock(mLock); 78 for (size_t i = 0; i < kSessionIdSize / sizeof(long); i++) { 79 long r = random(); 80 sessionId.appendArray((uint8_t *)&r, sizeof(long)); 81 } 82 mSessions.add(sessionId); 83 84 ALOGD("MockDrmPlugin::openSession() -> %s", vectorToString(sessionId).string()); 85 return OK; 86 } 87 88 status_t MockDrmPlugin::closeSession(Vector<uint8_t> const &sessionId) 89 { 90 Mutex::Autolock lock(mLock); 91 ALOGD("MockDrmPlugin::closeSession(%s)", vectorToString(sessionId).string()); 92 ssize_t index = findSession(sessionId); 93 if (index == kNotFound) { 94 ALOGD("Invalid sessionId"); 95 return BAD_VALUE; 96 } 97 mSessions.removeAt(index); 98 return OK; 99 } 100 101 102 status_t MockDrmPlugin::getKeyRequest(Vector<uint8_t> const &sessionId, 103 Vector<uint8_t> const &initData, 104 String8 const &mimeType, KeyType keyType, 105 KeyedVector<String8, String8> const &optionalParameters, 106 Vector<uint8_t> &request, String8 &defaultUrl) 107 { 108 Mutex::Autolock lock(mLock); 109 ALOGD("MockDrmPlugin::getKeyRequest(sessionId=%s, initData=%s, mimeType=%s" 110 ", keyType=%d, optionalParameters=%s))", 111 vectorToString(sessionId).string(), vectorToString(initData).string(), mimeType.string(), 112 keyType, stringMapToString(optionalParameters).string()); 113 114 ssize_t index = findSession(sessionId); 115 if (index == kNotFound) { 116 ALOGD("Invalid sessionId"); 117 return BAD_VALUE; 118 } 119 120 // Properties used in mock test, set by mock plugin and verifed cts test app 121 // byte[] initData -> mock-initdata 122 // string mimeType -> mock-mimetype 123 // string keyType -> mock-keytype 124 // string optionalParameters -> mock-optparams formatted as {key1,value1},{key2,value2} 125 126 mByteArrayProperties.add(String8("mock-initdata"), initData); 127 mStringProperties.add(String8("mock-mimetype"), mimeType); 128 129 String8 keyTypeStr; 130 keyTypeStr.appendFormat("%d", (int)keyType); 131 mStringProperties.add(String8("mock-keytype"), keyTypeStr); 132 133 String8 params; 134 for (size_t i = 0; i < optionalParameters.size(); i++) { 135 params.appendFormat("%s{%s,%s}", i ? "," : "", 136 optionalParameters.keyAt(i).string(), 137 optionalParameters.valueAt(i).string()); 138 } 139 mStringProperties.add(String8("mock-optparams"), params); 140 141 // Properties used in mock test, set by cts test app returned from mock plugin 142 // byte[] mock-request -> request 143 // string mock-default-url -> defaultUrl 144 145 index = mByteArrayProperties.indexOfKey(String8("mock-request")); 146 if (index < 0) { 147 ALOGD("Missing 'mock-request' parameter for mock"); 148 return BAD_VALUE; 149 } else { 150 request = mByteArrayProperties.valueAt(index); 151 } 152 153 index = mStringProperties.indexOfKey(String8("mock-defaultUrl")); 154 if (index < 0) { 155 ALOGD("Missing 'mock-defaultUrl' parameter for mock"); 156 return BAD_VALUE; 157 } else { 158 defaultUrl = mStringProperties.valueAt(index); 159 } 160 return OK; 161 } 162 163 status_t MockDrmPlugin::provideKeyResponse(Vector<uint8_t> const &sessionId, 164 Vector<uint8_t> const &response, 165 Vector<uint8_t> &keySetId) 166 { 167 Mutex::Autolock lock(mLock); 168 ALOGD("MockDrmPlugin::provideKeyResponse(sessionId=%s, response=%s)", 169 vectorToString(sessionId).string(), vectorToString(response).string()); 170 ssize_t index = findSession(sessionId); 171 if (index == kNotFound) { 172 ALOGD("Invalid sessionId"); 173 return BAD_VALUE; 174 } 175 if (response.size() == 0) { 176 return BAD_VALUE; 177 } 178 179 // Properties used in mock test, set by mock plugin and verifed cts test app 180 // byte[] response -> mock-response 181 mByteArrayProperties.add(String8("mock-response"), response); 182 183 const size_t kKeySetIdSize = 8; 184 185 for (size_t i = 0; i < kKeySetIdSize / sizeof(long); i++) { 186 long r = random(); 187 keySetId.appendArray((uint8_t *)&r, sizeof(long)); 188 } 189 mKeySets.add(keySetId); 190 191 return OK; 192 } 193 194 status_t MockDrmPlugin::removeKeys(Vector<uint8_t> const &keySetId) 195 { 196 Mutex::Autolock lock(mLock); 197 ALOGD("MockDrmPlugin::removeKeys(keySetId=%s)", 198 vectorToString(keySetId).string()); 199 200 ssize_t index = findKeySet(keySetId); 201 if (index == kNotFound) { 202 ALOGD("Invalid keySetId"); 203 return BAD_VALUE; 204 } 205 mKeySets.removeAt(index); 206 207 return OK; 208 } 209 210 status_t MockDrmPlugin::restoreKeys(Vector<uint8_t> const &sessionId, 211 Vector<uint8_t> const &keySetId) 212 { 213 Mutex::Autolock lock(mLock); 214 ALOGD("MockDrmPlugin::restoreKeys(sessionId=%s, keySetId=%s)", 215 vectorToString(sessionId).string(), 216 vectorToString(keySetId).string()); 217 ssize_t index = findSession(sessionId); 218 if (index == kNotFound) { 219 ALOGD("Invalid sessionId"); 220 return BAD_VALUE; 221 } 222 223 index = findKeySet(keySetId); 224 if (index == kNotFound) { 225 ALOGD("Invalid keySetId"); 226 return BAD_VALUE; 227 } 228 229 return OK; 230 } 231 232 status_t MockDrmPlugin::queryKeyStatus(Vector<uint8_t> const &sessionId, 233 KeyedVector<String8, String8> &infoMap) const 234 { 235 ALOGD("MockDrmPlugin::queryKeyStatus(sessionId=%s)", 236 vectorToString(sessionId).string()); 237 238 ssize_t index = findSession(sessionId); 239 if (index == kNotFound) { 240 ALOGD("Invalid sessionId"); 241 return BAD_VALUE; 242 } 243 244 infoMap.add(String8("purchaseDuration"), String8("1000")); 245 infoMap.add(String8("licenseDuration"), String8("100")); 246 return OK; 247 } 248 249 status_t MockDrmPlugin::getProvisionRequest(Vector<uint8_t> &request, 250 String8 &defaultUrl) 251 { 252 Mutex::Autolock lock(mLock); 253 ALOGD("MockDrmPlugin::getProvisionRequest()"); 254 255 // Properties used in mock test, set by cts test app returned from mock plugin 256 // byte[] mock-request -> request 257 // string mock-default-url -> defaultUrl 258 259 ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-request")); 260 if (index < 0) { 261 ALOGD("Missing 'mock-request' parameter for mock"); 262 return BAD_VALUE; 263 } else { 264 request = mByteArrayProperties.valueAt(index); 265 } 266 267 index = mStringProperties.indexOfKey(String8("mock-defaultUrl")); 268 if (index < 0) { 269 ALOGD("Missing 'mock-defaultUrl' parameter for mock"); 270 return BAD_VALUE; 271 } else { 272 defaultUrl = mStringProperties.valueAt(index); 273 } 274 return OK; 275 } 276 277 status_t MockDrmPlugin::provideProvisionResponse(Vector<uint8_t> const &response) 278 { 279 Mutex::Autolock lock(mLock); 280 ALOGD("MockDrmPlugin::provideProvisionResponse(%s)", 281 vectorToString(response).string()); 282 283 // Properties used in mock test, set by mock plugin and verifed cts test app 284 // byte[] response -> mock-response 285 286 mByteArrayProperties.add(String8("mock-response"), response); 287 return OK; 288 } 289 290 status_t MockDrmPlugin::getSecureStops(List<Vector<uint8_t> > &secureStops) 291 { 292 Mutex::Autolock lock(mLock); 293 ALOGD("MockDrmPlugin::getSecureStops()"); 294 const uint8_t ss1[] = {0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89}; 295 const uint8_t ss2[] = {0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99}; 296 297 Vector<uint8_t> vec; 298 vec.appendArray(ss1, sizeof(ss1)); 299 secureStops.push_back(vec); 300 301 vec.clear(); 302 vec.appendArray(ss2, sizeof(ss2)); 303 secureStops.push_back(vec); 304 return OK; 305 } 306 307 status_t MockDrmPlugin::releaseSecureStops(Vector<uint8_t> const &ssRelease) 308 { 309 Mutex::Autolock lock(mLock); 310 ALOGD("MockDrmPlugin::releaseSecureStops(%s)", 311 vectorToString(ssRelease).string()); 312 return OK; 313 } 314 315 status_t MockDrmPlugin::getPropertyString(String8 const &name, String8 &value) const 316 { 317 ALOGD("MockDrmPlugin::getPropertyString(name=%s)", name.string()); 318 ssize_t index = mStringProperties.indexOfKey(name); 319 if (index < 0) { 320 ALOGD("no property for '%s'", name.string()); 321 return BAD_VALUE; 322 } 323 value = mStringProperties.valueAt(index); 324 return OK; 325 } 326 327 status_t MockDrmPlugin::getPropertyByteArray(String8 const &name, 328 Vector<uint8_t> &value) const 329 { 330 ALOGD("MockDrmPlugin::getPropertyByteArray(name=%s)", name.string()); 331 ssize_t index = mByteArrayProperties.indexOfKey(name); 332 if (index < 0) { 333 ALOGD("no property for '%s'", name.string()); 334 return BAD_VALUE; 335 } 336 value = mByteArrayProperties.valueAt(index); 337 return OK; 338 } 339 340 status_t MockDrmPlugin::setPropertyString(String8 const &name, 341 String8 const &value) 342 { 343 Mutex::Autolock lock(mLock); 344 ALOGD("MockDrmPlugin::setPropertyString(name=%s, value=%s)", 345 name.string(), value.string()); 346 mStringProperties.add(name, value); 347 return OK; 348 } 349 350 status_t MockDrmPlugin::setPropertyByteArray(String8 const &name, 351 Vector<uint8_t> const &value) 352 { 353 Mutex::Autolock lock(mLock); 354 ALOGD("MockDrmPlugin::setPropertyByteArray(name=%s, value=%s)", 355 name.string(), vectorToString(value).string()); 356 mByteArrayProperties.add(name, value); 357 return OK; 358 } 359 360 status_t MockDrmPlugin::setCipherAlgorithm(Vector<uint8_t> const &sessionId, 361 String8 const &algorithm) 362 { 363 Mutex::Autolock lock(mLock); 364 365 ALOGD("MockDrmPlugin::setCipherAlgorithm(sessionId=%s, algorithm=%s)", 366 vectorToString(sessionId).string(), algorithm.string()); 367 368 ssize_t index = findSession(sessionId); 369 if (index == kNotFound) { 370 ALOGD("Invalid sessionId"); 371 return BAD_VALUE; 372 } 373 374 if (algorithm == "AES/CBC/NoPadding") { 375 return OK; 376 } 377 return BAD_VALUE; 378 } 379 380 status_t MockDrmPlugin::setMacAlgorithm(Vector<uint8_t> const &sessionId, 381 String8 const &algorithm) 382 { 383 Mutex::Autolock lock(mLock); 384 385 ALOGD("MockDrmPlugin::setMacAlgorithm(sessionId=%s, algorithm=%s)", 386 vectorToString(sessionId).string(), algorithm.string()); 387 388 ssize_t index = findSession(sessionId); 389 if (index == kNotFound) { 390 ALOGD("Invalid sessionId"); 391 return BAD_VALUE; 392 } 393 394 if (algorithm == "HmacSHA256") { 395 return OK; 396 } 397 return BAD_VALUE; 398 } 399 400 status_t MockDrmPlugin::encrypt(Vector<uint8_t> const &sessionId, 401 Vector<uint8_t> const &keyId, 402 Vector<uint8_t> const &input, 403 Vector<uint8_t> const &iv, 404 Vector<uint8_t> &output) 405 { 406 Mutex::Autolock lock(mLock); 407 ALOGD("MockDrmPlugin::encrypt(sessionId=%s, keyId=%s, input=%s, iv=%s)", 408 vectorToString(sessionId).string(), 409 vectorToString(keyId).string(), 410 vectorToString(input).string(), 411 vectorToString(iv).string()); 412 413 ssize_t index = findSession(sessionId); 414 if (index == kNotFound) { 415 ALOGD("Invalid sessionId"); 416 return BAD_VALUE; 417 } 418 419 // Properties used in mock test, set by mock plugin and verifed cts test app 420 // byte[] keyId -> mock-keyid 421 // byte[] input -> mock-input 422 // byte[] iv -> mock-iv 423 mByteArrayProperties.add(String8("mock-keyid"), keyId); 424 mByteArrayProperties.add(String8("mock-input"), input); 425 mByteArrayProperties.add(String8("mock-iv"), iv); 426 427 // Properties used in mock test, set by cts test app returned from mock plugin 428 // byte[] mock-output -> output 429 index = mByteArrayProperties.indexOfKey(String8("mock-output")); 430 if (index < 0) { 431 ALOGD("Missing 'mock-request' parameter for mock"); 432 return BAD_VALUE; 433 } else { 434 output = mByteArrayProperties.valueAt(index); 435 } 436 return OK; 437 } 438 439 status_t MockDrmPlugin::decrypt(Vector<uint8_t> const &sessionId, 440 Vector<uint8_t> const &keyId, 441 Vector<uint8_t> const &input, 442 Vector<uint8_t> const &iv, 443 Vector<uint8_t> &output) 444 { 445 Mutex::Autolock lock(mLock); 446 ALOGD("MockDrmPlugin::decrypt(sessionId=%s, keyId=%s, input=%s, iv=%s)", 447 vectorToString(sessionId).string(), 448 vectorToString(keyId).string(), 449 vectorToString(input).string(), 450 vectorToString(iv).string()); 451 452 ssize_t index = findSession(sessionId); 453 if (index == kNotFound) { 454 ALOGD("Invalid sessionId"); 455 return BAD_VALUE; 456 } 457 458 // Properties used in mock test, set by mock plugin and verifed cts test app 459 // byte[] keyId -> mock-keyid 460 // byte[] input -> mock-input 461 // byte[] iv -> mock-iv 462 mByteArrayProperties.add(String8("mock-keyid"), keyId); 463 mByteArrayProperties.add(String8("mock-input"), input); 464 mByteArrayProperties.add(String8("mock-iv"), iv); 465 466 // Properties used in mock test, set by cts test app returned from mock plugin 467 // byte[] mock-output -> output 468 index = mByteArrayProperties.indexOfKey(String8("mock-output")); 469 if (index < 0) { 470 ALOGD("Missing 'mock-request' parameter for mock"); 471 return BAD_VALUE; 472 } else { 473 output = mByteArrayProperties.valueAt(index); 474 } 475 return OK; 476 } 477 478 status_t MockDrmPlugin::sign(Vector<uint8_t> const &sessionId, 479 Vector<uint8_t> const &keyId, 480 Vector<uint8_t> const &message, 481 Vector<uint8_t> &signature) 482 { 483 Mutex::Autolock lock(mLock); 484 ALOGD("MockDrmPlugin::sign(sessionId=%s, keyId=%s, message=%s)", 485 vectorToString(sessionId).string(), 486 vectorToString(keyId).string(), 487 vectorToString(message).string()); 488 489 ssize_t index = findSession(sessionId); 490 if (index == kNotFound) { 491 ALOGD("Invalid sessionId"); 492 return BAD_VALUE; 493 } 494 495 // Properties used in mock test, set by mock plugin and verifed cts test app 496 // byte[] keyId -> mock-keyid 497 // byte[] message -> mock-message 498 mByteArrayProperties.add(String8("mock-keyid"), keyId); 499 mByteArrayProperties.add(String8("mock-message"), message); 500 501 // Properties used in mock test, set by cts test app returned from mock plugin 502 // byte[] mock-signature -> signature 503 index = mByteArrayProperties.indexOfKey(String8("mock-signature")); 504 if (index < 0) { 505 ALOGD("Missing 'mock-request' parameter for mock"); 506 return BAD_VALUE; 507 } else { 508 signature = mByteArrayProperties.valueAt(index); 509 } 510 return OK; 511 } 512 513 status_t MockDrmPlugin::verify(Vector<uint8_t> const &sessionId, 514 Vector<uint8_t> const &keyId, 515 Vector<uint8_t> const &message, 516 Vector<uint8_t> const &signature, 517 bool &match) 518 { 519 Mutex::Autolock lock(mLock); 520 ALOGD("MockDrmPlugin::verify(sessionId=%s, keyId=%s, message=%s, signature=%s)", 521 vectorToString(sessionId).string(), 522 vectorToString(keyId).string(), 523 vectorToString(message).string(), 524 vectorToString(signature).string()); 525 526 ssize_t index = findSession(sessionId); 527 if (index == kNotFound) { 528 ALOGD("Invalid sessionId"); 529 return BAD_VALUE; 530 } 531 532 // Properties used in mock test, set by mock plugin and verifed cts test app 533 // byte[] keyId -> mock-keyid 534 // byte[] message -> mock-message 535 // byte[] signature -> mock-signature 536 mByteArrayProperties.add(String8("mock-keyid"), keyId); 537 mByteArrayProperties.add(String8("mock-message"), message); 538 mByteArrayProperties.add(String8("mock-signature"), signature); 539 540 // Properties used in mock test, set by cts test app returned from mock plugin 541 // String mock-match "1" or "0" -> match 542 index = mStringProperties.indexOfKey(String8("mock-match")); 543 if (index < 0) { 544 ALOGD("Missing 'mock-request' parameter for mock"); 545 return BAD_VALUE; 546 } else { 547 match = atol(mStringProperties.valueAt(index).string()); 548 } 549 return OK; 550 } 551 552 ssize_t MockDrmPlugin::findSession(Vector<uint8_t> const &sessionId) const 553 { 554 ALOGD("findSession: nsessions=%d, size=%d", mSessions.size(), sessionId.size()); 555 for (size_t i = 0; i < mSessions.size(); ++i) { 556 if (memcmp(mSessions[i].array(), sessionId.array(), sessionId.size()) == 0) { 557 return i; 558 } 559 } 560 return kNotFound; 561 } 562 563 ssize_t MockDrmPlugin::findKeySet(Vector<uint8_t> const &keySetId) const 564 { 565 ALOGD("findKeySet: nkeySets=%d, size=%d", mKeySets.size(), keySetId.size()); 566 for (size_t i = 0; i < mKeySets.size(); ++i) { 567 if (memcmp(mKeySets[i].array(), keySetId.array(), keySetId.size()) == 0) { 568 return i; 569 } 570 } 571 return kNotFound; 572 } 573 574 575 // Conversion utilities 576 String8 MockDrmPlugin::vectorToString(Vector<uint8_t> const &vector) const 577 { 578 return arrayToString(vector.array(), vector.size()); 579 } 580 581 String8 MockDrmPlugin::arrayToString(uint8_t const *array, size_t len) const 582 { 583 String8 result("{ "); 584 for (size_t i = 0; i < len; i++) { 585 result.appendFormat("0x%02x ", array[i]); 586 } 587 result += "}"; 588 return result; 589 } 590 591 String8 MockDrmPlugin::stringMapToString(KeyedVector<String8, String8> map) const 592 { 593 String8 result("{ "); 594 for (size_t i = 0; i < map.size(); i++) { 595 result.appendFormat("%s{name=%s, value=%s}", i > 0 ? ", " : "", 596 map.keyAt(i).string(), map.valueAt(i).string()); 597 } 598 return result + " }"; 599 } 600 601 bool operator<(Vector<uint8_t> const &lhs, Vector<uint8_t> const &rhs) { 602 return lhs.size() < rhs.size() || (memcmp(lhs.array(), rhs.array(), lhs.size()) < 0); 603 } 604 605 // 606 // Crypto Plugin 607 // 608 609 bool MockCryptoPlugin::requiresSecureDecoderComponent(const char *mime) const 610 { 611 ALOGD("MockCryptoPlugin::requiresSecureDecoderComponent(mime=%s)", mime); 612 return false; 613 } 614 615 ssize_t 616 MockCryptoPlugin::decrypt(bool secure, const uint8_t key[16], const uint8_t iv[16], 617 Mode mode, const void *srcPtr, const SubSample *subSamples, 618 size_t numSubSamples, void *dstPtr, AString *errorDetailMsg) 619 { 620 ALOGD("MockCryptoPlugin::decrypt(secure=%d, key=%s, iv=%s, mode=%d, src=%p, " 621 "subSamples=%s, dst=%p)", 622 (int)secure, 623 arrayToString(key, sizeof(key)).string(), 624 arrayToString(iv, sizeof(iv)).string(), 625 (int)mode, srcPtr, 626 subSamplesToString(subSamples, numSubSamples).string(), 627 dstPtr); 628 return OK; 629 } 630 631 // Conversion utilities 632 String8 MockCryptoPlugin::arrayToString(uint8_t const *array, size_t len) const 633 { 634 String8 result("{ "); 635 for (size_t i = 0; i < len; i++) { 636 result.appendFormat("0x%02x ", array[i]); 637 } 638 result += "}"; 639 return result; 640 } 641 642 String8 MockCryptoPlugin::subSamplesToString(SubSample const *subSamples, 643 size_t numSubSamples) const 644 { 645 String8 result; 646 for (size_t i = 0; i < numSubSamples; i++) { 647 result.appendFormat("[%d] {clear:%d, encrypted:%d} ", i, 648 subSamples[i].mNumBytesOfClearData, 649 subSamples[i].mNumBytesOfEncryptedData); 650 } 651 return result; 652 } 653 654}; 655