vn-verdnaturachat/ios/Pods/MMKVCore/Core/KeyValueHolder.cpp

217 lines
7.9 KiB
C++
Raw Normal View History

[NEW] Encrypt user credentials and preferences (#2247) * install react-native-mmkv-storage * wip ios migration * change all js rn-user-defaults -> react-native-mmkv-storage * remove all rn-user-defaults native references (iOS) * android migration from rn-user-defaults to react-native-mmkv-storage * ios app group accessible mmkv * handle get errors * remove access of credentials from legacy native apps * remove data of user defaults * remove no longer necessary import * js mmkv encryption * run migration only once * reply from notification android * fix app group key access at native level ios * encrypt user credentials using a specific key * ios encrypt with random key * use a random key at the first encryption * encrypt migrated data on js land * remove unused function * reply notifications ios should be working * use fix instanceID * android ejson retrieve encrypted data * remove encryption migrated data for a while * encryption working between app and share extension * fix patch react-native-notifications * ssl pinning working using mmkv encrypted data * improve react-native-notifications * run encrypt migration data only once * fix build * fix patches magic string * fix mmkv id * mmkv -> userPreferences * fix instance id on android migration * cast our oldest sharedPreferences string into an object * revert log remove * create currentServer Rocket.Chat key * wrap mmkv api class * change the get logic * move userPreferences to lib * move encrypt migrated data to userPreferences class * check if the new object is new before insert * invalidate ci yarn cache * fix sort migration from android shared preferences * fix splashscreen forever * invalidate yarn cache * invalidate yarn cache * fix patch * Minor change * fix android notifications looking for wrong mmkv instance * Fix some issues on iOS mmkv native access * Remove unnecessary code * Fix notification reply and ssl pinning * WIP NotificationService use MMKV credentials * Add KeychainGroup * Notification idOnly get credentials from mmkv * Some fixes * Invalidate yarn cache * Pods * Use MMKVAppExtension on NotificationService Co-authored-by: Diego Mello <diegolmello@gmail.com>
2020-08-19 17:14:22 +00:00
/*
* Tencent is pleased to support the open source community by making
* MMKV available.
*
* Copyright (C) 2020 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of
* the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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 "KeyValueHolder.h"
#include "PBUtility.h"
#include "aes/AESCrypt.h"
#include <cerrno>
#include <cstring>
#include <stdexcept>
namespace mmkv {
KeyValueHolder::KeyValueHolder(uint32_t keyLength, uint32_t valueLength, uint32_t off)
: keySize(static_cast<uint16_t>(keyLength)), valueSize(valueLength), offset(off) {
computedKVSize = keySize + static_cast<uint16_t>(pbRawVarint32Size(keySize));
computedKVSize += static_cast<uint16_t>(pbRawVarint32Size(valueSize));
}
MMBuffer KeyValueHolder::toMMBuffer(const void *basePtr) const {
auto realPtr = (uint8_t *) basePtr + offset;
realPtr += computedKVSize;
return MMBuffer(realPtr, valueSize, MMBufferNoCopy);
}
#ifndef MMKV_DISABLE_CRYPT
KeyValueHolderCrypt::KeyValueHolderCrypt(const void *src, size_t length) {
if (length <= SmallBufferSize()) {
type = KeyValueHolderType_Direct;
paddedSize = static_cast<uint8_t>(length);
memcpy(paddedValue, src, length);
} else {
type = KeyValueHolderType_Memory;
memSize = static_cast<uint32_t>(length);
memPtr = malloc(length);
if (!memPtr) {
throw std::runtime_error(strerror(errno));
}
memcpy(memPtr, src, memSize);
}
}
KeyValueHolderCrypt::KeyValueHolderCrypt(MMBuffer &&data) {
if (data.type == MMBuffer::MMBufferType_Small) {
static_assert(SmallBufferSize() >= MMBuffer::SmallBufferSize(), "KeyValueHolderCrypt can't hold MMBuffer");
type = KeyValueHolderType_Direct;
paddedSize = static_cast<uint8_t>(data.length());
memcpy(paddedValue, data.getPtr(), data.length());
} else {
# ifdef MMKV_APPLE
assert(data.m_data == nil);
# endif
type = KeyValueHolderType_Memory;
memSize = static_cast<uint32_t>(data.length());
memPtr = data.getPtr();
data.detach();
}
}
KeyValueHolderCrypt::KeyValueHolderCrypt(uint32_t keyLength, uint32_t valueLength, uint32_t off)
: type(KeyValueHolderType_Offset), keySize(static_cast<uint16_t>(keyLength)), valueSize(valueLength), offset(off) {
pbKeyValueSize = static_cast<uint8_t>(pbRawVarint32Size(keySize) + pbRawVarint32Size(valueSize));
}
KeyValueHolderCrypt::KeyValueHolderCrypt(KeyValueHolderCrypt &&other) noexcept {
this->move(std::move(other));
}
KeyValueHolderCrypt &KeyValueHolderCrypt::operator=(KeyValueHolderCrypt &&other) noexcept {
if (type == KeyValueHolderType_Memory && memPtr) {
free(memPtr);
}
this->move(std::move(other));
return *this;
}
void KeyValueHolderCrypt::move(KeyValueHolderCrypt &&other) noexcept {
if (other.type == KeyValueHolderType_Direct || other.type == KeyValueHolderType_Offset) {
memcpy(this, &other, sizeof(other));
} else if (other.type == KeyValueHolderType_Memory) {
type = KeyValueHolderType_Memory;
memSize = other.memSize;
memPtr = other.memPtr;
other.memPtr = nullptr;
}
}
KeyValueHolderCrypt::~KeyValueHolderCrypt() {
if (type == KeyValueHolderType_Memory && memPtr) {
free(memPtr);
}
}
// get decrypt data with [position, -1)
static MMBuffer decryptBuffer(AESCrypt &crypter, const MMBuffer &inputBuffer, size_t position) {
static uint8_t smallBuffer[16];
auto basePtr = (uint8_t *) inputBuffer.getPtr();
auto ptr = basePtr;
for (size_t index = sizeof(smallBuffer); index < position; index += sizeof(smallBuffer)) {
crypter.decrypt(ptr, smallBuffer, sizeof(smallBuffer));
ptr += sizeof(smallBuffer);
}
if (ptr < basePtr + position) {
crypter.decrypt(ptr, smallBuffer, static_cast<size_t>(basePtr + position - ptr));
ptr = basePtr + position;
}
size_t length = inputBuffer.length() - position;
MMBuffer tmp(length);
auto input = ptr;
auto output = tmp.getPtr();
crypter.decrypt(input, output, length);
return tmp;
}
MMBuffer KeyValueHolderCrypt::toMMBuffer(const void *basePtr, const AESCrypt *crypter) const {
if (type == KeyValueHolderType_Direct) {
return MMBuffer((void *) paddedValue, paddedSize, MMBufferNoCopy);
} else if (type == KeyValueHolderType_Memory) {
return MMBuffer(memPtr, memSize, MMBufferNoCopy);
} else {
auto realPtr = (uint8_t *) basePtr + offset;
auto position = static_cast<uint32_t>(pbKeyValueSize + keySize);
auto realSize = position + valueSize;
auto kvBuffer = MMBuffer(realPtr, realSize, MMBufferNoCopy);
auto decrypter = crypter->cloneWithStatus(cryptStatus);
return decryptBuffer(decrypter, kvBuffer, position);
}
}
#endif // MMKV_DISABLE_CRYPT
} // namespace mmkv
#if !defined(MMKV_DISABLE_CRYPT) && !defined(NDEBUG)
# include "CodedInputData.h"
# include "CodedOutputData.h"
# include "MMKVLog.h"
# include <ctime>
using namespace std;
namespace mmkv {
void KeyValueHolderCrypt::testAESToMMBuffer() {
const uint8_t plainText[] = "Hello, OpenSSL-mmkv::KeyValueHolderCrypt::testAESToMMBuffer() with AES CFB 128.";
constexpr size_t textLength = sizeof(plainText) - 1;
const uint8_t key[] = "TheAESKey";
constexpr size_t keyLength = sizeof(key) - 1;
uint8_t iv[AES_KEY_LEN];
srand((unsigned) time(nullptr));
for (uint32_t i = 0; i < AES_KEY_LEN; i++) {
iv[i] = (uint8_t) rand();
}
AESCrypt crypt1(key, keyLength, iv, sizeof(iv));
auto encryptText = new uint8_t[DEFAULT_MMAP_SIZE];
memset(encryptText, 0, DEFAULT_MMAP_SIZE);
CodedOutputData output(encryptText, DEFAULT_MMAP_SIZE);
output.writeData(MMBuffer((void *) key, keyLength, MMBufferNoCopy));
auto lengthOfValue = textLength + pbRawVarint32Size((uint32_t) textLength);
output.writeRawVarint32((int32_t) lengthOfValue);
output.writeData(MMBuffer((void *) plainText, textLength, MMBufferNoCopy));
crypt1.encrypt(encryptText, encryptText, (size_t)(output.curWritePointer() - encryptText));
AESCrypt decrypt(key, keyLength, iv, sizeof(iv));
uint8_t smallBuffer[32];
decrypt.decrypt(encryptText, smallBuffer, 5);
auto keySize = CodedInputData(smallBuffer, 5).readUInt32();
auto sizeOfKeySize = pbRawVarint32Size(keySize);
auto position = sizeOfKeySize;
decrypt.decrypt(encryptText + 5, smallBuffer + 5, static_cast<size_t>(sizeOfKeySize + keySize - 5));
position += keySize;
decrypt.decrypt(encryptText + position, smallBuffer + position, 5);
auto valueSize = CodedInputData(smallBuffer + position, 5).readUInt32();
// auto sizeOfValueSize = pbRawVarint32Size(valueSize);
KeyValueHolderCrypt kvHolder(keySize, valueSize, 0);
auto rollbackSize = position + 5;
decrypt.statusBeforeDecrypt(encryptText + rollbackSize, smallBuffer + rollbackSize, rollbackSize,
kvHolder.cryptStatus);
auto value = kvHolder.toMMBuffer(encryptText, &decrypt);
# ifdef MMKV_APPLE
MMKVInfo("testAESToMMBuffer: %@", CodedInputData((char *) value.getPtr(), value.length()).readString());
# else
MMKVInfo("testAESToMMBuffer: %s", CodedInputData((char *) value.getPtr(), value.length()).readString().c_str());
# endif
MMKVInfo("MMBuffer::SmallBufferSize() = %u, KeyValueHolderCrypt::SmallBufferSize() = %u",
MMBuffer::SmallBufferSize(), KeyValueHolderCrypt::SmallBufferSize());
}
} // namespace mmkv
#endif