Secure config WIP
This commit is contained in:
parent
b5890340e3
commit
14384131f4
7 changed files with 83 additions and 28 deletions
|
@ -40,6 +40,7 @@ namespace QSimpleCrypto
|
||||||
/// \return Returns random bytes.
|
/// \return Returns random bytes.
|
||||||
///
|
///
|
||||||
QByteArray generateRandomBytes(const int& size);
|
QByteArray generateRandomBytes(const int& size);
|
||||||
|
QByteArray generateSecureRandomBytes(const int& size);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief encryptAesBlockCipher - Function encrypts data with Aes Block Cipher algorithm.
|
/// \brief encryptAesBlockCipher - Function encrypts data with Aes Block Cipher algorithm.
|
||||||
|
|
|
@ -26,6 +26,15 @@ QByteArray QSimpleCrypto::QBlockCipher::generateRandomBytes(const int& size)
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray QSimpleCrypto::QBlockCipher::generateSecureRandomBytes(const int &size)
|
||||||
|
{
|
||||||
|
unsigned char arr[sizeof(size)];
|
||||||
|
RAND_priv_bytes(arr, sizeof(size));
|
||||||
|
|
||||||
|
QByteArray buffer = QByteArray(reinterpret_cast<char*>(arr), size);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief QSimpleCrypto::QBlockCipher::encryptAesBlockCipher - Function encrypts data with Aes Block Cipher algorithm.
|
/// \brief QSimpleCrypto::QBlockCipher::encryptAesBlockCipher - Function encrypts data with Aes Block Cipher algorithm.
|
||||||
/// \param data - Data that will be encrypted.
|
/// \param data - Data that will be encrypted.
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
|
|
||||||
void MobileUtils::shareText(const QStringList&) {}
|
void MobileUtils::shareText(const QStringList&) {}
|
||||||
|
|
||||||
void MobileUtils::writeToKeychain(const QString&, const QString&) {}
|
void MobileUtils::writeToKeychain(const QString&, const QByteArray &) {}
|
||||||
QString MobileUtils::readFromKeychain(const QString&) { return {}; }
|
QByteArray MobileUtils::readFromKeychain(const QString&) { return {}; }
|
||||||
|
|
|
@ -13,8 +13,9 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
static void shareText(const QStringList& filesToSend);
|
static void shareText(const QStringList& filesToSend);
|
||||||
|
|
||||||
static void writeToKeychain(const QString& tag, const QString& value);
|
static void writeToKeychain(const QString& tag, const QByteArray& value);
|
||||||
static QString readFromKeychain(const QString& tag);
|
static bool deleteFromKeychain(const QString& tag);
|
||||||
|
static QByteArray readFromKeychain(const QString& tag);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MOBILEUTILS_H
|
#endif // MOBILEUTILS_H
|
||||||
|
|
|
@ -35,7 +35,7 @@ void MobileUtils::shareText(const QStringList& filesToSend) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deleteFromKeychain(const QString& tag) {
|
bool MobileUtils::deleteFromKeychain(const QString& tag) {
|
||||||
NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding];
|
NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
|
||||||
NSDictionary *deleteQuery = @{ (id)kSecAttrAccount: nsTag,
|
NSDictionary *deleteQuery = @{ (id)kSecAttrAccount: nsTag,
|
||||||
|
@ -46,17 +46,14 @@ bool deleteFromKeychain(const QString& tag) {
|
||||||
if (status != errSecSuccess) {
|
if (status != errSecSuccess) {
|
||||||
qDebug() << "Error deleteFromKeychain" << status;
|
qDebug() << "Error deleteFromKeychain" << status;
|
||||||
return false;
|
return false;
|
||||||
} else {
|
|
||||||
qDebug() << "OK deleteFromKeychain";
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MobileUtils::writeToKeychain(const QString& tag, const QString& value) {
|
void MobileUtils::writeToKeychain(const QString& tag, const QByteArray& value) {
|
||||||
deleteFromKeychain(tag);
|
deleteFromKeychain(tag);
|
||||||
|
|
||||||
NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding];
|
NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
NSData* nsValue = [value.toNSString() dataUsingEncoding:NSUTF8StringEncoding];
|
NSData* nsValue = value.toNSData();
|
||||||
|
|
||||||
NSDictionary* addQuery = @{ (id)kSecAttrAccount: nsTag,
|
NSDictionary* addQuery = @{ (id)kSecAttrAccount: nsTag,
|
||||||
(id)kSecClass: (id)kSecClassGenericPassword,
|
(id)kSecClass: (id)kSecClassGenericPassword,
|
||||||
|
@ -66,12 +63,10 @@ void MobileUtils::writeToKeychain(const QString& tag, const QString& value) {
|
||||||
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL);
|
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL);
|
||||||
if (status != errSecSuccess) {
|
if (status != errSecSuccess) {
|
||||||
qDebug() << "Error writeToKeychain" << status;
|
qDebug() << "Error writeToKeychain" << status;
|
||||||
} else {
|
|
||||||
qDebug() << "OK writeToKeychain";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MobileUtils::readFromKeychain(const QString& tag) {
|
QByteArray MobileUtils::readFromKeychain(const QString& tag) {
|
||||||
NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding];
|
NSData* nsTag = [tag.toNSString() dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
NSData* nsValue = NULL;
|
NSData* nsValue = NULL;
|
||||||
|
|
||||||
|
@ -85,11 +80,9 @@ QString MobileUtils::readFromKeychain(const QString& tag) {
|
||||||
(CFTypeRef *)&nsValue);
|
(CFTypeRef *)&nsValue);
|
||||||
if (status != errSecSuccess) {
|
if (status != errSecSuccess) {
|
||||||
qDebug() << "Error readFromKeychain" << status;
|
qDebug() << "Error readFromKeychain" << status;
|
||||||
} else {
|
|
||||||
qDebug() << "OK readFromKeychain" << nsValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString result;
|
QByteArray result;
|
||||||
if (nsValue) {
|
if (nsValue) {
|
||||||
result = QByteArray::fromNSData(nsValue);
|
result = QByteArray::fromNSData(nsValue);
|
||||||
CFRelease(nsValue);
|
CFRelease(nsValue);
|
||||||
|
|
|
@ -14,11 +14,6 @@ SecureQSettings::SecureQSettings(const QString &organization, const QString &app
|
||||||
encryptedKeys({"Servers/serversList"})
|
encryptedKeys({"Servers/serversList"})
|
||||||
{
|
{
|
||||||
qDebug() << "SecureQSettings::SecureQSettings CTOR";
|
qDebug() << "SecureQSettings::SecureQSettings CTOR";
|
||||||
// load keys from system key storage
|
|
||||||
#ifdef Q_OS_IOS
|
|
||||||
m_key = QByteArray::fromBase64(MobileUtils::readFromKeychain(settingsKeyTag).toUtf8());
|
|
||||||
m_iv = QByteArray::fromBase64(MobileUtils::readFromKeychain(settingsIvTag).toUtf8());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool encrypted = m_settings.value("Conf/encrypted").toBool();
|
bool encrypted = m_settings.value("Conf/encrypted").toBool();
|
||||||
|
|
||||||
|
@ -51,7 +46,7 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue
|
||||||
if (retVal.userType() == QVariant::ByteArray &&
|
if (retVal.userType() == QVariant::ByteArray &&
|
||||||
retVal.toByteArray().mid(0, magicString.size()) == magicString) {
|
retVal.toByteArray().mid(0, magicString.size()) == magicString) {
|
||||||
|
|
||||||
if (m_key.isEmpty() || m_iv.isEmpty()) {
|
if (getEncKey().isEmpty() || getEncIv().isEmpty()) {
|
||||||
qCritical() << "SecureQSettings::setValue Decryption requested, but key is empty";
|
qCritical() << "SecureQSettings::setValue Decryption requested, but key is empty";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -65,6 +60,7 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue
|
||||||
|
|
||||||
if (!retVal.isValid()) {
|
if (!retVal.isValid()) {
|
||||||
qWarning() << "SecureQSettings::value settings decryption failed";
|
qWarning() << "SecureQSettings::value settings decryption failed";
|
||||||
|
retVal = QVariant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +77,7 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue
|
||||||
void SecureQSettings::setValue(const QString &key, const QVariant &value)
|
void SecureQSettings::setValue(const QString &key, const QVariant &value)
|
||||||
{
|
{
|
||||||
if (encryptionRequired() && encryptedKeys.contains(key)) {
|
if (encryptionRequired() && encryptedKeys.contains(key)) {
|
||||||
if (!m_key.isEmpty() && !m_iv.isEmpty()) {
|
if (!getEncKey().isEmpty() && !getEncIv().isEmpty()) {
|
||||||
QByteArray decryptedValue;
|
QByteArray decryptedValue;
|
||||||
{
|
{
|
||||||
QDataStream ds(&decryptedValue, QIODevice::WriteOnly);
|
QDataStream ds(&decryptedValue, QIODevice::WriteOnly);
|
||||||
|
@ -155,22 +151,75 @@ void SecureQSettings::restoreAppConfig(const QByteArray &base64Cfg)
|
||||||
QByteArray SecureQSettings::encryptText(const QByteArray& value) const
|
QByteArray SecureQSettings::encryptText(const QByteArray& value) const
|
||||||
{
|
{
|
||||||
QSimpleCrypto::QBlockCipher cipher;
|
QSimpleCrypto::QBlockCipher cipher;
|
||||||
return cipher.encryptAesBlockCipher(value, m_key, m_iv);
|
return cipher.encryptAesBlockCipher(value, getEncKey(), getEncIv());
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray SecureQSettings::decryptText(const QByteArray& ba) const
|
QByteArray SecureQSettings::decryptText(const QByteArray& ba) const
|
||||||
{
|
{
|
||||||
QSimpleCrypto::QBlockCipher cipher;
|
QSimpleCrypto::QBlockCipher cipher;
|
||||||
return cipher.decryptAesBlockCipher(ba, m_key, m_iv);
|
return cipher.decryptAesBlockCipher(ba, getEncKey(), getEncIv());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SecureQSettings::encryptionRequired() const
|
bool SecureQSettings::encryptionRequired() const
|
||||||
{
|
{
|
||||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS
|
#if defined Q_OS_IOS // || defined Q_OS_ANDROID
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray SecureQSettings::getEncKey() const
|
||||||
|
{
|
||||||
|
// load keys from system key storage
|
||||||
|
m_key = MobileUtils::readFromKeychain(settingsKeyTag);
|
||||||
|
|
||||||
|
if (m_key.isEmpty()) {
|
||||||
|
// Create new key
|
||||||
|
QSimpleCrypto::QBlockCipher cipher;
|
||||||
|
QByteArray key = cipher.generateSecureRandomBytes(32);
|
||||||
|
if (key.isEmpty()) {
|
||||||
|
qCritical() << "SecureQSettings::getEncKey Unable to generate new enc key";
|
||||||
|
}
|
||||||
|
|
||||||
|
MobileUtils::writeToKeychain(settingsKeyTag, key);
|
||||||
|
|
||||||
|
// check
|
||||||
|
m_key = MobileUtils::readFromKeychain(settingsKeyTag);
|
||||||
|
if (key != m_key) {
|
||||||
|
qCritical() << "SecureQSettings::getEncKey Unable to store key in keychain" << key.size() << m_key.size();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//qDebug() << "SecureQSettings::getEncKey() key" << m_key.size();
|
||||||
|
|
||||||
|
return m_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray SecureQSettings::getEncIv() const
|
||||||
|
{
|
||||||
|
// load keys from system key storage
|
||||||
|
m_iv = MobileUtils::readFromKeychain(settingsIvTag);
|
||||||
|
|
||||||
|
if (m_iv.isEmpty()) {
|
||||||
|
// Create new IV
|
||||||
|
QSimpleCrypto::QBlockCipher cipher;
|
||||||
|
QByteArray iv = cipher.generateSecureRandomBytes(32);
|
||||||
|
if (iv.isEmpty()) {
|
||||||
|
qCritical() << "SecureQSettings::getEncIv Unable to generate new enc IV";
|
||||||
|
}
|
||||||
|
MobileUtils::writeToKeychain(settingsIvTag, iv);
|
||||||
|
|
||||||
|
// check
|
||||||
|
m_iv = MobileUtils::readFromKeychain(settingsIvTag);
|
||||||
|
if (iv != m_iv) {
|
||||||
|
qCritical() << "SecureQSettings::getEncIv Unable to store IV in keychain" << iv.size() << m_iv.size();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//qDebug() << "SecureQSettings::getEncIv() iv" << m_iv.size();
|
||||||
|
|
||||||
|
return m_iv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@ public:
|
||||||
|
|
||||||
bool encryptionRequired() const;
|
bool encryptionRequired() const;
|
||||||
|
|
||||||
|
QByteArray getEncKey() const;
|
||||||
|
QByteArray getEncIv() const;
|
||||||
private:
|
private:
|
||||||
QSettings m_settings;
|
QSettings m_settings;
|
||||||
|
|
||||||
|
@ -33,8 +35,8 @@ private:
|
||||||
|
|
||||||
QStringList encryptedKeys; // encode only key listed here
|
QStringList encryptedKeys; // encode only key listed here
|
||||||
|
|
||||||
QByteArray m_key;
|
mutable QByteArray m_key;
|
||||||
QByteArray m_iv;
|
mutable QByteArray m_iv;
|
||||||
|
|
||||||
const QByteArray magicString { "EncData" }; // Magic keyword used for mark encrypted QByteArray
|
const QByteArray magicString { "EncData" }; // Magic keyword used for mark encrypted QByteArray
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue