Last active
October 6, 2023 12:58
Revisions
-
Semdevmaster revised this gist
Oct 6, 2023 . 2 changed files with 66 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,63 @@ <?php declare(strict_types=1); namespace Modules\ApiV1\Services; use phpseclib3\Crypt\Common\PrivateKey; use phpseclib3\Crypt\Common\PublicKey; use phpseclib3\Crypt\RSA; use phpseclib3\Crypt\PublicKeyLoader; class EncryptionService { public static function generateKeys(): void { $privateKey = RSA::createKey(); self::saveKeysToEnv($privateKey->toString('PKCS8'), $privateKey->getPublicKey()->toString('PKCS8')); } public static function getPublicKey(): PublicKey { return PublicKeyLoader::loadPublicKey(config('encryption.public_key_path')); } public static function getPrivateKey(): PrivateKey { return PublicKeyLoader::loadPrivateKey(config('encryption.private_key_path')); } public static function encrypt($plaintext): bool|string { return self::getPublicKey() ->encrypt($plaintext); } public static function decrypt($ciphertext): bool|string { return self::getPrivateKey() ->decrypt($ciphertext); } private static function saveKeysToEnv($privateKeyString, $publicKeyString): void { $envFile = app()->environmentFilePath(); $contents = file_get_contents($envFile); $privateKeyExists = str_contains($contents, 'APP_PRIVATE_KEY='); $publicKeyExists = str_contains($contents, 'APP_PUBLIC_KEY='); if ($privateKeyExists) { $contents = preg_replace('/APP_PRIVATE_KEY=.*/', "APP_PRIVATE_KEY=\"$privateKeyString\"", $contents); } else { $contents .= "\nAPP_PRIVATE_KEY=\"$privateKeyString\""; } if ($publicKeyExists) { $contents = preg_replace('/APP_PUBLIC_KEY=.*/', "APP_PUBLIC_KEY=\"$publicKeyString\"", $contents); } else { $contents .= "\nAPP_PUBLIC_KEY=\"$publicKeyString\""; } file_put_contents($envFile, $contents); } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,6 @@ <?php declare(strict_types=1); use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; use Modules\ApiV1\Services\EncryptionService; -
Semdevmaster revised this gist
Oct 6, 2023 . 1 changed file with 6 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,9 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; use Modules\ApiV1\Services\EncryptionService; use phpseclib3\Crypt\AES; use phpseclib3\Crypt\Random; Route::post('test', static function (Request $request) { $data = base64_decode($request->input('data')); $decrypted_aes_key = EncryptionService::decrypt(base64_decode($request->input('aesKeyEncrypted'))); -
Semdevmaster created this gist
Oct 6, 2023 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,132 @@ class SecureTransport { constructor (algorithm = 'AES-GCM') { this.algorithm = algorithm } async encrypt (targetString) { const rsaKey = await this.loadRsaKey() const aesKey = await this.generateAesKey() const encryptedAesKey = await this.encryptAesKeyWithPublicRSAKey(aesKey, rsaKey) const { ciphertext, iv } = await this.aesEncrypt(targetString, aesKey) const base64EncryptedData = this.arrayBufferToBase64(ciphertext) const base64Iv = this.arrayBufferToBase64(iv) const base64EncryptedAesKey = this.arrayBufferToBase64(encryptedAesKey) return { data: base64EncryptedData, iv: base64Iv, aesKeyEncrypted: base64EncryptedAesKey, aesKey } } async decrypt (ciphertext, iv, aesKey) { const ciphertextBuffer = this.base64ToArrayBuffer(ciphertext) const nonceBuffer = this.base64ToArrayBuffer(iv) return await this.aesDecrypt(ciphertextBuffer, aesKey, nonceBuffer) } async loadRsaKey () { const rsa_key = localStorage.getItem('rsa_key') if (!rsa_key) { console.log('В хранилище нет ключа для загрузки') } return await this.importRsaKey(rsa_key) } importRsaKey (pem) { const pemHeader = '-----BEGIN PUBLIC KEY-----' const pemFooter = '-----END PUBLIC KEY-----' const pemContents = pem.substring(pemHeader.length, pem.length - pemFooter.length - 1) return crypto.subtle.importKey( 'spki', this.base64ToArrayBuffer(pemContents), { name: 'RSA-OAEP', hash: 'SHA-256', }, true, ['encrypt', 'wrapKey'] ) } async generateAesKey (algorithm = 'AES-GCM', length = 256, extractable = true) { return crypto.subtle.generateKey( { name: algorithm, length: length, }, extractable, ['encrypt', 'decrypt'] ) } async encryptAesKeyWithPublicRSAKey (aesKey, rsaKey) { return await crypto.subtle.wrapKey( 'raw', aesKey, rsaKey, { name: 'RSA-OAEP' } ) } async aesEncrypt (plaintext, aesKey, ivLength = 12) { const iv = crypto.getRandomValues(new Uint8Array(ivLength)) const ciphertext = await crypto.subtle.encrypt( { name: this.algorithm, iv }, aesKey, new TextEncoder().encode(plaintext) ) return { ciphertext, aesKey, iv } } async aesDecrypt (ciphertext, key, iv) { const plaintext = await crypto.subtle.decrypt( { name: this.algorithm, iv }, key, ciphertext ) return new TextDecoder().decode(plaintext) } arrayBufferToBase64 (buffer) { let binary = '' const bytes = new Uint8Array(buffer) const len = bytes.byteLength for (let i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]) } return btoa(binary) } base64ToArrayBuffer (base64) { const binaryString = atob(base64) const len = binaryString.length const bytes = new Uint8Array(len) for (let i = 0; i < len; i++) { bytes[i] = binaryString.charCodeAt(i) } return bytes.buffer } } export default new SecureTransport() /* Example of using this class const targetString = 'Привет сервер' const { data, iv, aesKeyEncrypted, aesKey } = await secureTransport.encrypt(targetString) const { ciphertext, iv: response_iv } = await fetch( 'https://my-site.ru/api/v1/test', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ data, iv, aesKeyEncrypted }), } ).then(response => response.json()) const decrypted_data = await secureTransport.decrypt(ciphertext, response_iv, aesKey) console.log(decrypted_data) */ This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,31 @@ Route::post('test', static function (Request $request) { $data = base64_decode($request->input('data')); $decrypted_aes_key = EncryptionService::decrypt(base64_decode($request->input('aesKeyEncrypted'))); $iv = base64_decode($request->input('iv')); $tagLength = 16; $tag = substr($data, -$tagLength); $ciphertext = substr($data, 0, -$tagLength); $aes = new AES('gcm'); $aes->setKeyLength(256); $aes->setKey($decrypted_aes_key); $aes->setNonce($iv); $aes->setTag($tag); $plaintext = $aes->decrypt($ciphertext); dump($plaintext); //=================================================== $target_string = 'Привет клиент'; $iv = Random::string(12); $aes->setNonce($iv); $result = $aes->encrypt($target_string); $tag = $aes->getTag(); return [ 'ciphertext' => base64_encode($result.$tag), 'iv' => base64_encode($iv), ]; });