!C99Shell v. 2.0 [PHP 7 Update] [25.02.2019]!

Software: Apache. PHP/5.6.40 

uname -a: Linux cpanel06wh.bkk1.cloud.z.com 2.6.32-954.3.5.lve1.4.80.el6.x86_64 #1 SMP Thu Sep 24
01:42:00 EDT 2020 x86_64
 

uid=851(cp949260) gid=853(cp949260) groups=853(cp949260) 

Safe-mode: OFF (not secure)

/opt/passenger-5.3.7-4.el6.cloudlinux/src/cxx_supportlib/SecurityKit/   drwxr-xr-x
Free 234.19 GB of 981.82 GB (23.85%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     Crypto.cpp (28.46 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 *  Phusion Passenger - https://www.phusionpassenger.com/
 *  Copyright (c) 2010-2018 Phusion Holding B.V.
 *
 *  "Passenger", "Phusion Passenger" and "Union Station" are registered
 *  trademarks of Phusion Holding B.V.
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *  THE SOFTWARE.
 */

#include <SecurityKit/Crypto.h>
#include <modp_b64.h>
#include <LoggingKit/LoggingKit.h>
#include <string>
#include <SystemTools/SystemTime.h>
#include <StrIntTools/StrIntUtils.h>

#if BOOST_OS_MACOS
#else
#include <openssl/aes.h>
#endif

#define AES_KEY_BYTESIZE (256/8)
#define AES_CBC_IV_BYTESIZE (128/8)

namespace Passenger {

using namespace std;
using namespace boost;
using namespace oxt;

#if BOOST_OS_MACOS

Crypto::Crypto()
    :id(NULL) {
}

Crypto::~Crypto() {
}

CFDictionaryRef Crypto::createQueryDict(const char *label) {
    if (kSecClassIdentity != NULL) {
        const size_t size = 5L;
        CFStringRef cfLabel = CFStringCreateWithCString(NULL, label, kCFStringEncodingUTF8);
        SecPolicyRef policy = SecPolicyCreateSSL(false, NULL);
        CFTypeRef keys[] = {kSecClass, kSecReturnRef, kSecMatchLimit, kSecMatchPolicy, kSecMatchSubjectWholeString};
        CFTypeRef values[] = {kSecClassIdentity, kCFBooleanTrue, kSecMatchLimitOne, policy, cfLabel};

        CFDictionaryRef queryDict = CFDictionaryCreate(NULL, keys, values, size,
                                       &kCFCopyStringDictionaryKeyCallBacks,
                                       &kCFTypeDictionaryValueCallBacks);
        CFRelease(policy);
        CFRelease(cfLabel);

        return queryDict;
    }
    return NULL;
}

OSStatus Crypto::lookupKeychainItem(const char *label, SecIdentityRef *oIdentity) {
    OSStatus status = errSecItemNotFound;

    CFDictionaryRef queryDict = createQueryDict(label);
    if (queryDict) {
        /* Do we have a match? */
        status = SecItemCopyMatching(queryDict, (CFTypeRef *) oIdentity);
        CFRelease(queryDict);
    }
    return status;
}

SecAccessRef Crypto::createAccess(const char *cLabel) {
    SecAccessRef access = NULL;
    CFStringRef label = CFStringCreateWithCString(NULL, cLabel, kCFStringEncodingUTF8);
    if (SecAccessCreate(label, NULL, &access)) {
        logError("SecAccessCreate failed.");
        CFRelease(label);
        return NULL;
    }
    CFRelease(label);
    return access;
}

OSStatus Crypto::copyIdentityFromPKCS12File(const char *cPath,
                                            const char *cPassword,
                                            const char *cLabel) {
    OSStatus status = errSecItemNotFound;
    if (strlen(cPath) == 0) {
        return errSecMissingValue;
    }
    CFURLRef url = CFURLCreateFromFileSystemRepresentation(NULL,
                                                           (const UInt8 *) cPath, strlen(cPath), false);
    CFStringRef password = cPassword ? CFStringCreateWithCString(NULL,
                                                                 cPassword, kCFStringEncodingUTF8) : NULL;

    CFReadStreamRef cfrs = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
    SecTransformRef readTransform = SecTransformCreateReadTransformWithReadStream(cfrs);
    CFErrorRef error = NULL;
    CFDataRef pkcsData = (CFDataRef) SecTransformExecute(readTransform, &error);
    if (error != NULL) {
        logFreeErrorExtended("ReadTransform", error);
        return status;
    }

    SecAccessRef access = createAccess(cLabel);
    if (access == NULL) {
        return status;
    }
    CFTypeRef cKeys[] = {kSecImportExportPassphrase, kSecImportExportAccess};
    CFTypeRef cValues[] = {password, access};
    CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues, 2L, NULL, NULL);
    CFArrayRef items = NULL;

    /* Here we go: */
    status = SecPKCS12Import(pkcsData, options, &items);
    if (!(status == noErr && items && CFArrayGetCount(items))) {
        string suffix = string("Please check for a certificate labeled: ") + cLabel + " in your keychain, and remove the associated private key. For more help please read: https://www.phusionpassenger.com/library/admin/standalone/mac_keychain_popups.html";
        string prefix = "Loading Passenger Cert failed";
        if (status == noErr) {
            status = errSecAuthFailed;
            logError( prefix + ". " + suffix );
        }else{
            CFStringRef str = SecCopyErrorMessageString(status, NULL);
            logError( prefix + ": " + CFStringGetCStringPtr(str, kCFStringEncodingUTF8) + "\n" + suffix );
            CFRelease(str);
        }
    }else{
      id = (CFDataRef)CFDictionaryGetValue((CFDictionaryRef)CFArrayGetValueAtIndex(items, 0),kSecImportItemKeyID);
      CFRetain(id);
    }

    if (items) {
        CFRelease(items);
    }
    CFRelease(options);
    CFRelease(access);
    if (pkcsData) {
        CFRelease(pkcsData);
    }
    CFRelease(readTransform);
    CFRelease(cfrs);
    if (password) {
        CFRelease(password);
    }
    CFRelease(url);
    return status;
}

#if PRE_HIGH_SIERRA
void Crypto::killKey(const char *cLabel) {
    SecIdentityRef id = NULL;
    OSStatus status = lookupKeychainItem(cLabel, &id);
    if (status != errSecItemNotFound) {

        CFArrayRef itemList = CFArrayCreate(NULL, (const void **) &id, 1, NULL);
        CFTypeRef keys[]   = { kSecClass,  kSecMatchItemList,  kSecMatchLimit };
        CFTypeRef values[] = { kSecClassCertificate, itemList, kSecMatchLimitOne };

        CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values, 3L, NULL, NULL);
        OSStatus oserr = SecItemDelete(dict);
        if (oserr) {
            CFStringRef str = SecCopyErrorMessageString(oserr, NULL);
            logError(string("Removing Passenger Cert from keychain failed: ") + CFStringGetCStringPtr(str, kCFStringEncodingUTF8) +
                    ". Please remove the certificate labeled " + cLabel + " in your keychain.");
            CFRelease(str);
        }
        CFRelease(dict);
        CFRelease(itemList);

        if(id){
            CFTypeRef keys2[]   = { kSecClass,  kSecAttrSubjectKeyID,  kSecMatchLimit };
            CFTypeRef values2[] = { kSecClassKey, id, kSecMatchLimitOne };
            dict = CFDictionaryCreate(NULL, keys2, values2, 3L, NULL, NULL);
            oserr = SecItemDelete(dict);
            if (oserr) {
                CFStringRef str = SecCopyErrorMessageString(oserr, NULL);
                logError(string("Removing Passenger private key from keychain failed: ") + CFStringGetCStringPtr(str, kCFStringEncodingUTF8) +
                         ". Please remove the private key from the certificate labeled " + cLabel + " in your keychain.");
                CFRelease(str);
            }
            CFRelease(dict);
            CFRelease(id);
            id = NULL;
        }

    } else {
        CFStringRef str = SecCopyErrorMessageString(status, NULL);
        logError(string("Finding Passenger Cert failed: ") + CFStringGetCStringPtr(str, kCFStringEncodingUTF8) );
        CFRelease(str);
    }
}

bool Crypto::preAuthKey(const char *path, const char *passwd, const char *cLabel) {
    SecIdentityRef id = NULL;
    if (lookupKeychainItem(cLabel, &id) == errSecItemNotFound) {
        OSStatus oserr = SecKeychainSetUserInteractionAllowed(false);
        if (oserr) {
            CFStringRef str = SecCopyErrorMessageString(oserr, NULL);
            logError(string("Disabling GUI Keychain interaction failed: ") + CFStringGetCStringPtr(str, kCFStringEncodingUTF8));
            CFRelease(str);
        }
        oserr = copyIdentityFromPKCS12File(path, passwd, cLabel);
        bool success = (noErr == oserr);
        if (!success) {
            CFStringRef str = SecCopyErrorMessageString(oserr, NULL);
            logError(string("Pre authorizing the Passenger client certificate failed: ") + CFStringGetCStringPtr(str, kCFStringEncodingUTF8));
            CFRelease(str);
        }
        oserr = SecKeychainSetUserInteractionAllowed(true);
        if (oserr) {
            //This is really bad, we should probably ask the user to reboot.
            CFStringRef str = SecCopyErrorMessageString(oserr, NULL);
            logError(string("Re-enabling GUI Keychain interaction failed with error: ") + CFStringGetCStringPtr(str, kCFStringEncodingUTF8) +
                    " Please reboot as soon as possible, thanks.");
            CFRelease(str);
        }
        return success;
    } else {
        logError(string("Passenger client certificate was found in the keychain unexpectedly, skipping security update check. Please remove the private key from the certificate labeled ") + cLabel + " in your keychain.");
        if (id) {
            CFRelease(id);
        }
        return false;
    }
}
#endif

bool Crypto::generateRandomChars(unsigned char *rndChars, int rndLen) {
    FILE *fPtr = fopen("/dev/random", "r");
    if (fPtr == NULL) {
        CFIndex errNum = errno;
        char* errMsg = strerror(errno);
        const UInt8 numKeys = 4;
        CFTypeRef userInfoKeys[numKeys] = { kCFErrorFilePathKey,
                                            kCFErrorLocalizedDescriptionKey,
                                            kCFErrorLocalizedFailureReasonKey,
                                            kCFErrorLocalizedRecoverySuggestionKey };
        CFTypeRef userInfoValues[numKeys] = { CFSTR("/dev/random"),
                                              CFSTR("Couldn't open file for reading."),
                                              CFStringCreateWithCStringNoCopy(NULL, errMsg, kCFStringEncodingUTF8, NULL),
                                              CFSTR("Have you tried turning it off and on again?") };

        CFErrorRef error = CFErrorCreateWithUserInfoKeysAndValues(NULL, kCFErrorDomainOSStatus, errNum, userInfoKeys, userInfoValues, numKeys);
        logFreeErrorExtended("generateRandomChars failed", error);
        return false;
    }
    for (int i = 0; i < rndLen; i++) {
        rndChars[i] = fgetc(fPtr);
    }
    fclose(fPtr);

    return true;
}

bool Crypto::generateAndAppendNonce(string &nonce) {
    nonce.append(toString(SystemTime::getUsec()));

    int rndLen = 16;
    unsigned char rndChars[rndLen];

    if (generateRandomChars(rndChars, rndLen)) {
        char rndChars64[modp_b64_encode_len(rndLen)];
        modp_b64_encode(rndChars64, (const char *) rndChars, rndLen);

        nonce.append(rndChars64);
        return true;
    } else {
        return false;
    }
}

CFDataRef Crypto::genIV(size_t ivSize) {
    UInt8 *ivBytesPtr = (UInt8*) malloc(ivSize);//freed when iv is freed
    if (generateRandomChars(ivBytesPtr, ivSize)) {
        return CFDataCreateWithBytesNoCopy(NULL, ivBytesPtr, ivSize, kCFAllocatorMalloc);
    } else {
        return NULL;
    }
}

bool Crypto::getKeyBytes(SecKeyRef cryptokey, void **target, size_t &len) {
    const CSSM_KEY *cssmKey;
    CSSM_WRAP_KEY wrappedKey;

    CSSM_CSP_HANDLE cspHandle = 0;
    CSSM_CC_HANDLE ccHandle = 0;

    const CSSM_ACCESS_CREDENTIALS *creds;
    CSSM_RETURN error = SecKeyGetCredentials(cryptokey,
                                             CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED,
                                             kSecCredentialTypeDefault, &creds);
    if (error != CSSM_OK) { cssmPerror("SecKeyGetCredentials", error); }

    error = SecKeyGetCSSMKey(cryptokey, &cssmKey);
    if (error != CSSM_OK) { cssmPerror("SecKeyGetCSSMKey", error); }

    error = SecKeyGetCSPHandle(cryptokey, &cspHandle);
    if (error != CSSM_OK) { cssmPerror("SecKeyGetCSPHandle", error); }

    error = CSSM_CSP_CreateSymmetricContext(cspHandle,
                                            CSSM_ALGID_NONE,
                                            CSSM_ALGMODE_NONE,
                                            creds,
                                            NULL,
                                            NULL,
                                            CSSM_PADDING_NONE,
                                            0,
                                            &ccHandle);
    if (error != CSSM_OK) { cssmPerror("CSSM_CSP_CreateSymmetricContext",error); }

    memset(&wrappedKey, 0, sizeof(wrappedKey));
    error = CSSM_WrapKey(ccHandle,
                 creds,
                 cssmKey,
                 NULL,
                 &wrappedKey);
    if (error != CSSM_OK) { cssmPerror("CSSM_WrapKey", error); }

    CSSM_DeleteContext(ccHandle);

    len = wrappedKey.KeyData.Length;

    return innerMemoryBridge(wrappedKey.KeyData.Data,target,wrappedKey.KeyData.Length);
}

bool Crypto::encryptAES256(char *dataChars, size_t dataLen, AESEncResult &aesEnc) {
    CFErrorRef error = NULL;
    bool retVal = false;

    CFNumberRef cfSize = NULL;
    CFDictionaryRef parameters = NULL;
    SecKeyRef cryptokey = NULL;
    CFDataRef iv = NULL;
    SecTransformRef encrypt = NULL;
    CFDataRef message = NULL;
    CFDataRef enc = NULL;

    do {
        UInt32 size = kSecAES256; // c++ is dumb
        CFNumberRef cfSize = CFNumberCreate(NULL, kCFNumberSInt32Type, &size);
        CFTypeRef cKeys[] = {kSecAttrKeyType, kSecAttrKeySizeInBits};
        CFTypeRef cValues[] = {kSecAttrKeyTypeAES, cfSize};
        CFDictionaryRef parameters = CFDictionaryCreate(NULL, cKeys, cValues, 2L, NULL, NULL);
        if (parameters == NULL) {
            logError("CFDictionaryCreate failed.");
            retVal = false;
            break;
        }

        SecKeyRef cryptokey = SecKeyGenerateSymmetric(parameters, &error);
        if (error != NULL) {
            logFreeErrorExtended("SecKeyGenerateSymmetric", error);
            retVal = false;
            break;
        }

        if (!getKeyBytes(cryptokey, (void **) &aesEnc.key, aesEnc.keyLen)) {
            retVal = false;
            break;
        }

        CFDataRef iv = genIV(AES_CBC_IV_BYTESIZE);
        if (iv == NULL) {
            logError("genIV failed.");
            retVal = false;
            break;
        } else if (!memoryBridge(iv, (void **) &aesEnc.iv, aesEnc.ivLen)) {
            retVal = false;
            break;
        }

        SecTransformRef encrypt = SecEncryptTransformCreate(cryptokey, &error);
        if (error != NULL) {
            logFreeErrorExtended("SecEncryptTransformCreate", error);
            retVal = false;
            break;
        }
        SecTransformSetAttribute(encrypt, kSecIVKey, iv, &error);
        if (error != NULL) {
            logFreeErrorExtended("SecTransformSetAttribute", error);
            retVal = false;
            break;
        }
        CFDataRef message = CFDataCreateWithBytesNoCopy(NULL,
                                                        (UInt8*) dataChars,
                                                        dataLen,
                                                        kCFAllocatorNull);
        SecTransformSetAttribute(encrypt, kSecTransformInputAttributeName, message, &error);
        if (error != NULL) {
            logFreeErrorExtended("SecTransformSetAttribute", error);
            retVal = false;
            break;
        }
        CFDataRef enc = (CFDataRef) SecTransformExecute(encrypt, &error);
        if (error != NULL) {
            logFreeErrorExtended("SecTransformExecute", error);
            retVal = false;
            break;
        }

        if (!memoryBridge(enc, (void **) &aesEnc.encrypted, aesEnc.encryptedLen)) {
            retVal = false;
            break;
        }
        retVal = true;
    } while (false);

    if (enc) { CFRelease(enc); }
    if (message) { CFRelease(message); }
    if (encrypt) { CFRelease(encrypt); }
    if (iv) { CFRelease(iv); }
    if (cryptokey) { CFRelease(cryptokey); }
    if (parameters) { CFRelease(parameters); }
    if (cfSize) { CFRelease(cfSize); }

    return retVal;
}

void Crypto::freeAESEncrypted(AESEncResult &aesEnc) {
    if (aesEnc.encrypted != NULL) {
        free(aesEnc.encrypted);
        aesEnc.encrypted = NULL;
    }
    if (aesEnc.iv != NULL) {
        free(aesEnc.iv);
        aesEnc.iv = NULL;
    }
    if (aesEnc.key != NULL) {
        memset(aesEnc.key, 0, aesEnc.keyLen);
        free(aesEnc.key);
        aesEnc.key = NULL;
    }
}

bool Crypto::encryptRSA(unsigned char *dataChars, size_t dataLen,
                        string encryptPubKeyPath, unsigned char **encryptedCharsPtr, size_t &encryptedLen) {
    bool retVal = false;
    CFErrorRef error = NULL;
    SecKeyRef rsaPubKey = loadPubKey(encryptPubKeyPath.c_str());

    CFDataRef aesKeyData = NULL;
    SecTransformRef rsaEncryptContext = NULL;
    CFDataRef encryptedKey = NULL;

    do {
        if (rsaPubKey == NULL) {
            logError("loadPubKey failed");
            retVal = false;
            break;
        }

        aesKeyData = CFDataCreateWithBytesNoCopy(NULL, (UInt8*) dataChars, dataLen, kCFAllocatorNull);
        if (aesKeyData == NULL) {
            logError("CFDataCreateWithBytesNoCopy failed");
            retVal = false;
            break;
        }

        rsaEncryptContext = SecEncryptTransformCreate(rsaPubKey, &error);
        if (error) {
            logFreeErrorExtended("SecEncryptTransformCreate", error);
            retVal = false;
            break;
        }
        SecTransformSetAttribute(rsaEncryptContext,
                                 kSecPaddingKey,
                                 kSecPaddingOAEPKey,
                                 &error);
        if (error) {
            logFreeErrorExtended("SecTransformSetAttribute", error);
            retVal = false;
            break;
        }

        SecTransformSetAttribute(rsaEncryptContext, kSecTransformInputAttributeName, aesKeyData, &error);
        if (error) {
            logFreeErrorExtended("SecTransformSetAttribute", error);
            retVal = false;
            break;
        }
        encryptedKey = (CFDataRef) SecTransformExecute(rsaEncryptContext, &error);
        if (error) {
            logFreeErrorExtended("SecTransformExecute", error);
            retVal = false;
            break;
        }

        if (!memoryBridge(encryptedKey, (void **) encryptedCharsPtr, encryptedLen)) {
            retVal = false;
            break;
        }
        retVal = true;
    } while (false);

    if (encryptedKey) { CFRelease(encryptedKey); }
    if (rsaEncryptContext) { CFRelease(rsaEncryptContext); }
    if (aesKeyData) { CFRelease(aesKeyData); }
    if (rsaPubKey) { CFRelease(rsaPubKey); }

    return retVal;
}

bool Crypto::memoryBridge(CFDataRef input, void **target, size_t &len) {
    len = CFDataGetLength(input);
    return innerMemoryBridge((void *) CFDataGetBytePtr(input), target, len);
}

bool Crypto::innerMemoryBridge(void *input, void **target, size_t len){
    *target = malloc(len);
    if (*target == NULL) {
        logError("malloc failed: " + toString(len));
        return false;
    }
    memcpy(*target, input, len);
    return true;
}

bool Crypto::verifySignature(string signaturePubKeyPath, char *signatureChars, int signatureLen, string data) {
    SecKeyRef rsaPubKey = NULL;
    bool result = false;

    SecTransformRef verifier = NULL;
    CFNumberRef cfSize = NULL;
    do {
        rsaPubKey = loadPubKey(signaturePubKeyPath.c_str());
        if (rsaPubKey == NULL) {
            logError("Failed to load public key at " + signaturePubKeyPath);
            break;
        }

        CFDataRef signatureRef = CFDataCreateWithBytesNoCopy(NULL, (UInt8*) signatureChars, signatureLen, kCFAllocatorNull);

        CFDataRef dataRef = CFDataCreateWithBytesNoCopy(NULL, (UInt8*) data.c_str(), data.length(), kCFAllocatorNull);

        CFErrorRef error = NULL;
        verifier = SecVerifyTransformCreate(rsaPubKey, signatureRef, &error);
        if (error) {
            logFreeErrorExtended("SecVerifyTransformCreate", error);
            result = -20;
            break;
        }

        SecTransformSetAttribute(verifier, kSecTransformInputAttributeName, dataRef, &error);
        if (error) {
            logFreeErrorExtended("SecTransformSetAttribute InputName", error);
            result = -21;
            break;
        }

        SecTransformSetAttribute(verifier, kSecDigestTypeAttribute, kSecDigestSHA2, &error);
        if (error) {
            logFreeErrorExtended("SecTransformSetAttribute DigestType", error);
            result = -22;
            break;
        }

        UInt32 size = kSecAES256; // c++ is dumb
        cfSize = CFNumberCreate(NULL, kCFNumberSInt32Type, &size);
        SecTransformSetAttribute(verifier, kSecDigestLengthAttribute, cfSize, &error);
        if (error) {
            logFreeErrorExtended("SecTransformSetAttribute DigestLength", error);
            result = -23;
            break;
        }

        CFTypeRef verifyResult = SecTransformExecute(verifier, &error);
        if (error) {
            logFreeErrorExtended("SecTransformExecute", error);
            result = -24;
            break;
        }

        result = (verifyResult == kCFBooleanTrue);
    } while(0);

    if (cfSize) {
        CFRelease(cfSize);
    }
    if (verifier) {
        CFRelease(verifier);
    }
    freePubKey(rsaPubKey);

    return result;
}

PUBKEY_TYPE Crypto::loadPubKey(const char *filename) {
    SecKeyRef pubKey = NULL;
    CFDataRef keyData = NULL;
    CFURLRef url = NULL;
    CFReadStreamRef cfrs = NULL;
    SecTransformRef readTransform = NULL;
    CFArrayRef temparray = NULL;
    do {
        url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
                                                      (UInt8*) filename, strlen(filename), false);
        if (url == NULL) {
            logError("CFURLCreateFromFileSystemRepresentation failed.");
            break;
        }

        cfrs = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
        if (cfrs == NULL) {
            logError("CFReadStreamCreateWithFile failed");
            break;
        }

        readTransform = SecTransformCreateReadTransformWithReadStream(cfrs);
        if (readTransform == NULL) {
            logError("SecTransformCreateReadTransformWithReadStream failed");
            break;
        }
        CFErrorRef error = NULL;
        keyData = (CFDataRef) SecTransformExecute(readTransform, &error);
        if (keyData == NULL) {
            logError("SecTransformExecute failed to get keyData");
            break;
        }
        if (error) {
            logFreeErrorExtended("SecTransformExecute", error);
            break;
        }

        SecExternalItemType itemType = kSecItemTypePublicKey;
        SecExternalFormat externalFormat = kSecFormatPEMSequence;
        OSStatus oserr = SecItemImport(keyData,
                                       NULL, // filename or extension
                                       &externalFormat, // See SecExternalFormat for details
                                       &itemType,
                                       0, // See SecItemImportExportFlags for details, Note that PEM formatting
                                       // is determined internally via inspection of the incoming data, so
                                       // the kSecItemPemArmour flag is ignored.
                                       NULL,
                                       NULL, // Don't import into a keychain
                                       &temparray);
        if (oserr) {
            CFStringRef str = SecCopyErrorMessageString(oserr, NULL);
            logError(string("SecItemImport: ") + CFStringGetCStringPtr(str, kCFStringEncodingUTF8));
            CFRelease(str);
            break;
        }
        pubKey = (SecKeyRef) CFArrayGetValueAtIndex(temparray, 0);
        CFRetain(pubKey); //bump ref count, now we own this and need to release it eventually
    } while (0);

    if (keyData) {
        CFRelease(keyData); //might be wrong to release here, not sure if SecItemImport makes a copy of the bytes, it looks like it does
        //https://opensource.apple.com/source/libsecurity_keychain/libsecurity_keychain-55035/lib/SecImport.cpp
        //http://opensource.apple.com//source/libsecurity_keychain/libsecurity_keychain-14/lib/SecImportExportPem.cpp
    }
    if (temparray) {
        CFRelease(temparray);
    }
    if (readTransform) {
        CFRelease(readTransform);
    }
    if (cfrs) {
        CFRelease(cfrs);
    }
    if (url) {
        CFRelease(url);
    }

    return pubKey;
}

void Crypto::freePubKey(PUBKEY_TYPE pubKey) {
    if (pubKey) {
        CFRelease(pubKey);
    }
}

void Crypto::logFreeErrorExtended(const StaticString &prefix, CFErrorRef &error) {
    if (error) {
        CFStringRef description = CFErrorCopyDescription((CFErrorRef) error);
        CFStringRef failureReason = CFErrorCopyFailureReason((CFErrorRef) error);
        CFStringRef recoverySuggestion = CFErrorCopyRecoverySuggestion((CFErrorRef) error);

        logError(prefix +
                ": " + CFStringGetCStringPtr(description, kCFStringEncodingUTF8) +
                "; " + CFStringGetCStringPtr(failureReason, kCFStringEncodingUTF8) +
                "; " + CFStringGetCStringPtr(recoverySuggestion, kCFStringEncodingUTF8)
                );

        CFRelease(recoverySuggestion);
        CFRelease(failureReason);
        CFRelease(description);
        CFRelease(error);
        error = NULL;
    }
}

#else

Crypto::Crypto() {
    OpenSSL_add_all_algorithms();
}

Crypto::~Crypto() {
    EVP_cleanup();
}

bool Crypto::generateAndAppendNonce(string &nonce) {
    nonce.append(toString(SystemTime::getUsec()));

    int rndLen = 16;
    unsigned char rndChars[rndLen];

    if (1 != RAND_bytes(rndChars, rndLen)) {
        logErrorExtended("RAND_bytes failed for nonce");
        return false;
    }

    char rndChars64[modp_b64_encode_len(rndLen)];
    modp_b64_encode(rndChars64, (const char *) rndChars, rndLen);

    nonce.append(rndChars64);
    return true;
}

bool Crypto::encryptAES256(char *dataChars, size_t dataLen, AESEncResult &aesEnc) {
    assert(dataLen > 0 && dataChars != NULL);

    aesEnc.encrypted = NULL;
    aesEnc.key = NULL;
    aesEnc.iv = NULL;

    bool result = false;
    EVP_CIPHER_CTX *aesEncryptContext = NULL;

    do {
        // 1. Generate random key (secret) and init vector to be used for the encryption
        aesEnc.keyLen = AES_KEY_BYTESIZE;
        aesEnc.key = (unsigned char*) OPENSSL_malloc(aesEnc.keyLen);
        if (aesEnc.key == NULL) {
            logErrorExtended("OPENSSL_malloc failed");
            break;
        }

        aesEnc.ivLen = AES_CBC_IV_BYTESIZE;
        aesEnc.iv = (unsigned char*) malloc(aesEnc.ivLen); // not secret
        if (aesEnc.iv == NULL) {
            logError("malloc for IV failed");
            break;
        }

        if (1 != RAND_bytes(aesEnc.key, aesEnc.keyLen)) {
            logErrorExtended("RAND_bytes failed for AES key");
            break;
        }
        if (1 != RAND_bytes(aesEnc.iv, aesEnc.ivLen)) {
            logErrorExtended("RAND_bytes failed for IV");
            break;
        }

        // 2. Get ready to encrypt
        aesEncryptContext = EVP_CIPHER_CTX_new();
        if (aesEncryptContext == NULL) {
            logErrorExtended("EVP_CIPHER_CTX_new failed");
            break;
        }

        aesEnc.encrypted = (unsigned char*) malloc(dataLen + AES_BLOCK_SIZE); // not secret
        if (aesEnc.encrypted == NULL) {
            logError("malloc for encryptedChars failed " + toString(dataLen + AES_BLOCK_SIZE));
            break;
        }

        // 3. Let's go
        if (1 != EVP_EncryptInit_ex(aesEncryptContext, EVP_aes_256_cbc(), NULL, aesEnc.key, aesEnc.iv)) {
            logErrorExtended("EVP_EncryptInit_ex failed");
            break;
        }

        size_t blockLength = 0;
        size_t writeIdx = 0;
        if (1 != EVP_EncryptUpdate(aesEncryptContext, aesEnc.encrypted + writeIdx, (int *) &blockLength, (unsigned char*) dataChars, dataLen)) {
            logErrorExtended("EVP_EncryptUpdate failed");
            break;
        }
        writeIdx += blockLength;

        if (1 != EVP_EncryptFinal_ex(aesEncryptContext, aesEnc.encrypted + writeIdx, (int *) &blockLength)) {
            logErrorExtended("EVP_EncryptFinal_ex failed");
            break;
        }
        writeIdx += blockLength;
        aesEnc.encryptedLen = writeIdx;

        result = true;
    } while(0);

    if (!result) {
        // convenience: free the result if it's not valid anyway
        freeAESEncrypted(aesEnc);
    }

    if (aesEncryptContext != NULL) {
        EVP_CIPHER_CTX_free(aesEncryptContext);
    }

    return result;
}

void Crypto::freeAESEncrypted(AESEncResult &aesEnc) {
    if (aesEnc.encrypted != NULL) {
        free(aesEnc.encrypted);
        aesEnc.encrypted = NULL;
    }
    if (aesEnc.iv != NULL) {
        free(aesEnc.iv);
        aesEnc.iv = NULL;
    }

    // Secret parts were allocated differently
    if (aesEnc.key != NULL) {
        OPENSSL_free(aesEnc.key);
        aesEnc.key = NULL;
    }
}

bool Crypto::encryptRSA(unsigned char *dataChars, size_t dataLen,
        string encryptPubKeyPath, unsigned char **encryptedCharsPtr, size_t &encryptedLen) {
    RSA *rsaPubKey = NULL;
    EVP_PKEY *rsaPubKeyEVP = NULL;
    EVP_PKEY_CTX *ctx = NULL;
    bool result = false;

    do {
        // 1. Get the RSA public key to encrypt with
        rsaPubKey = loadPubKey(encryptPubKeyPath.c_str());
        if (rsaPubKey == NULL) {
            logError("Failed to load public key at " + encryptPubKeyPath);
            break;
        }

        rsaPubKeyEVP = EVP_PKEY_new();
        if (1 != EVP_PKEY_assign_RSA(rsaPubKeyEVP, rsaPubKey)) {
            logErrorExtended("EVP_PKEY_assign_RSA");
            freePubKey(rsaPubKey); // since it's not tied to EVP key yet
            break;
        }

        // 2. Prepare for encryption
        ctx = EVP_PKEY_CTX_new(rsaPubKeyEVP, NULL);
        if (ctx == NULL) {
            logErrorExtended("EVP_PKEY_CTX_new");
            break;
        }
        if (1 != EVP_PKEY_encrypt_init(ctx)) {
            logErrorExtended("EVP_PKEY_encrypt_init");
            break;
        }
        if (1 != EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING)) {
            logErrorExtended("EVP_PKEY_CTX_set_rsa_padding");
            break;
        }

        // 3. First encrypt to get encryptedLen
        if (1 != EVP_PKEY_encrypt(ctx, NULL, &encryptedLen, (unsigned char *) dataChars, dataLen)) {
            logErrorExtended("EVP_PKEY_encrypt (first)");
            break;
        }

        *encryptedCharsPtr = (unsigned char *) malloc(encryptedLen); // not secret
        if (*encryptedCharsPtr == NULL) {
            logError("malloc for encryptedChars failed" + toString(encryptedLen));
            break;
        }

        if (1 != EVP_PKEY_encrypt(ctx, (unsigned char *) *encryptedCharsPtr, &encryptedLen,
                (unsigned char *) dataChars, AES_KEY_BYTESIZE)) {
            logErrorExtended("EVP_PKEY_encrypt (second)");
            break;
        }

        result = true;
    } while (0);

    if (ctx != NULL) {
        EVP_PKEY_CTX_free(ctx);
    }
    if (rsaPubKeyEVP != NULL) {
        EVP_PKEY_free(rsaPubKeyEVP); // also frees the rsaPubKey
    }

    return result;
}

bool Crypto::verifySignature(string signaturePubKeyPath, char *signatureChars, int signatureLen, string data) {
    RSA *rsaPubKey = NULL;
    EVP_PKEY *rsaPubKeyEVP = NULL;
    EVP_MD_CTX *mdctx = NULL;
    bool result = false;

    do {
        rsaPubKey = loadPubKey(signaturePubKeyPath.c_str());
        if (rsaPubKey == NULL) {
            logError("Failed to load public key at " + signaturePubKeyPath);
            break;
        }

        rsaPubKeyEVP = EVP_PKEY_new();
        if (!EVP_PKEY_assign_RSA(rsaPubKeyEVP, rsaPubKey)) {
            freePubKey(rsaPubKey);
            logErrorExtended("EVP_PKEY_assign_RSA");
            break;
        }

        if (!(mdctx = EVP_MD_CTX_create())) {
            logErrorExtended("EVP_MD_CTX_create");
            break;
        }

        if (1 != EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, rsaPubKeyEVP)) {
            logErrorExtended("EVP_DigestVerifyInit");
            break;
        }

        if (1 != EVP_DigestVerifyUpdate(mdctx, data.c_str(), data.length())) {
            logErrorExtended("EVP_DigestVerifyUpdate");
            break;
        }

        if (1 != EVP_DigestVerifyFinal(mdctx, (unsigned char *) signatureChars, signatureLen)) {
            logErrorExtended("EVP_DigestVerifyFinal");
            break;
        }

        result = true;
    } while(0);

    if (mdctx) {
        EVP_MD_CTX_destroy(mdctx);
    }

    if (rsaPubKeyEVP) {
        EVP_PKEY_free(rsaPubKeyEVP);
        // freePubKey not needed, already free by EVP_PKEY_free.
    }

    return result;
}

PUBKEY_TYPE Crypto::loadPubKey(const char *filename) {
    FILE *fp = fopen(filename, "rb");
    if (fp == NULL) {
        return NULL;
    }

    RSA *rsa = RSA_new();
    rsa = PEM_read_RSA_PUBKEY(fp, &rsa, NULL, NULL);
    fclose(fp);
    return rsa;
}

void Crypto::freePubKey(PUBKEY_TYPE pubKey) {
    if (pubKey) {
        RSA_free(pubKey);
    }
}

void Crypto::logErrorExtended(const StaticString &prefix) {
    char err[500];
    ERR_load_crypto_strings();
    ERR_error_string(ERR_get_error(), err);
    P_ERROR(prefix << ": " << err);
    ERR_free_strings();
}

#endif

void Crypto::logError(const StaticString &error) {
    P_ERROR(error);
}

} // namespace Passenger

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.0 [PHP 7 Update] [25.02.2019] maintained by KaizenLouie | C99Shell Github | Generation time: 0.0434 ]--