## RSA ECDSA

Windows specific questions.
deltarho[1859]
Posts: 1658
Joined: Jan 02, 2017 0:34
Location: UK

### RSA ECDSA

Most of you will know what public key encryption and signing is but some of you may not. For those of you that do not here are two excellent sites worth checking out.

RSA and DSA

Both methods are used here in the context of sending a message encrypted by a symmetric key algorithm suchas AES.

The Sender

1) Encrypts the message.
2) The encryption key/password is encrypted using recipient's RSA public key.
3) A hash of the encrypted message is determined.
4) The hash is then signed using the sender's DSA private key.

If the key/password is very strong, preferably a 256 bit binary key, then the encrypted key/password will not need to be changed that often.

RSA encryption could be used on the message but the message size is limited to the RSA bit strength employed and reduced even further if padding is used. The recommended padding is the Optimal Asymmetric Encryption Padding (OAEP) scheme, which uses a hash function, resulting in this simple formula for determining the maximum message size: (Bit strength)\8 - 2 - 2x(Hash length)\8. So, with a bit strength of 1024 and a 160 bit hash we get 86 bytes. We have a very different animal then to AES, for example, which can handle GBs of message. Actually, the term padding is a misnomer. If we applied RSA 1024 encryption to 160 bits, say, then the encrypted output would be 1024 bits, the RSA bit strength, but we would not recognise the structure of the 160 bits. It has the opposite effect to a message digest.

The Recipient

1) The signature is verified using the sender's DSA public key.
2) A hash of the encrypted message is determined and if that equates with the sent hash then the encrypted message is effectively authenticated.
3) The encrypted key/password is decrypted using the recipient's RSA private key.
4) The decrypted message is then decrypted.

If Eve, a dastardly eavesdropper, intercepts any of the files sent then they will be of no use to her without the recipient's RSA private key. The plaintext version of the key/password never enters the public domain.

Bit strength

RSA 1024 was broken in the middle of 2017 and the US National Institute of Standards and Technology (NIST) is recommending we now use at least RSA 2048. There is a correspondence between the RSA modulus/bit strength and security strength. AES 128 has a security strength of 128 bits. SHA512, for example, because of the birthday paradox, has a security strength of 256 bits. Here is a comparison taken from NIST Special Publication 800-57 Part 1 Revision 4 Recommendation for Key ManagementJanuary 2016 Table 2 page 53.

Code: Select all

`SecurityStrength  RSA modulus ECDSA  80        1024       160 112        2048       224 128        3072       256 192        7680       384 256       15360       512`

The DSA bit strengths are the same as RSA. More on Elliptic Curve Digital Signature Algorithm (ECDSA) later.

The correspondence between RSA bit strength and security strength is more precisely defined in Implementation Guidance for FIPS 140-2 and the Cryptographic Module Validation Program page 106.

The NIST reckon that RSA 2048 should hold us in good stead until about 2030 beyond which we should move up to 3072 bits. The NIST are not currently 'pushing' over and above RSA 3072. The NIST are not the only authority making recommendations and, after much reading, the following code, GenerateKeyPairs, a console application, defaults to a bit strength of 3072 bits; exceeding all minimum recommendations at this time (2018).

With regard DSA the NIST Digital Signature Standard specifies the following choices for the pair L and N where L is the bit strength and N is the length of the hash function to be signed.

(1024, 160) NIST FIPS-186-2 for earlier than Windows 8
(2048, 224) Above plus NIST FIPS-186-3 for Windows 8 and later
(2048, 256) -do-
(3072, 256) -do-

DSA (2048, 224) does not work with Microsoft APIs because SHA224 is not supported by Windows. FIPS-186-4 was published July 2013 but the four choices above were not expanded upon. DSA (1024, 160) has not been broken yet but it is no longer recommended by the NIST. So, the DSA used in Windows 7 is no longer recommended.

I found DSA to be very slow. For a 256 bit hash the signing and verifying times for DSA (2048, 256) and (3072, 256) were in the seconds whereas with ECDSA 256 I got, with one test, 0.9ms and 1.2ms for signing and verifying respectively. There are not many DSA/ECDSA performance comparisons on the Internet but of those that I found they did not report such a marked difference as I found. Perhaps the Microsoft DSA implementation is a poor one. With DSA I would have been lumbered with writing code to cater for Windows 7 (and earlier) and Windows 8 (and later).

Clearly, ECDSA wins hands down with regard to Microsoft's APIs and is OK for Windows Vista and later. We have a few ECDSA bit strengths to chose from but with ECDSA 256 having a security strength of 128 bits it is an ideal partner for RSA 3072 at 128 bits.

A little off topic but until recently the NIST recommended that passwords should have a bit strength/entropy of at least 80 bits. This has now been updated to 112 bits.

Console application GenerateKeyPairs.

We could have a separate folder for each person we deal with but there will be the resulting file navigation to contend with. I have opted to have everything in one folder: My keys, other people's keys and the applications. To this end GenerateKeyPairs asks for a prefix to add to the key names. For my keys I simply chose DR_ and got these keys.

DR_RSAPublicKey3072.dat
DR_RSAPrivateKey3072.dat
DR_ECDSAPublicKey256.dat
DR_ECDSAPrivateKey256.dat

The bit strengths are got from the code assignments.

On my machine using '-gen gcc -Wc -O3' the keys were generated in a little more than four seconds. If you have FreeBASIC 64 bit then use it because generation is a lot faster. Just to put things into perspective I generated a public and private key pair for RSA 16384, with 32 bit, and it took over 8 minutes. The law of diminishing returns is very noticeable with both RSA and DSA key generation and this is reflected when using the keys.

GUI application RSA-ECDSA

This was written using José Roca's WinFBX Windows framework. If you have Paul Squires' WinFBE then you will already have the necessary files on board and it is a simple matter to add the WinFBX path to the Editor's Compiler Setup. If you are using another IDE then go to JoseRoca / WinFBX at GitHub and click on the green 'Clone or download' button; then click on 'Download ZIP'. Within the unzipped WinFBX-master folder is a folder called Afx. Copy Afx to your FreeBASIC's installation's inc folder. That is it. If you have FreeBASIC 64 bit then do the same into it's inc folder; wherever you put that. I am suggesting the GitHub link as it has the latest Afx folder. In the WinFBX folder there are a lot of examples and there is also FBWinSpy for 'dissecting' GUIs. You can get a copy of the WinFBX help file here at the bottom of the first post.

I am compiling RSA-ECDSA.bas with '-gen gcc -Wc -O3 RSA-ECDA.rc'.

This what RSA-ECDSA looks like.

We don't need a help file for that, do we? <smile>

The Microsoft open file dialog is used extensively and I am using a heavily adapted version of José's code. Since there are a lot of different files the filtering is done programmatically. If we clicked on 'Verify a .sig file', for example, then we get a list of *ECDSAPublicKey*.dat files and nothing else. We are not left scratching our heads as to which algorithm we should use and what type of key. After selection we get another open file dialog with a list of *Hash.dat files and nothing else. After that selection we get another open file dialog with a list of *Hash.dat.sig files and nothing else. The only output with this task is a message advising whether we have a successful verification or not. The open file dialog title bar keeps us informed; as does the filter.

The Function Hash is one of my stock functions. It could have ben trimmed down for RSA-ECDSA but that would defeat the object of a stock function. <smile>

The first three tasks are obvious and don't require an explanation.

Hash a file option.

This is for hashing an encrypted message - the one subject to symmetric encryption, such as AES. If we hash <Somefile.ext> then we get <Somefile.ext_Hash.dat> and that will be a 256 bit (32 byte) binary hash; as opposed to a 64 character hex string. The open file dialog here has an all files ("*.*") filter; I don't know how you are naming your encrypted message.

Verify hashes option.

The first open file dialog needs the encrypted message which is then hashed for us. The second open file dialog needs a hash file, <Somefile.ext_Hash.dat>. This operation is similar to 'Verify a .sig file' in that the only output with this task is a message advising whether we have a successful authentication or not.

RSA-ECDSA specifics

The padlock icon in the window caption is placed there by

Code: Select all

`pWindow.SmallIcon = LoadImage(hInstance, MAKEINTRESOURCE(100), IMAGE_ICON, 32, 32, LR_SHARED)`

and the entry '100 icon padlock.ico' in the resource file.

The 'signature' bitmap at the bottom right is placed there by

Code: Select all

`LoadImage(hInstance, MAKEINTRESOURCE(101), IMAGE_BITMAP, 0, 0, LR_SHARED)pWindow.AddControl("BitMapButton", , ID_DR, "#101", 223, 266, 26, 33)`

and the entry '101 bitmap DRmed.bmp' in the resource file.

The 'signature' is just a bit of fun. I figured that I couldn't write an application for signing without signing the dialog. <smile> Just click on the bitmap for another reason for it's existence.

The images can be downloded at the beginning of the next post.

The 256 bit hashing done in 'Hash a file' and 'Verify hashes' uses a truncated SHA512 and adapted to overcome the length extension bug in the SHA-2 family of hash functions.

If RSA-ECDSA's closing position differs to that of its opening position it's closing position will be remembered and used at the next opening. I do this often as I have two monitors and prefer some applications to open on the secondary monitor. No big deal but it is there if required.

TaskDialog, as opposed to messagebox, has been used throughout. José's code makes it very easy to implement. Some of the parameters are the same for each execution so I wrote a little wrapper which takes just four parameters; the same number as messagebox. TaskDialog is nothing like as powerfull as TaskDialogIndirect and is only a small step up from messagebox but here is an example.

That was got from

Code: Select all

`TDWrapper Hwnd, "Hash comparison", "Hash of " + EncMainMessage + " and given hash match.", TD_INFORMATION_ICON`

All the source code is in the next post and any revisions will take place there. The files for theming are also there.

Code: Select all

`RSA 3072/ECDSA 256 (128) versus RSA 7680/ECDSA 384 (192) on key sizes 256 bits and 384 bits respectively. enc 0.2ms                         0.6msdec 9.3ms                       119.1mssig 0.3ms                         0.7msver 0.5ms                         1.0ms`

Here we can see the performance of RSA suffering very badly moving from a 128 bit security strength to a 192 bit security strength. The ECDSA performance, on the other hand, is very much less noticable. Having said that enc/dec on a key/password will be a rare event, perhaps every year or so. Organisations involved in mass sig/ver operations will be looking for a balance between speed and security and will need a very good reason to be using a security level of 192 bits in 2018. NIST clearance levels are 128 bits up to Secret and 192/256 bits up to Top Secret. For most of us RSA 3072/ECDSA 256 (128) is more than adequate.

As written RSA-ECDSA will not accomodate ECDSA 521. It could, but I am not going to go there. I have no need to rub shoulders with the NSA, GCHQ and their like.

Special thanks to José Roca - WinFBX is absolutely awesome.

Still on topic but minus the encryption/decryption aspect. Suppose you have a pdf which anyone can have but want to send it to someone in the knowledge that they know for certain it was from you and that is has not been tampered with; a licence agreement, for example. The message now is a pdf and not an encrypted file. Hash the pdf file and then sign the hash. When the recipient verifies the signature and then verifies the hashes using options 4 and 6 of the RSA-ECDSA dialog then they will know that you sent the pdf and it has not been tampered with. We can sign anything - a jpg or whatever.

You may have wondered what the difference between a digital signature and a HMAC is. HMAC is symmetrical: Both the sender and receiver use the same secret key. 'A' could produce a licence agreement and a HMAC but 'B' may repudiate sending anything. Digital Signatures are asymmetric and provide integrity plus non-repudiation whereas HMAC provides only integrity. 'B' cannot repudiate the signature as his/her private key is not known to anyone else and 'A' cannot try and pull a 'fast one'.

Quantum computers

The D-Wave 2000 qubit quantum computer, which costs \$15 million dollars and will need a spare room to put it in, is about 100 million times faster than a desktop PC or 3600 times faster than the current super computers. I do not know what the running costs are but if anyone can afford £15 million dollars they can probably afford getting some solar panels fitted on their roof. <smile> It is reckoned not to be a fully fledged quantum computer as, it seems, it does not exploit quantum entanglement. It may be some years before quantum computers become main stream, if ever they do. Remembering that 2^256 = 2^128 x 2^128 > 10^38 x 2^128 then AES256 is more powerful than 10^38 x AES128. It is thought that AES256 is post-quantum computer proof. I have not seen anything with regard ECDSA but the 'arithmetic' used by RSA and DSA is such that both are destined to be dead in the water in the post-quantum computer era. In other words the security strength of RSA and DSA based upon classical computers collapses with quantum computer computing. The NIST recently held a competition with regard to post-quantum computer cryptography. All being well we should be well prepared.

Finally, I should mention that cryptlib has both RSA, up to RSA 4096, and ECDSA, up to ECDSA 521, giving both a Windows and Linux route but my comfort zone is the Windows API so please forgive me for preferring to keep comfortable. <big smile>
Last edited by deltarho[1859] on Feb 13, 2018 20:12, edited 1 time in total.
deltarho[1859]
Posts: 1658
Joined: Jan 02, 2017 0:34
Location: UK

### Re: RSA ECDSA

Here are the images

Images

GenerateKeypairs.bas

Code: Select all

`#include once "windows.bi"#inclib "bcrypt"#include once "win/wincrypt.bi"#include once "file.bi"Const HashLen = 256 ' Corresponds to SHA256' Only ever use a HashLen of 256, 384 or 521#define STATUS_SUCCESS 0Dim As Ulong cbOutput, pcbResultDim As dword dwStatusDim As BCRYPT_KEY_HANDLE hKeyHandleDim As BCRYPT_ALG_HANDLE hAlgHandleDim As Long lError, i, BitStrengthDim As String sPrefixDim Blob() As ByteDim As Double t' Console specificsSetConsoleTitle("GenerateKeyPairs")SetWindowPos( GetConsoleWindow, HWND_TOPMOST, 200, 400, 0, 0, SWP_NOSIZE )Do  Input "Task file prefix: "; sPrefixLoop Until sPrefix <> ""Print "Please wait" : Print' RSABitStrength = 3072 ' Security strength: 128 bitst = TimerdwStatus = BCryptOpenAlgorithmProvider( @hAlgHandle, BCRYPT_RSA_ALGORITHM, "", 0 )If dwStatus <> STATUS_SUCCESS Then lError = 10 : Goto ErrorTrap' Create an empty objectdwStatus = BCryptGenerateKeyPair(hAlgHandle, @hKeyHandle, BitStrength, 0)If dwStatus <> STATUS_SUCCESS Then lError = 20 : Goto ErrorTrap' Populate objectdwStatus = BCryptFinalizeKeyPair(hKeyHandle, 0)If dwStatus <> STATUS_SUCCESS Then lError = 30 : Goto ErrorTrap' Generate RSA public key encrypt' Get public key memory blob length in pcbResultdwStatus = BCryptExportKey(hKeyHandle, 0, BCRYPT_RSAPUBLIC_BLOB, 0, 0, @pcbResult,0)If dwStatus <> STATUS_SUCCESS Then lError = 40: Goto ErrorTrapRedim Blob(1 To pcbResult) As BytecbOutput = pcbResultdwStatus = BCryptExportKey(hKeyHandle, 0, BCRYPT_RSAPUBLIC_BLOB, @Blob(1), cbOutput, @pcbResult,0)If dwStatus <> STATUS_SUCCESS Then lError = 50: Goto ErrorTrapIf Fileexists( sPrefix + "RSAPublicKey" + Str(BitStrength) + ".dat" ) Then Kill sPrefix + "RSAPublicKey" + Str(BitStrength) + ".dat"Open sPrefix+"RSAPublicKey" + Str(BitStrength) + ".dat" For Binary As #1Put #1, , Blob()Close #1Print sPrefix + "RSA public key generated"Print' Generate RSA private key decrypt' Get private key memory blob length in pcbResultdwStatus = BCryptExportKey(hKeyHandle, 0, BCRYPT_RSAPRIVATE_BLOB, 0, 0, @pcbResult,0)If dwStatus <> STATUS_SUCCESS Then lError = 60: Goto ErrorTrapRedim Blob(1 To pcbResult) As BytecbOutput = pcbResultdwStatus = BCryptExportKey(hKeyHandle, 0, BCRYPT_RSAPRIVATE_BLOB, @Blob(1), cbOutput, @pcbResult,0)If dwStatus <> STATUS_SUCCESS Then lError = 70: Goto ErrorTrapIf Fileexists( sPrefix + "RSAPrivateKey" + Str(BitStrength) + ".dat" ) Then Kill sPrefix + "RSAPrivateKey" + Str(BitStrength) + ".dat"Open sPrefix + "RSAPrivateKey" + Str(BitStrength) + ".dat" For Binary As #1Put #1, , Blob()Close #1Print sPrefix+"RSA private key generated"PrintBCryptCloseAlgorithmProvider(hAlgHandle, 0)BCryptDestroyKey hKeyHandle' ECDSABitStrength = 256 ' Security strength: 128 bitsdwStatus = BCryptOpenAlgorithmProvider( @hAlgHandle, wstr( "ECDSA_P" + Str(HashLen) ), "", 0 )If dwStatus <> STATUS_SUCCESS Then lError = 80 : Goto ErrorTrap' Create an empty objectdwStatus = BCryptGenerateKeyPair(hAlgHandle, @hKeyHandle, BitStrength, 0)If dwStatus <> STATUS_SUCCESS Then lError = 90 : Goto ErrorTrap' Populate objectdwStatus = BCryptFinalizeKeyPair(hKeyHandle, 0)If dwStatus <> STATUS_SUCCESS Then lError = 100 : Goto ErrorTrap' Generate ECDSA public key verify' Get public key memory blob length in pcbResultdwStatus = BCryptExportKey(hKeyHandle, 0, BCRYPT_ECCPUBLIC_BLOB, 0, 0, @pcbResult, 0)If dwStatus <> STATUS_SUCCESS Then lError = 110: Goto ErrorTrapRedim Blob(1 To pcbResult) As BytecbOutput = pcbResultdwStatus = BCryptExportKey(hKeyHandle, 0, BCRYPT_ECCPUBLIC_BLOB, @Blob(1), cbOutput, @pcbResult, 0)If dwStatus <> STATUS_SUCCESS Then lError = 120: Goto ErrorTrapIf Fileexists( sPrefix + "ECDSAPublicKey" + Str(BitStrength) + ".dat" ) Then Kill sPrefix + "ECDSAPublicKey" + Str(BitStrength) + ".dat"Open sPrefix+"ECDSAPublicKey" + Str(BitStrength) + ".dat" For Binary As #1Put #1, , Blob()Close #1Print sPrefix + "ECDSA public key generated"Print' Generate ECDSA private key sign' Get private key memory blob length in pcbResultdwStatus = BCryptExportKey(hKeyHandle, 0, BCRYPT_ECCPRIVATE_BLOB, 0, 0, @pcbResult, 0)If dwStatus <> STATUS_SUCCESS Then lError = 130: Goto ErrorTrapRedim Blob(1 To pcbResult) As BytecbOutput = pcbResultdwStatus = BCryptExportKey(hKeyHandle, 0, BCRYPT_ECCPRIVATE_BLOB, @Blob(1), cbOutput, @pcbResult, 0)If dwStatus <> STATUS_SUCCESS Then lError = 140: Goto ErrorTrapIf Fileexists( sPrefix + "ECDSAPrivateKey" + Str(BitStrength) + ".dat" ) Then Kill sPrefix + "ECDSAPrivateKey" + Str(BitStrength) + ".dat"Open sPrefix + "ECDSAPrivateKey" + Str(BitStrength) + ".dat" For Binary As #1Put #1, , Blob()Close #1Print sPrefix+"ECDSA private key generated"Printt = Timer - tPrint "Time taken:"; t; "s"Goto TidyUpErrorTrap:Print "Error at location " + Str(lError);", Windows error code ";Hex(dwStatus)TidyUp:If hAlgHandle <> 0 Then BCryptCloseAlgorithmProvider(hAlgHandle, 0)If hKeyHandle <> 0 Then BCryptDestroyKey hKeyHandlePrint : Print "Press any key"Sleep`

AES-RSA-ECDSA.bas ( March 5, 2018 )

Code: Select all

`' ########################################################################################' With regard Afx material:' Copyright (c) 2016 José Roca. Freeware. Use at your own risk.' This CODE And INFORMATION Is PROVIDED "As Is" WITHOUT WARRANTY OF Any KIND, EITHER' EXPRESSED Or IMPLIED, INCLUDING BUT Not LIMITED To THE IMPLIED WARRANTIES OF' MERCHANTABILITY And/Or FITNESS For A PARTICULAR PURPOSE.' ' #########################################################################################Define UNICODE#Define _WIN32_WINNT &h0602#Include Once "Afx/CWindow.inc"#Include Once "Afx/CFileSys.inc"#Inclib "bcrypt"#Inclib "crypt32"#Include Once "windows.bi"#Include Once "String.bi"Using AfxConst HashLen = 256 ' Corresponds To SHA256' Only ever use a HashLen of 256, 384 Or 521Const STATUS_SUCCESS = 0Const STATUS_INVALID_SIGNATURE = &HC000A000Const IDC_GROUPBOX = 1001Const IDC_OPTION1 = 1002Const IDC_OPTION2 = 1003Const IDC_OPTION3 = 1004Const IDC_OPTION4 = 1005Const IDC_OPTION5 = 1006Const IDC_OPTION6 = 1007Const IDC_OPTION7 = 1008Const IDC_OPTION8 = 1009Const ID_OK = 1010Const ID_DR = 1011Const EncAES = 1Const DecAES = 2Const Enc = 3Const Dec = 4Const Sig = 5Const Ver = 6Const HashFile = 7Const HashCompare = 8Const Enc_File = 9Const Sig_File = 10Const Hash_File = 11Const All_Files1 = 12Const All_Files2 = 13Const AES128 = 128Const AES192 = 192Const AES256 = 256const BlockSize = 16const BufferSize = 256 * 1024#Define CrLf Chr(10) + Chr(13)' Following courtesy of Mr Swiss#Define IsFalse(e)  ( Not CBool(e) )#Define IsTrue(e)   ( CBool(e) )Declare Function WinMain (Byval hInstance As HINSTANCE, _Byval hPrevInstance As HINSTANCE, _Byval szCmdLine As Zstring Ptr, _Byval nCmdShow As Long) As LongEnd WinMain(GetModuleHandleW(NULL), NULL, Command(), SW_NORMAL)' // Forward declarationDeclare Function WndProc (Byval hwnd As HWND, Byval uMsg As UINT, Byval wParam As WPARAM, Byval lParam As LPARAM) As LRESULTDeclare Function AfxIFileOpenDialog (Byval hwndOwner As HWND, Byval DisplyType As Long, _Byval sigdnName As SIGDN = SIGDN_FILESYSPATH) As Wstring PtrDeclare Function IsHex( As String ) As LongDeclare Function Hash( As lpcwstr, As String, As Long, As Long, As Long, As String = Chr(0)) As StringDeclare Function GetFileHashEx( As String, As Long ) As StringDeclare Sub TDWrapper( As HWND, As PCWSTR, As PCWSTR, As PCWSTR )declare Function AES( As Long, As String, As String, As Long ) As LongDim Shared As Long xWindow, yWindowDim shared pFileSys As CFileSys  ' MainFunction WinMain (Byval hInstance As HINSTANCE, _  Byval hPrevInstance As HINSTANCE, _  Byval szCmdLine As Zstring Ptr, _  Byval nCmdShow As Long) As Long    Dim As Long f     ' // Set process DPI aware  AfxSetProcessDPIAware    ' // Create the main Window  Dim pWindow As CWindow  '  pWindow.SetFont("Tahoma", 10, FW_NORMAL, , , , DEFAULT_CHARSET)  pWindow.Create(NULL, "AES-RSA-ECDSA", @WndProc, ,,,, WS_SYSMENU Or WS_CAPTION, WS_EX_TOPMOST)  pWindow.SetClientSize(250, 360)    ' Open at last position    If pFileSys.Fileexists("Position.dat") Then    f = Freefile    Open "Position.dat" For Binary As #f    Get #f, , xWindow    Get #f, , yWindow    Close #f    Dim hwnd As Hwnd = pWindow.hWindow    SetWindowPos( HWnd, HWND_NOTOPMOST, xWindow, yWindow, 0, 0, SWP_NOSIZE )  Else    pWindow.Center  End If    ' Get small icon For titlebar  pWindow.SmallIcon = LoadImage(hInstance, MAKEINTRESOURCE(100), IMAGE_ICON, 32, 32, LR_SHARED)    ' // Add a group box control  Dim As Long h  h = 60  pWindow.AddControl("GroupBox", , IDC_GROUPBOX, "Choose one of the following tasks", 20, 12, 210, 224+h)  ' // Add radio buttons (the first one should have the WS_GROUP style)  pWindow.AddControl("RadioButton", , IDC_OPTION1, "Encrypt a file AES", 64, 48, 120, 16, WS_GROUP)  pWindow.AddControl("RadioButton", , IDC_OPTION2, "Decrypt a .aes file", 64, 78, 120, 16)  pWindow.AddControl("RadioButton", , IDC_OPTION3, "Encrypt a key RSA", 64, 48+h, 120, 16)  pWindow.AddControl("RadioButton", , IDC_OPTION4, "Decrypt a .enc file", 64, 78+h, 130, 16)  pWindow.AddControl("RadioButton", , IDC_OPTION5, "Sign a hash", 64, 108+h, 130, 16)  pWindow.AddControl("RadioButton", , IDC_OPTION6, "Verify a .sig file", 64, 138+h, 130, 16)  pWindow.AddControl("RadioButton", , IDC_OPTION7, "Hash a file", 64, 168+h, 130, 16)  pWindow.AddControl("RadioButton", , IDC_OPTION8, "Verify hashes", 64, 198+h, 130, 16)  ' // Add OK button  pWindow.AddControl("Button", , ID_OK, "OK", 80, 250+h, 88, 38)    'Get dialog image  LoadImage(hInstance, MAKEINTRESOURCE(101), IMAGE_BITMAP, 0, 0, LR_SHARED)  pWindow.AddControl("BitMapButton", , ID_DR, "#101", 223, 266+h, 26, 33)    LoadImage(hInstance, MAKEINTRESOURCE(102), IMAGE_ICON, 0, 0, LR_SHARED)    ' // Check the first radio button  'CheckDlgButton pWindow.hWindow, IDC_OPTION1, BST_CHECKED    ' // Dispatch Windows messages  Function = pWindow.DoEvents(nCmdShow)  End Function' Window procedureFunction WndProc (Byval hwnd As HWND, Byval uMsg As UINT, Byval wParam As WPARAM, Byval lParam As LPARAM) As LRESULT  Dim As Boolean FirstPass = True  Static As BCRYPT_ALG_HANDLE hRSAHandle, hECDSAHandle  Static As Long lChoice = Enc  Static As Long dllIsLoaded  'Static As Any Ptr AES  Dim As BCRYPT_KEY_HANDLE hKeyHandle  Dim As String sInFile, sOutFile, sInputFile, sHash, sSigFile, sHashFile, EncMainMessage, sDummy  Dim As Long lError, f, MaxFileSize  Dim As Ulong dwstatus, cbInput, dummy, cbOutPut, pcbResult, Stretch  Dim pbOutput() As Byte  Dim Blob() As Byte  Dim ptrBlob As Ulong Ptr  Dim pwszName As Wstring Ptr  Dim As Double t  Dim pFileSys As CFileSys  Dim As string PassKey, AESName      If FirstPass = True Then    If BCryptOpenAlgorithmProvider( @hRSAHandle, BCRYPT_RSA_ALGORITHM, "", 0 ) <> STATUS_SUCCESS Then      TDWrapper 0, "Error", "Unable To Open RSA algorithm provider.", TD_ERROR_ICON      End    End If    If BCryptOpenAlgorithmProvider( @hECDSAHandle, Wstr( "ECDSA_P" + Str(HashLen) ), "", 0 ) <> STATUS_SUCCESS Then      TDWrapper 0, "Error", "Unable To Open ECDSA algorithm provider.", TD_ERROR_ICON      End    End If    FirstPass = False  End If    Select Case uMsg        Case WM_COMMAND        Select Case Loword(wParam)        Case IDC_OPTION1      lChoice = EncAES            Case IDC_OPTION2      lChoice = DecAES          Case IDC_OPTION3      lChoice = Enc          Case IDC_OPTION4      lChoice = Dec          Case IDC_OPTION5      lChoice = Sig          Case IDC_OPTION6      lChoice = Ver         Case IDC_OPTION7      lChoice = HashFile          Case IDC_OPTION8      lChoice = HashCompare          Case ID_OK            Select Case lChoice              Case EncAES, DecAES         if lChoice = EncAES then          pwszName = AfxIFileOpenDialog(hwnd, All_Files2)        else          pwszName = AfxIFileOpenDialog(hwnd, DecAES )        end if        If pwszName Then          AESName = *pwszName          CoTaskMemFree(pwszName)          Dim rc As RECT          GetWindowRect( hWnd, @rc )          dim as long x, y          x = rc.Left - 36          y = rc.Top + 110          PassKey = AfxInputBox( Hwnd, x, y, "AES", "Please provide password/passkey", , , True )          if PassKey = "" Then exit function          If ( Len( Passkey ) Mod 2 <> 0 ) orelse ( Len( Passkey ) < 64 ) orelse IsHex( Passkey ) = 0 then            sDummy = right( Passkey, 2 )            Stretch = valint( sDummy )            If Stretch >= 32 Then Stretch = 24          End If          BlockInput True          ' Remove Close button          EnableMenuItem GetSystemMenu(hWnd, False), SC_CLOSE, MF_BYCOMMAND or MF_DISABLED          t = timer          dwStatus = AES( AES256, AESName, PassKey, Stretch )          t = timer - t          ' Restore Close button          EnableMenuItem GetSystemMenu(hWnd, False), SC_CLOSE, MF_BYCOMMAND or MF_ENABLED          BlockInput False          if dwStatus <> 0 then            select case dwStatus              case -5                TDWrapper Hwnd, AfxGetFileNameX(AESName) + " is a zero byte file.", "", TD_ERROR_ICON              case -6                TDWrapper Hwnd, "Password/Passkey verification failed", "", TD_ERROR_ICON            end select            exit function          end if          if lChoice = EncAES Then            TDWrapper Hwnd, "AES256 encryption", AfxGetFileNameX(AESName) + CrLf + CrLf + "Time taken: " _            + Format(t*1000, "0.0") + "ms", TD_INFORMATION_ICON          Else            TDWrapper Hwnd, "AES256 decryption", AfxGetFileNameX(AESName) + CrLf + CrLf + "Time taken: " _            + Format(t*1000, "0.0") + "ms", TD_INFORMATION_ICON          End If        End If                   Case Enc, Dec, Sig, Ver        ' Get task Blob        pwszName = AfxIFileOpenDialog(hwnd, lChoice)        If pwszName Then          sInfile = *pwszName          CoTaskMemFree(pwszName)          f = Freefile          Open sInFile For Binary As #f          cbInput = Lof(f)          Redim Blob(1 To cbInput) As Byte          Get #f, , Blob()          Close #f        Else          Exit Function        End If                If lChoice = Enc Then          pwszName = AfxIFileOpenDialog(hwnd, All_Files1)        Elseif lChoice = Dec Then          pwszName = AfxIFileOpenDialog(hwnd, Enc_File)        Else          pwszName = AfxIFileOpenDialog(hwnd, Hash_File)        End If        If pwszName = 0 Then Exit Function                sInfile = *pwszName        CoTaskMemFree(pwszName)        Dim pFileSys As CFileSys        Dim sExtn As CWSTR = pFileSys.GetExtensionName(sInFile)        If sExtn <> "enc" And sExtn <> "sig" Then          If lChoice = Enc Then            sOutFile = sInFile & ".enc"          Elseif lChoice = Sig Then            sOutFile = sInFile & ".sig"          End If        Else          sOutFile = Left( sInFile, Len( sInFile ) - 4 )        End If                ' Get target file And make sure it Is a valid size For RSA encryption        f = Freefile        Open sInFile For Binary As #f        sInputFile = String(Lof(f), 0)        Get #f, , sInputFile        If lChoice = Enc Then          ' 2nd Dword of header Is Bit strength          ptrBlob = Cast( Ulong Ptr, @Blob(5) )          MaxFileSize = Peek(Ulong, ptrBlob)\8 -2 - 2*HashLen\8          If Lof(f) > MaxFileSize Then             TDWrapper Hwnd, "RSA message size", "Target file must be less than Or equal To " _            + Str( MaxFileSize ) + " bytes.", TD_ERROR_ICON            Close #f            Exit Function          End If        End If        Close #f                Dim paddinginfo As BCRYPT_OAEP_PADDING_INFO        Dim algo As Wstring * 8        Dim buffer As String        algo = "SHA" + Str(HashLen)        buffer = String(HashLen, 0)        paddinginfo.pszAlgid = Varptr(algo)        paddinginfo.pblabel = Strptr(buffer)        paddinginfo.cblabel = HashLen                If lChoice = Enc Then          t = Timer          dwStatus = BCryptImportKeyPair( hRSAHandle, Null, BCRYPT_RSAPublic_BLOB, @hKeyHandle, _          @Blob(1), cbInput, 0 )          If dwStatus <> STATUS_SUCCESS Then lError = 10 : Goto ErrorTrap          ' Get Output length in pcbResult          dwStatus = Bcryptencrypt( hKeyhandle, Strptr(sInputFile), Len(sInputFile), @paddinginfo, _          Null, dummy, null, 0, @pcbResult, BCRYPT_PAD_OAEP)          If dwStatus <> STATUS_SUCCESS Then lError = 20 : Goto ErrorTrap          Redim pbOutput( 1 To pcbResult) As Byte          cbOutput = pcbResult          dwStatus = Bcryptencrypt( hKeyhandle, Strptr(sInputFile), Len(sInputFile), @paddinginfo, _          Null, dummy, @pbOutput(1), cbOutput, @pcbResult, BCRYPT_PAD_OAEP)          If dwStatus <> STATUS_SUCCESS Then lError = 30 : Goto ErrorTrap          t = Timer - t        Elseif lChoice = Dec Then          t = Timer          dwStatus = BCryptImportKeyPair( hRSAHandle, Null, BCRYPT_RSAPrivate_BLOB, @hKeyHandle, _          @Blob(1), cbInput, 0 )          If dwStatus <> STATUS_SUCCESS Then lError = 40 : Goto ErrorTrap          ' Get Output length in pcbResult          dwStatus = Bcryptdecrypt( hKeyhandle, Strptr(sInputFile), Len(sInputFile), @paddinginfo, _          Null, dummy, null, 0, @pcbResult, BCRYPT_PAD_OAEP)          If dwStatus <> STATUS_SUCCESS Then lError = 50 : Goto ErrorTrap          Redim pbOutput( 1 To pcbResult) As Byte          cbOutput = pcbResult          dwStatus = Bcryptdecrypt( hKeyhandle, Strptr(sInputFile), Len(sInputFile), @paddinginfo, _          Null, dummy, @pbOutput(1), cbOutPut, @pcbResult, BCRYPT_PAD_OAEP)          If dwStatus <> STATUS_SUCCESS Then lError = 60 : Goto ErrorTrap          t = Timer - t        Elseif lChoice = Sig Then          t = Timer          dwStatus = BCryptImportKeyPair( hECDSAHandle, Null, BCRYPT_ECCPRIVATE_BLOB, @hKeyHandle, _          @Blob(1), cbInput, 0 )          If dwStatus <> STATUS_SUCCESS Then lError = 70 : Goto ErrorTrap          ' Get Output length in pcbResult          dwStatus = BCryptSignHash( hKeyhandle, null, Strptr(sInputFile), Len(sInputFile), null, _          0, @pcbResult, 0)          If dwStatus <> STATUS_SUCCESS Then lError = 80 : Goto ErrorTrap          Redim pbOutput( 1 To pcbResult) As Byte          cbOutput = pcbResult          dwStatus = BcryptSignhash( hKeyhandle, null, Strptr(sInputFile), Len(sInputFile), _          @pbOutput(1), cbOutput, @pcbResult, 0)          If dwStatus <> STATUS_SUCCESS Then lError = 90 : Goto ErrorTrap          t = Timer - t        Else          pwszName = AfxIFileOpenDialog(hwnd, Sig_File)          If pwszName Then            sInfile = *pwszName            CoTaskMemFree(pwszName)            t = Timer            f = Freefile            Open sInFile For Binary As #f            sSigFile = String(Lof(f), 0)            Get #f, , sSigFile            Close #f            dwStatus = BCryptImportKeyPair( hECDSAHandle, Null, BCRYPT_ECCPUBLIC_BLOB, @hKeyHandle, @Blob(1), cbInput, 0 )            If dwStatus <> STATUS_SUCCESS Then lError = 100 : Goto ErrorTrap            ' Get Output length in pcbResult            dwStatus = BCryptVerifySignature( hKeyhandle, 0, Strptr(sInputFile), Len(sInputFile),_            Strptr(sSigFile), Len(sSigFile), 0)            t = Timer - t            If dwStatus = STATUS_SUCCESS Then              TDWrapper Hwnd, "Signature verification", AfxGetFileNameX(sInFile) + " has been verified." + _              CrLf + CrLf + "Time taken: " + Format(t*1000, "0.0") + "ms", TD_INFORMATION_ICON            Elseif dwStatus = STATUS_INVALID_SIGNATURE Then              TDWrapper Hwnd, "Signature verification", AfxGetFileNameX(sInFile) + " was Not verified." + _              CrLf + CrLf + "Time taken: " + Format(t*1000, "0.0") + "ms", TD_WARNING_ICON            Else              lError = 110 : Goto ErrorTrap            End If          Else            Exit Function          End If        End If                If lChoice <> Ver Then          If pFileSys.Fileexists(sOutFile) Then Kill sOutfile          f = Freefile          Open sOutFile For Binary As #f          Put #f, , pbOutput()          Close #f          TDWrapper Hwnd, "File creation", AfxGetFileNameX(sOutFile) + " has been created." + _          CrLf + CrLf + "Time taken: " + Format(t*1000, "0.0") + "ms", TD_INFORMATION_ICON        End If                Goto TidyUp                ErrorTrap:                TDWrapper Hwnd, "Error", "Error at Position " + Str(lError) + " " + Hex(dwStatus), TD_ERROR_ICON                TidyUp:        If hKeyHandle <> 0 Then BCryptDestroyKey hKeyHandle              Case HashFile        ' Get encrypted message        pwszName = AfxIFileOpenDialog(hwnd, All_Files2)        If pwszName Then          sInfile = *pwszName          CoTaskMemFree(pwszName)          t = Timer          sHash = GetFileHashEx( sInFile, False )          t = Timer - t          f = Freefile          sHashFile = AfxGetFilenameX( sInFile ) + "_Hash.dat"          Open  sHashFile For Binary As #f          Put #f, , sHash          Close #f          TDWrapper Hwnd, "Hash file", sHashFile + " has been created." + _          CrLf + CrLf + "Time taken: " + Format(t*1000, "0.0") + "ms", TD_INFORMATION_ICON        Else          Exit Function        End If              Case HashCompare        ' Get encrypted message        pwszName = AfxIFileOpenDialog(hwnd, All_Files2)        If pwszName Then          sInfile = *pwszName          EncMainMessage = AfxGetFileNameX(sInFile)          CoTaskMemFree(pwszName)          sHash = GetFileHashEx( sInFile, False )          pwszName = AfxIFileOpenDialog(hwnd, Hash_File)          If pwszName Then            sInfile = *pwszName            CoTaskMemFree(pwszName)            f = Freefile            Open sInfile For Binary As #f            Dim As String sGetHash = String(Lof(f),0)            Get #f, , sGetHash            Close #f            If sHash = sGetHash Then              TDWrapper Hwnd, "Hash comparison", "Hash of " + EncMainMessage + " And given hash match.",_              TD_INFORMATION_ICON            Else              TDWrapper Hwnd, "Hash comparison", "Hash of " + EncMainMessage + " And given hash Do Not match.",_              TD_WARNING_ICON            End If          Else            Exit Function          End If        Else          Exit Function        End If              End Select          Case ID_DR      Dim nClickedButton As Long      TaskDialog( hWnd, GetModuleHandle(NULL), "AES-RSA-ECDSA", "Written in FreeBASIC With José Roca's WinFBX", "by deltarho[1859]", 0, "#102", @nClickedButton)        End Select       Case WM_DESTROY    ' Clean up    If hRSAHandle <> 0 Then BCryptCloseAlgorithmProvider(hRSAHandle, 0)    If hECDSAHandle <> 0 Then BCryptCloseAlgorithmProvider(hECDSAHandle, 0)    PostQuitMessage(0)    Exit Function      Case WM_SYSCOMMAND    If Loword(wParam) = SC_CLOSE Then ' Close message      Dim As Long x, y, f      Dim rc As RECT      GetWindowRect( hWnd, @rc )      ' If Window has moved Then save current position      If xWindow <> rc.Left Orelse yWindow <> rc.top Then        If pFileSys.Fileexists("Position.dat") Then Kill "Position.dat"        f = Freefile        Open "Position.dat" For Binary As #f        Put #f, , rc.Left        Put #f, , rc.top        Close #f      End If    End If      End Select    ' // Default processing of Windows messages  Function = DefWindowProcW(hWnd, uMsg, wParam, lParam)  End Function' Display the File Open Dialog' The returned Pointer must be freed With CoTaskMemFree' Adapted by deltarho[1859]Function AfxIFileOpenDialog ( hwndOwner As HWND, DisplayType As Long, sigdnName As SIGDN = SIGDN_FILESYSPATH) As Wstring Ptr    ' // Create an instance of the FileOpenDialog interface  Dim hr As Long  Dim pofd As IFileOpenDialog Ptr  hr = CoCreateInstance(@CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, @IID_IFileOpenDialog, @pofd)  If pofd = NULL Then Return NULL  Dim rgFileTypes As COMDLG_FILTERSPEC    Select Case DisplayType      case DecAES    rgFileTypes.pszName = @Wstr("Decryption AES")    rgFileTypes.pszSpec = @Wstr("*.aes")    pofd->lpVtbl->SetFileTypes(pofd, 1, @rgFileTypes)    hr = pofd->lpVtbl->SetTitle(pofd, "Select encrypted file")    Case Enc    rgFileTypes.pszName = @Wstr("Encryption")    rgFileTypes.pszSpec = @Wstr("*RSAPublicKey*.dat")    pofd->lpVtbl->SetFileTypes(pofd, 1, @rgFileTypes)    hr = pofd->lpVtbl->SetTitle(pofd, "Select encrypted task file")      Case Dec    rgFileTypes.pszName = @Wstr("Decryption RSA")    rgFileTypes.pszSpec = @Wstr("*RSAPrivateKey*.dat")    pofd->lpVtbl->SetFileTypes(pofd, 1, @rgFileTypes)    hr = pofd->lpVtbl->SetTitle(pofd, "Select RSA decryption task file")      Case Sig    rgFileTypes.pszName = @Wstr("Signing")    rgFileTypes.pszSpec = @Wstr("*ECDSAPrivateKey*.dat")    pofd->lpVtbl->SetFileTypes(pofd, 1, @rgFileTypes)    hr = pofd->lpVtbl->SetTitle(pofd, "Select signing task file")      Case Ver    rgFileTypes.pszName = @Wstr("Verifying")    rgFileTypes.pszSpec = @Wstr("*ECDSAPublicKey*.dat")    pofd->lpVtbl->SetFileTypes(pofd, 1, @rgFileTypes)    hr = pofd->lpVtbl->SetTitle(pofd, "Select verifying task file")          Case Enc_File    rgFileTypes.pszName = @Wstr("Encrypted file")    rgFileTypes.pszSpec = @Wstr("*.enc")    pofd->lpVtbl->SetFileTypes(pofd, 1, @rgFileTypes)    hr = pofd->lpVtbl->SetTitle(pofd, "Select an encrypted key/password file")      Case Sig_File    rgFileTypes.pszName = @Wstr("Signed file")    rgFileTypes.pszSpec = @Wstr("*.sig")    pofd->lpVtbl->SetFileTypes(pofd, 1, @rgFileTypes)    hr = pofd->lpVtbl->SetTitle(pofd, "Select a signed hash file")      Case Hash_File    rgFileTypes.pszName = @Wstr("Hash files")    rgFileTypes.pszSpec = @Wstr("*Hash.dat")    pofd->lpVtbl->SetFileTypes(pofd, 1, @rgFileTypes)    hr = pofd->lpVtbl->SetTitle(pofd, "Select a hash file")      Case All_Files1    rgFileTypes.pszName = @Wstr("All files")    rgFileTypes.pszSpec = @Wstr("*.*")    pofd->lpVtbl->SetFileTypes(pofd, 1, @rgFileTypes)    hr = pofd->lpVtbl->SetTitle(pofd, "Select a key/password")      Case All_Files2    rgFileTypes.pszName = @Wstr("All files")    rgFileTypes.pszSpec = @Wstr("*.*")    pofd->lpVtbl->SetFileTypes(pofd, 1, @rgFileTypes)    hr = pofd->lpVtbl->SetTitle(pofd, "Select a message")        End Select     ' // Display the dialog  hr = pofd->lpVtbl->Show(pofd, hwndOwner)    ' // Set the default folder  Dim pFolder As IShellItem Ptr  SHCreateItemFromParsingName (Curdir, NULL, @IID_IShellItem, @pFolder)  If pFolder Then    pofd->lpVtbl->SetDefaultFolder(pofd, pFolder)    pFolder->lpVtbl->Release(pFolder)  End If    ' // Get the result  Dim pItem As IShellItem Ptr  Dim pwszName As Wstring Ptr  If SUCCEEDED(hr) Then    hr = pofd->lpVtbl->GetResult(pofd, @pItem)    If SUCCEEDED(hr) Then      hr = pItem->lpVtbl->GetDisplayName(pItem, sigdnName, @pwszName)      Function = pwszName    End If  End If    ' // Cleanup  If pItem Then pItem->lpVtbl->Release(pItem)  If pofd Then pofd->lpVtbl->Release(pofd)  End Function' Check If a String Is wholly hexadecimal Or Not, returns True If soFunction IsHex(s As String) As Long  Dim i As Long    For i = 0 To Len(s) - 1    Select Case s[i]    Case 48 To 57, 65 To 70, 97 To 102    Case Else      Return False    End Select  Next i  Return true  End Function' General Hash Function. See https://freebasic.net/forum/viewtopic.php?f=7&t=25320 For full detailsFunction Hash( hashalg As lpcwstr, stext As String, index As Long, mode As Long, final As Long, _  pbsecret As String = Chr(0)) As String    Static phalg(1 To 8) As Byte Ptr  Static phhash(1 To 8) As Byte Ptr  Dim sbinary As String  Dim shex As String  Dim nlength As Long    ' Initialize section    If phhash(index) = 0 Then ' will be the Case On, And perhaps only, first pass    If pbsecret = Chr(0) Then ' Not hmac      BcryptOpenAlgorithmprovider @phalg(index), hashalg, 0, 0 ' we want phalg(index)      BcryptCreatehash phalg(index), @phhash(index), null, 0, 0, 0, 0 ' we want phhash(index)    Else ' Is hmac      ' We want phalg(index)      BcryptOpenAlgorithmprovider @phalg(index), hashalg, 0, bcrypt_alg_handle_hmac_flag' we want phalg(index)      If Right( pbsecret, 1 ) <> Chr(0) Then ' ascii Not forced        ' are we going To use pbsecret As ascii Or Binary?        If ( Len( pbsecret ) Mod 2 = False ) And IsHex( pbsecret ) = true Then          nlength = Len(pbsecret)\2          sbinary = Space( nlength )          CryptStringToBinarya Strptr(pbsecret), Len(pbsecret), crypt_string_hexraw, Strptr(sbinary), @nlength, 0, 0          pbsecret = sbinary        End If      Else        pbsecret = Left( pbsecret, Len(pbsecret) - 1)      End If      ' We want phhash(index)      BcryptCreatehash phalg(index), @phhash(index), null, 0, Strptr( pbsecret ), Len( pbsecret ), 0    End If  End If    ' update section    BcryptHashData( phhash(index), Strptr( stext), Len( stext ), 0 )    ' finalization section    If final = true Then ' finalize hash    Dim As Ulong lhashlength    Dim As Ulong lresult    Dim sbinhash As String        BcryptGetProperty phalg(index), bcrypt_hash_length, Cast( Puchar, @lhashlength ), 4, Varptr(lresult), 0    sbinhash = String( lhashlength, 0 )    BcryptFinishHash phhash(index), Strptr( sbinhash ), lhashlength, 0    BcryptDestroyHash phhash(index)     BcryptCloseAlgorithmprovider phalg(index), 0    phhash(index) = 0 ' ensures a New hash Is created On another pass of hash() With This index    If mode = 0 Then      Return sbinhash    Else      nlength = Len(sbinhash)*2 + 1 ' + 1 To accomodate a null terminator      shex = Space( nlength )      CryptBinaryToStringa Strptr(sbinhash), Len(sbinhash), crypt_string_hexraw + crypt_string_nocrlf, _      Strptr(shex), @nlength ' at msdn nlength 'Out' Is Len(sbinhash) * 2, so      Return Ucase( Left( shex, nlength ) )    End If  End If  End Function' Hash a file - specific For AES-RSA-ECDSAFunction GetFileHashEx( sFile As String, Flag As Long ) As String  ' If Flag Is 0 Then Binary Is returned Else hexadecimal  Dim As String * 262144 sBuffer  Dim As String sHash  Dim As Ulong f  Dim As Uinteger BytesRead    ' Prepend message With blocksize of zeros - security measure  ' SHA512 Is used And reduced according To HashLen  Hash Wstr("SHA512"), String(128,0), 1, Flag, False  f = Freefile  Open sFile For Binary As #f  While Not Eof(f)    Get #f, , sBuffer, , BytesRead    Hash Wstr("SHA512"), Left( sBuffer, BytesRead ), 1, Flag, False  Wend  Close #f  ' The hash has Not been finalized so employ hash() again With an empty String.  sHash = Hash( "", "", 1, Flag, true )  Return Left(sHash, Len(sHash)*HashLen\512)   End Function' Digest of TaskDialogSub TDWrapper( hWndParent As HWND, pszMainInstruction As PCWSTR, pszContent As PCWSTR, pszIcon As PCWSTR )  Dim nClickedButton As Long  TaskDialog( hWndParent, NULL, "AES-RSA-ECDSA", pszMainInstruction, pszContent, TDCBF_OK_BUTTON, pszIcon, @nClickedButton)End SubFunction AES( AESstrength As Long, sInFile As String, sPassword As String, lStretch As Long ) As Long' If sInFile has an aes extension Then decrypt Else encryptDim As BCRYPT_ALG_HANDLE Ptr hRand, hAESAlgDim As BCRYPT_KEY_HANDLE Ptr hKeyDim OutText() As ByteDim As Long i, Final, lFileLen, FinalSection, SectionCount, IsInputEncrypted, LenInText, LenOutText, nLengthDim As Ulong ntStatus, lError, dwResult, phHashAES, hIn, hOutDim sIV As String * 16Dim sSalt As String * 32Dim As String sBinary, sOutFile, sDummy, sKeyDim As String*32 sKeyVerify, sSavedKeyVerifyDim As String * 262144 pbdataDim As Uinteger nbloaded   AESstrength /= 8  lStretch += 2   ' File Input/Output section  If pFileSys.FileExists( sInfile ) = False Then ' Unable To find file    Function = -1    Goto TidyUp  End If    hIn = Freefile  Open sInfile For Binary As #hIn    lFilelen = Lof( hIn )     If lFileLen = 0 Then ' Zer0 Byte file    Close #hIn    Function = -5    Goto TidyUp  End If   If Lcase( Right( sInFile, 4 ) ) <> ".aes" Then    sOutFile = sInFile & ".aes"    ' eg f:\folder\myapp.Exe ==> f:\folder\myapp.Exe.aes    IsInputEncrypted = False  Else    sOutFile = Left\$( sInFile, Len( sInFile ) - 4 )    ' eg f:\folder\myapp.Exe.aes ==> f:\folder\myapp.Exe    IsInputEncrypted = True  End If    ' Read Or generate header items    If IsInputEncrypted = True Then    Get #hIn,, sIV    Get #hIn,, sSalt    Get #hIn,, sSavedKeyVerify  Else    ntStatus = BCryptOpenAlgorithmProvider(@hRand, BCRYPT_RNG_ALGORITHM, "", 0) ' Prepare For Random number generation    If ntStatus <> STATUS_SUCCESS Then lError = 120 : Goto ErrorTrap    ntStatus = BCryptGenRandom(hRand, Strptr(sIV), BlockSize, 0)    If ntStatus <> STATUS_SUCCESS Then lError = 130 : Goto ErrorTrap    ntStatus = BCryptGenRandom(hRand, Strptr(sSalt), 32, 0)    If ntStatus <> STATUS_SUCCESS Then lError = 140 : Goto ErrorTrap    ntStatus = BCryptCloseAlgorithmProvider(hRand, 0)    If ntStatus <> STATUS_SUCCESS Then lError = 150 : Goto ErrorTrap  End If   ' Are we going To use sPassword As ascii Or Binary?   If ( sPassword <> "" ) And ( Len( sPassword ) Mod 2 = 0 ) And ( Len( sPassword ) >= 2 * AESStrength ) And IsHex( sPassword ) <> 0 Then    ' Treat As a Binary String    nLength = Len(sPassword)\2    sBinary = Space\$( nlength )    CryptStringToBinarya Strptr(sPassword), Len(sPassword), crypt_string_hexraw, Strptr(sBinary), @nLength, 0, 0    sPassword = sBinary  End If   ' Use SHA256 And stretch sPassword   ' Algorithm employed x0 = 0 : xi = Hash( xi-1 + sPassword + sSalt ) For i = 1 To 2^lStretch  ' From Cryptography Engineering: ISBN 978-0-470-47424-2   ' Calculate 2^lStretch - 1 hashes     For i = 1 To 2^lStretch - 1    sDummy = sKey + sPassword + sSalt    sKey = Hash( Wstr("SHA256"), sDummy, 1, False, False )  Next   ' Calculate password verification Data    sDummy = String\$(64,0) + sKey + sPassword + sSalt  sKeyVerify = Hash( Wstr("SHA256"), sDummy, 1, False, True )    If IsTrue( IsInputEncrypted ) Then    If sSavedKeyVerify <> sKeyVerify Then ' Password failed      Function = -6      Goto TidyUp    End If  End If   ' Now calculate final iterate    sDummy = sKey + sPassword + sSalt  sKey = Hash( Wstr("SHA256"), sDummy, 1, False, True )   ' Set up Output file    If IsTrue( pFileSys.Fileexists(sOutFile) ) Then    Kill sOutFile  End If  hOut = Freefile  Open sOutFile For Binary As hOut  If Err Then    Function = Err    Goto TidyUp  End If   If IsFalse( IsInputEncrypted ) Then ' Save Header items    Put #hOut, , sIV    Put #hOut, , sSalt    Put #hOut, , sKeyVerify  End If   ' AES section   ntStatus = BCryptOpenAlgorithmProvider( @hAESAlg, BCRYPT_AES_ALGORITHM, "", 0 ) ' We want hAESAlg  If ntStatus <> STATUS_SUCCESS Then lError = 160 : Goto ErrorTrap  ntStatus = BCryptGenerateSymmetricKey( hAESAlg, @hKey, 0, 0, Strptr(sKey), AESstrength, 0 ) ' We want hKey  If ntStatus <> STATUS_SUCCESS Then lError = 170 : Goto ErrorTrap   ' Encryption/Decryption section   Redim OutText( 1 To BufferSize ) As Byte  LenOutText = BufferSize  LenInText = BufferSize    If IsTrue( IsInputEncrypted ) Then    lFileLen -= 80 ' To account For sIV, sSalt And sSavedKeyVerify  End If  FinalSection = lFileLen\BufferSize  If lFileLen > FinalSection*BufferSize Then FinalSection += 1   ' Encryption/Decryption Loop    Do    SectionCount += 1    Get #hIn,, pbdata, , nbLoaded    If SectionCount = FinalSection Then      Final = BCRYPT_BLOCK_PADDING    End If     If IsFalse( IsInputEncrypted ) Then ' Encrypt      If Final = BCRYPT_BLOCK_PADDING Then        ntStatus = BCryptEnCrypt( hKey, Strptr(pbData), nbLoaded, 0, Cast( Byte Ptr, @sIV ), BlockSize, 0, 0, @LenOutText, Final )  'We want LenOutText        If ntStatus <> 0 Then lError = 180 : Goto ErrorTrap                ' If we are On blocksize boundary we will need BufferSize + BlockSize otherwise GPF        If IsFalse( LenOutText Mod BlockSize ) Then Redim OutText( 1 To BufferSize + BlockSize) As Byte        LenInText = nbLoaded      End If       ' LenOutText = BufferSize unless revised above      ntStatus = BCryptEnCrypt( hKey, Strptr(pbData), LenInText, 0, Cast( Byte Ptr, @sIV ), BlockSize, @OutText(1), LenOutText, @dwResult, Final )      If ntStatus <> 0 Then lError = 190 : Goto ErrorTrap     Else ' Decrypt      If Final = BCRYPT_BLOCK_PADDING Then        ntStatus = BCryptDecrypt( hKey, Strptr(pbData), nbLoaded, 0, Cast( Byte Ptr, @sIV ), BlockSize, 0, 0, @LenOutText, Final )  ' We want LenOutText        If ntStatus <> 0 Then lError = 200 : Goto ErrorTrap        If IsFalse( LenOutText Mod BlockSize ) Then Redim OutText( 1 To BufferSize + BlockSize) As Byte        LenInText = nbLoaded      End If       ntStatus = BCryptDecrypt( hKey, Strptr(pbData), LenInText, 0, Cast( Byte Ptr, @sIV ), BlockSize, @OutText(1), LenOutText, @dwResult, Final )      If ntStatus <> 0 Then lError = 210 : Goto ErrorTrap    End If     ' If Output file Is an exact multiple of bufferSize    ' Then dwResult will be zero And we have nothing To dump     If dwResult > 0 Then      If IsTrue( Final ) Then        Redim Preserve OutText(1 To dwResult) As Byte      End If      Put #hOut, , OutText()    End If   Loop Until Final  Goto TidyUpErrorTrap:MessageBox ( 0, "Error at Position " + Str(lError) + " " + Hex(ntStatus), "EncDec", MB_OK )  TidyUp:  If hAESAlg <> 0 Then BCryptCloseAlgorithmProvider( hAESAlg, 0 )  If hKey <> 0 Then BCryptDestroyKey( hKey )  Close hIn  Close hOut  End Function`

You are more than welcome to edit the last two bas files for your own needs but if you do then the following rc file will need to be edited to remove 'yours truly' before handy the exe to anyone else. If you compile the above as is then stay with the rc file as is. I will never publish cryptographic code for financial gain but I will also not publish the same anonymously. <smile>

RSA-ECDSA.rc

Code: Select all

`#define IDR_VERSION 1100 icon padlock.ico101 bitmap DRmed.bmp102 icon FB_Icon.icoIDR_VERSION VERSIONINFOFILEVERSION 1,0,0,0000FILEOS VOS__WINDOWS32FILETYPE VFT_APPBEGIN  BLOCK "StringFileInfo"  BEGIN    BLOCK "080904E4"    BEGIN      VALUE "FileDescription", "AES, RSA and ECDSA\0"      VALUE "ProductName", "AES-RSA-ECDSA\0"      VALUE "LegalCopyright", " \251 2018 David Roberts\0"    END  END  BLOCK "VarFileInfo"  BEGIN    VALUE "Translation", 0x0809, 0x04E4  ENDEND1 24 "Theme.xml"`

Theme.xml

Code: Select all

`<?xml version="1.0" encoding="UTF-8" standalone="yes"?><assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">    <assemblyIdentity        version="1.0.0.1"        processorArchitecture="*"        name="MyAppName.exe"        type="win32"    />    <description>Optional MyDescription for MyAppName.exe</description>        <asmv3:application>        <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">        <dpiAware>true</dpiAware>        </asmv3:windowsSettings>    </asmv3:application>    <!-- Compatibility section for Program Compatibility Assistant (PCA) -->    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">        <application>            <!-- Windows Vista -->            <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>            <!-- Windows 7 -->            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>            <!-- Windows 8 -->            <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>            <!-- Windows 8.1 -->            <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>            <!-- Windows 10 -->            <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>        </application>    </compatibility>    <!-- Trustinfo section for User Account Control (UAC) -->    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">        <security>            <requestedPrivileges>                <!-- level   = "asInvoker"            -->                <!-- level   = "highestAvailable"     -->                <!-- level   = "requireAdministrator" -->                <requestedExecutionLevel                    level    = "asInvoker"                    uiAccess = "false"                />            </requestedPrivileges>        </security>    </trustInfo>    <!-- Dependency section -->    <dependency>        <dependentAssembly>            <assemblyIdentity                type="win32"                name="Microsoft.Windows.Common-Controls"                version="6.0.0.0"                processorArchitecture="*"                publicKeyToken="6595b64144ccf1df"                language="*"            />        </dependentAssembly>    </dependency></assembly>`

A quick test run

After you have created your keys create a key/password file. Use your name for a password, for example, and call the file Key.dat

Run RSA-ECDSA and chose 'Encrypt a key'. You should get Key.dat.enc created. Now delete Key.dat and then chose 'Decrypt a .enc file'. You should get your Key.dat back in all its glory.

Now chose 'Hash a file'. Hash RSA-ECDSA.exe, for example. You should get RSA-ECDSA.exe_Hash.dat created. Normally the file to hash would be your AES, or whatever, encrypted message.

Now chose 'Sign a hash'. You should get 'RSA-ECDSA.exe_Hash.dat.sig created.

Now chose 'verify a .sig file'. Work your way through that and you should get a successful verification.

Now chose 'Verify hashes' and you get a hash match.

Be honest, that was fun wasn't it? <laugh>
Last edited by deltarho[1859] on Mar 05, 2018 13:01, edited 2 times in total.
srvaldez
Posts: 1816
Joined: Sep 25, 2005 21:54

### Re: RSA ECDSA

thank you deltarho[1859]
that's a very good explanation of cryptography, I was able to compile and run your code with no problems, though I am a bit confused on the password generation, need to re-read your explanation :-)
deltarho[1859]
Posts: 1658
Joined: Jan 02, 2017 0:34
Location: UK

### Re: RSA ECDSA

@srvaldez

Thanks for the feedback.

As the protocol above stands both the sender and user will need to use the same symmetric encryption/decryption application. The next version of RSA-ECDSA will have that built in. I have some AES PowerBASIC code which I can port in. That could use a key in a file but I will be looking at other ways of getting our passwords/keys into RSA-ECDSA.

RSA-ECDSA is not of 'commercial quality' but was written primarily as an exercise in using José Roca's WinFBX which had been on my to do list for too long. If the cryptography aspect was removed from RSA-ECDSA then we would have a template for writing other GUI applications; which is what I will do.
deltarho[1859]
Posts: 1658
Joined: Jan 02, 2017 0:34
Location: UK

### Re: RSA ECDSA

One way of using RSA-ECDSA more securely is to create a password like this: '32a?v@6o0?@\$Grm+H'2*Daw/*vAE-xb' and put that into a password manager.

That would be our symmetric key for AES, or whatever.

That password has an entropy of over 205 bits so is, at the present time, uncrackable.

So, provided Alice is diligent she will not have a plaintext copy of our symmetric key in the 'open' for very long, we will have it in our password manager and it never enters the Internet in plaintext form.

I use KeePass Password Safe and have over 50 website passwords, all different, all random and as long as the respective websites will allow me.
srvaldez
Posts: 1816
Joined: Sep 25, 2005 21:54

### Re: RSA ECDSA

thank you deltarho[1859] for the link :-)
deltarho[1859]
Posts: 1658
Joined: Jan 02, 2017 0:34
Location: UK

### Re: RSA ECDSA

I forgot to mention that the random password above was generated by KeePass. Had I asked for a 64 random character hex string I would get something like this 'D4CF2A99544ADFDF70189AE87E53B14CAFFCC072E445A6331CB85F4B647A0060'. My AES applications would convert that into a 256 bit binary key.

So, what do I use to open my password manager? I have a separate application which requires three inputs and it generates a 64 character password which uses both low and high ansi characters. It has an entropy of 495.45 bits. The three inputs? In my head and one of them is a pin number which hashes that many times, times 1000. It takes 348ms to generate those 64 characters. Eat your heart out security services - you won't scratch the paint on that - ever. <smile> Paranoid? Guilty!
deltarho[1859]
Posts: 1658
Joined: Jan 02, 2017 0:34
Location: UK

### Re: RSA ECDSA

AES-RSA-ECDSA replaces RSA-ECDSA in the second post and the rc file has been changed.

AES256 has been added: See AES file encryption for details. Ignore the timing - on this occasion 100MB.txt was coming out of the filecache. After choosing a message to encrypt/decrypt we are presented with an input box requesting a password/passkey.

The password may be 'stretched' according to the above link and this is achieved by appending the password with a stretch value eg MyPassword16. Two numeric characters are required otherwise the stretch value will be taken as zero. So, for less than 10 we would use, say, 08. Whatever we choose the stretch will limited to 24 - there is no escape once the encryption/decryption starts. On my machine a value of 24 will stretch for about 20 seconds. The recommended stretch is around 250 milliseconds so you will need to experiment bearing in mind that our recipient's machine maybe slower or faster than ours. I do not use passwords. I use binary keys with at least 64 random hex characters kept in a password manager.

This time I am attaching a zip of AES-RSA-ECDSA.exe (32 bit). The exe is surprisingly small coming in at only 166KB.

AES-RSA-ECDSA
deltarho[1859]
Posts: 1658
Joined: Jan 02, 2017 0:34
Location: UK

### Re: RSA ECDSA

Bug fix in AES-RSA-ECDSA.bas . It has nothing to do with the encryption/decryption but how errors are handled. coderJeff's error handling is better than mine. With his code this bug would not have crept in. I will be using an adaptation of his error handling in future. <smile>