Results 1 to 20 of 20

Thread: VB6 TLSCrypto

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2012
    Posts
    1,477

    VB6 TLSCrypto

    SSLClient and SSLServer are companion programs designed to demonstrate Transport Layer Security (TLS) Version 1.0. At the present time, they only support 2 cipher suites:
    TLS_RSA_WITH_RC4_128_MD5 (0x00,0x04)
    TLS_RSA_WITH_RC4_128_SHA (0x00,0x05)
    These 2 suites are supported by virtually all modern browsers and servers, although SHA is more commonly preferred. In addition, 2048 bit asymmetric keys are utilized for the session handshake, since these are strongly recommended by the Internet Engineering Task Force (IETF) since the end of 2013.

    In order to support TLS without the use of third party controls or libraries, Microsoft's RSA/SChannel (schannel.dll) is utilized. This library is shipped with all modern Windows Operating Systems. As well, my own cSocket2 Class and accompanying Module (mWinsock2) are utilized. These 2 modules will support IPv6 when it becomes universally available. Although the Cryptography routines will work on most Windows Operating Systems, cSocket2 will only work on systems that support dual stack (IPv4/IPv6). This more or less restricts it to Windows Vista or better.

    Originally, I planned on developing only the Client program without Certificates. But the severe lack of detailed information on TLS using SChannel made troubleshooting difficult if not impossible, and I could not connect with remote servers. So I decided to develop a Server program as well. Several months later, I had 2 programs that would communicate with each other, but I still could not communicate with external servers, and online assistance was virtually non-existent. So I then decided to test the server program using my local browser. That meant providing support for Certificates and a whole new level of complexity. But at least the browser provided a little more troubleshooting information than a remote server. This particular project has by far been the most challanging I have ever attempted. The programming itself was not all that difficult, but the lack of information, and the conflict between information that I did manage to find, made it a struggle. Troubleshooting was very difficult because Cryptographers basically strive to eliminate repeatability. Repeatability facilitates hacking.

    The included ReadMe file contains the necessary setup instructions.

    J.A. Coutts
    UPDATE 11/25/2014: MikesToolBox no longer supplies CA Record. See later post for details.
    Attached Files Attached Files
    Last edited by couttsj; Nov 25th, 2014 at 07:30 PM.

  2. #2

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2012
    Posts
    1,477

    Re: VB6 TLSCrypto

    TLSCrypto has been updated to use NewSocket instead of cSocket2. This has resulted in a 15% improvement in speed.

    J.A. Coutts

  3. #3
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: VB6 TLSCrypto

    Quote Originally Posted by couttsj View Post
    TLSCrypto has been updated to use NewSocket instead of cSocket2. This has resulted in a 15% improvement in speed.

    J.A. Coutts
    C
    I got Runtime 5 error (invalid procedure call) on server side after clicking 'CONNECT' (https://localhost).

    Code:
    Public Function ChooseCipher(sCiphers As String) As String
        Dim N%
        Alg_Hash = 0
        N% = 1
        Do Until Alg_Hash <> 0
            lCipher = CLng(Asc(Mid$(sCiphers, N%, 1))) * 256 + CLng(Asc(Mid$(sCiphers, N% + 1, 1)))  '--->error
            Select Case lCipher
                Case 4
                    Alg_Hash = CALG_MD5
                Case 5
                    Alg_Hash = CALG_SHA1
                Case Else
                    Alg_Hash = 0
            End Select
            N% = N% + 2
        Loop
        ChooseCipher = Mid$(sCiphers, N% - 2, 1) & Mid$(sCiphers, N% - 1, 1)
    End Function

  4. #4

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2012
    Posts
    1,477

    Re: VB6 TLSCrypto

    What is the value of sCiphers? You can use the debug line:
    Call DebugPrintString("Ciphers:", sCiphers)
    It should say "00 04 00 05" and is extracted from the Client Hello. If it doesn't, then trace back to find out why.

    J.A. Coutts

  5. #5
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: VB6 TLSCrypto

    Quote Originally Posted by couttsj View Post
    What is the value of sCiphers? You can use the debug line:
    Call DebugPrintString("Ciphers:", sCiphers)
    It should say "00 04 00 05" and is extracted from the Client Hello. If it doesn't, then trace back to find out why.

    J.A. Coutts
    Ciphers::
    00 00 0E 00 0C 00 00 09 6C 6F 63 61 6C 68 6F 73
    74

    In clsCrypto.cls, I saw many StrConv, this is not good for Unicode. Please test your program using locale=2052 (on Control Panel,change your language setting to Chinese (PRC) to see what happen).

    I changed my locale=1033 (English -USA), your server program just immediately crash once starting Client,both on VBIDE and exe.
    Last edited by Jonney; Apr 4th, 2014 at 03:42 AM.

  6. #6

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2012
    Posts
    1,477

    Re: VB6 TLSCrypto

    Thanks for the hint Jonney. I have to admit that I know next to nothing about Non-ANSI character sets. However, I am unable to duplicate the error you experienced when I change the language setting to Chinese(PRC). It makes it through that part, but the Client is unable to verify the signature on the server certificate. At least it gives me something to work on.

    J.A. Coutts

  7. #7

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2012
    Posts
    1,477

    Re: VB6 TLSCrypto

    This is what I have learned so far.
    Client Hello:
    01 00 00 4A 03 01 53 3D{F6 00 A2 69 32 4F 24 AC
    0C 01 26 5D B2 0D 4B F3 33 56 F9 E7 5C 03 A0 2C
    D0 05 2D C2 7E DF}00 00 04 00 04 00 05 01 00 00
    1D 00 00 00 19 00 17 00 00 14 77 77 77 2E 6D 69
    6B 65 73 74 6F 6F 6C 62 6F 78 2E 6F 72 67
    Reading this directly from memory shows agreement:
    strToSend:
    01 00 00 00 00 00 4A 00 03 00 01 00 53 00 3D{00
    F6 00 00 00 A2 00 69 00 32 00 4F 00 24 00 AC 00
    0C 00 01 00 26 00 5D 00 B2 00 0D 00 4B 00 F3 00
    33 00 56 00 F9 00 E7 00 5C 00 03 00 A0 00 2C 00
    D0 00 05 00 2D 00 C2 00 7E 00 DF}00 00 00 00 00
    04 00 00 00 04 00 00 00 05 00 01 00 00 00 00 00
    1D 00 00 00 00 00 00 00 19 00 00 00 17 00 00 00
    00 00 14 00 77 00 77 00 77 00 2E 00 6D 00 69 00
    6B 00 65 00 73 00 74 00 6F 00 6F 00 6C 00 62 00
    6F 00 78 00 2E 00 6F 00 72 00 67 00
    However, when StrConv converts it to an array, it gets:
    arrData:
    01 00 00 4A 03 01 53 3D{3F 00 A1 E9 69 32 4F 24
    3F 0C 01 26 5D 32 0D 4B A8 AE 33 56 A8 B4 3F 5C
    03 3F 2C 44 05 2D 3F 7E 3F}00 00 04 00 04 00 05
    01 00 00 1D 00 00 00 19 00 17 00 00 14 77 77 77
    2E 6D 69 6B 65 73 74 6F 6F 6C 62 6F 78 2E 6F 72
    67
    The part that is different (between angle brackets) is the random string generated by the system call CryptGenRandom. Now all I have to do is figure out is how and why.

    J.A. Coutts

  8. #8

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2012
    Posts
    1,477

    Re: VB6 TLSCrypto

    It doesn't look like there is going to be an easy solution to this problem. If all the characters were ASCII (0x00 - 0x7F), it would be relatively simple. I could copy memory from one location to another and create a new string or byte array that would convert properly. But in cryptography, the system uses all of the ANSI characters (0x00 - 0xFF). The same is true when the system creates a random string. Most of these characters convert properly because of the 0x00 leading byte, with the exception of the following:
    0x80 U+20AC
    0x82 U+201A
    0x83 U+0192
    0x84 U+201E
    0x85 U+2026
    0x86 U+2020
    0x87 U+2021
    0x88 U+02C6
    0x89 U+2030
    0x8A U+0160
    0x8B U+2039
    0x8C U+0152
    0x8E U+017D
    0x91 U+2018
    0x92 U+2019
    0x93 U+201C
    0x94 U+201D
    0x95 U+2022
    0x96 U+2013
    0x97 U+2014
    0x98 U+02DC
    0x99 U+2122
    0x9A U+0161
    0x9B U+203A
    0x9C U+0153
    0x9E U+017E
    0x9F U+0178
    In the previous example that I provided, it was just a matter of chance that none of these characters were used. I don't know how the system knows which ones need converted, but it doesn't seem to do a very good job. For example, the first 2 characters that it changed (F6 00) are not even part of the Random String. They are the last 2 characters of the Unix time. The major problem is that it adds 3 additional bytes when using the Chinese(PRC)language setting.

    I tried creating the Random String as a byte array, but the Unicode characters listed above caused a problem in both the Chinese(PRC) and English(United States) settings. This is going to take more research.

    J.A. Coutts

  9. #9
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,253

    Re: VB6 TLSCrypto

    Quote Originally Posted by couttsj View Post
    I tried creating the Random String as a byte array, but the Unicode characters listed above caused a problem in both the Chinese(PRC) and English(United States) settings.
    ByteArrays is the way to go about it, if you want to avoid any locale- or Unicode/ANSI-issues.

    You will need to ensure though, that your whole queue - from the Public Method-Interface the User has access to -
    and also in your internal functions which finally call into the System-APIs... - you pass only this ByteArray-allocation
    along - if you don't allow any strings (or stringconversions) inbetween, then you will not encounter any problems.

    If you already have done so (using a Bytearray against your random-creation-stuff "all the way") -
    then you shouldn't get the errors you list above.

    Olaf

  10. #10

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2012
    Posts
    1,477

    Re: VB6 TLSCrypto

    The problem is not with the StrConv function. The problem is with the substitution that the operating system makes for the 27 ANSI characters that it converts to 2 byte Unicode. When I replace
    "arrData() = StrConv(m_strSendBuffer, vbFromUnicode)" with
    "arrData() = StrToByte(m_strSendBuffer)"
    Code:
    Private Function StrToByte(strInput As String) As Byte()
        Dim lPntr As Long
        Dim bTmp() As Byte
        Dim bArray() As Byte
        ReDim bTmp(LenB(strInput) - 1)
        ReDim bArray(Len(strInput) - 1)
        CopyMemory bTmp(0), ByVal StrPtr(strInput), LenB(strInput)
        'Examine every second byte
        For lPntr = 0 To UBound(bArray)
            If bTmp(lPntr * 2 + 1) > 0 Then
                bArray(lPntr) = Asc(Mid$(strInput, lPntr + 1, 1))
            Else
                bArray(lPntr) = bTmp(lPntr * 2)
            End If
        Next lPntr
        StrToByte = bArray
    End Function
    using the Chinese(PRC) setting, I get the following results:
    Client Hello:
    01 00 00 4A 03 01 53 3F 47 80 F6 A0 83 87 D8 EB
    52 C1 52 A7 13 18 BC 70 B0 C2 4B 19 71 5F 45 F9
    54 EA D3 59 5A 26 00 00 04 00 04 00 05 01 00 00
    1D 00 00 00 19 00 17 00 00 14 77 77 77 2E 6D 69
    6B 65 73 74 6F 6F 6C 62 6F 78 2E 6F 72 67
    strToSend:
    16 00 03 00 01 00 00 00 4E 00
    01 00 00 00 00 00 4A 00 03 00 01 00 53 00 3F 00
    47 00 AC 20 F6 00 A0 00 92 01 21 20 D8 00 EB 00
    52 00 C1 00 52 00 A7 00 13 00 18 00 BC 00 70 00
    B0 00 C2 00 4B 00 19 00 71 00 5F 00 45 00 F9 00
    54 00 EA 00 D3 00 59 00 5A 00 26 00 00 00 00 00
    04 00 00 00 04 00 00 00 05 00 01 00 00 00 00 00
    1D 00 00 00 00 00 00 00 19 00 00 00 17 00 00 00
    00 00 14 00 77 00 77 00 77 00 2E 00 6D 00 69 00
    6B 00 65 00 73 00 74 00 6F 00 6F 00 6C 00 62 00
    6F 00 78 00 2E 00 6F 00 72 00 67 00
    arrData:
    16 03 01 00 4E
    01 00 00 4A 03 01 53 3F 47 80 F6 A0 83 87 D8 EB
    52 C1 52 A7 13 18 BC 70 B0 C2 4B 19 71 5F 45 F9
    54 EA D3 59 5A 26 00 00 04 00 04 00 05 01 00 00
    1D 00 00 00 19 00 17 00 00 14 77 77 77 2E 6D 69
    6B 65 73 74 6F 6F 6C 62 6F 78 2E 6F 72 67

    The non zero leading byte records trigger the Unicode conversion using the current language setting. When these are replaced with the correct code and leading zero, the conversion takes place properly regardless of the locale in use.

    J.A. Coutts

  11. #11
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,253

    Re: VB6 TLSCrypto

    What I mean is, you don't have to convert Strings to Bytes *within* your Socket-Component.
    Just offer ByteArrays in your interface - and let the User be responsible for the proper conversions.
    (e.g. proper conversion from a chinese Unicode-String to Bytes would be achieved using
    WideCharToMultiByte with Codepage 65001 (UTF-8) - and in the opposite direction
    then per MultiByteToWideChar in roughly the same way...

    Olaf

  12. #12

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2012
    Posts
    1,477

    Re: VB6 TLSCrypto

    Quote Originally Posted by Schmidt View Post
    What I mean is, you don't have to convert Strings to Bytes *within* your Socket-Component.
    Just offer ByteArrays in your interface - and let the User be responsible for the proper conversions.
    (e.g. proper conversion from a chinese Unicode-String to Bytes would be achieved using
    WideCharToMultiByte with Codepage 65001 (UTF-8) - and in the opposite direction
    then per MultiByteToWideChar in roughly the same way...

    Olaf
    I can appreciate what you are saying Olaf, but at some point the data has to be converted to string anyway, and the problem just reappears. Early in the design stage I had considered using byte arrays, but strings are much easier to manipulate in VB6 than byte arrays. In Cryptography, packet length is extremely critical and variable length characters just don't cut it.

    J.A. Coutts

  13. #13

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2012
    Posts
    1,477

    Re: VB6 TLSCrypto

    Since incoming packets can contain the same problem bytes (0x80 +), I came up with the following:
    Code:
    Public Function ByteToStr(bArray() As Byte) As String
        Dim lPntr As Long
        Dim bTmp() As Byte
        ReDim bTmp(UBound(bArray) * 2 + 1)
        For lPntr = 0 To UBound(bArray)
            bTmp(lPntr * 2) = bArray(lPntr)
        Next lPntr
        Let ByteToStr = bTmp
    End Function
    Now that I have a way of testing it (thanks to Jonney), I will develope a Unicode version of TLSCrypto and post it later. If the performance hit is not too great, I will replace the original version with the Unicode version.

    J.A. Coutts

  14. #14
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,253

    Re: VB6 TLSCrypto

    I still don't understand why you are performing a loop...

    you don't even need a separate function to convert 16Bit-WChar content from VB-Strings to ByteArrays and vice versa.

    As soon as you have decided to transport WChars (in appropriately allocated ByteArrays)
    in their fulll (non ANSI-converted) length (as described by LenB(SomeString)),
    the compiler will perform the conversion already in this simple way directly:

    Dim BSend() As Byte, sSend As String
    sSend = "ABC"
    BSend = sSend 'non-destructive unicode-WChar-conversion into Bytes
    Debug.Print (Ubound(BSend) + 1) = LenB(sSend) 'gives True

    'now put this BSend()-ByteArray onto your socket-channel ...
    '... and at the receiving end you can simply backconvert into a Wide-String per:

    sRecv = BRecv

    That's all there is to it, when you want to transfer unicode-strings in a losless manner
    (over ByteArray-Containers)... only thing to swallow is, that you transfer now twice
    the volume of bytes (now matching LenB() and not Len() anymore) - but there's no
    way around it, in case you want to avoid UTF8-encoding for example. The UTF8-alternative
    would be more efficient (using less bytes) for most "western and european locales" -
    but would be less efficient (using more chars than UTF-16-transfers) for "eastern UniChars".

    Olaf

  15. #15

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2012
    Posts
    1,477

    Re: VB6 TLSCrypto

    Here is a good example of why I prefer to use strings, and why it is necessary to loop through and change any 2 byte characters to what they are supposed to be. When the certificate data is received from the server, I have to search through that data (sometimes well over 4000 bytes) to find the Public Key, the Signature, and the Public Key from the Certificate Authority.
    lPntr1 = InStr(sBuff, Chr$(&H30) & Chr$(&H82)) + 4
    What I discovered is that the search key was not 0x30 0x00 0x82 0x00 as one might expect, it was actually 0x30 0x00 0x1A 0x20. This would work properly when I was using StrConv and English locale, because the operating system would make the necessary conversion to both the incoming data and the search key. However, using a different locale such as Chinese, this would no longer work. When I changed the StrConv functions to StrToByte and ByteToStr, it would not work in either locale. I had bypassed the correction that the operating system had made to the 0x82 byte in the incoming data, but I had not bypassed the correction that it had made when it created the search key. What I had to do was:
    Code:
        Dim sKey As String
        Dim bTmp() As Byte
        ReDim bTmp(1)
        bTmp(0) = &H30
        bTmp(1) = &H82
        sKey = ByteToStr(bTmp)
        'This routine returns the first part of the certificate only (w/o signature)
        lPntr1 = InStr(sBuff, sKey) + 4
    The interesting part is that this conversion only takes place when the string is created. It does not take place when you manipulate the string by choosing only part of it or when concatenating strings.

    J.A. Coutts

  16. #16
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,253

    Re: VB6 TLSCrypto

    Quote Originally Posted by couttsj View Post
    Here is a good example of why I prefer to use strings, and why it is necessary to loop through and change any 2 byte characters to what they are supposed to be.
    It would not be necessary, to deal with any "2byte-characters", when you would work with
    ByteArrays throughout your routines... (at least in all the critical, protocol-related ones).

    Quote Originally Posted by couttsj View Post
    When the certificate data is received from the server, I have to search through that data (sometimes well over 4000 bytes) to find the Public Key, the Signature, and the Public Key from the Certificate Authority.
    lPntr1 = InStr(sBuff, Chr$(&H30) & Chr$(&H82)) + 4
    There is a VB-search-function for ByteArrays (InstrB) ... why not use that instead.
    Your problems happen, because you use something like 'sBuf' in the first place
    (sBuf perhaps filled with an improper conversion-function you have no real control over).

    As said, I'd stay at the ByteArray-Level as long as possible...(for protocol-relevant things).

    For transport of User-Data (if this data has to be in String-Format) I already gave advise,
    how to convert Unicode-Strings to and from ByteArrays in a losless manner.

    Cannot do much more - no time to actually look into your code.

    Olaf

  17. #17
    Member
    Join Date
    Dec 2009
    Posts
    45

    Re: VB6 TLSCrypto

    All,

    I am experiencing the exact problem described by MCSchermer in post #7 regarding TLSSend (http://www.vbforums.com/showthread.p...87-VB6-TLSSend). Error 0x80090020 occurs in the server component under Windows 8.1 on a similar call to CryptCreateHash in clsCrypt:ImportMasterKey. Not having a Win7 environment, I converted the code to use mswinsck.ocx and tried it on XP -- interestingly, it fails there a few lines earlier on CryptImportKey. Elsewhere, CryptCreateHash works perfectly on both platforms. This makes me suspect a problem with the master key blob.

    I increased SChannel logging to the max (on Win 8.1) and it reports nothing unusual at the failure point but letting the code continue produces a fatal error EventID 36888 in the System log. The TLS protocol error code is 50. The Windows SChannel error state is 959. TLS1_ALERT_DECODE_ERROR (50) is likely being caused by an invalid state somewhere downstream.

    What little else I can find suggests that the 36888 EventID could be a certificate problem. This may well be. KeyStore Explorer indicates that the localhost.cer file I made on Win 8.1 is version 3 -- and the clsCrypt.cls code is setting bVersion in the master key blob = 2. Changing that parameter makes no difference (...of course).

    Good documentation on any of this is hard to find, but it seems obvious that the OS differences are important. I will continue working on these two angles unless someone else has already solved the problem. Are there any other ideas or updates on this issue?

    -- Fred

  18. #18

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2012
    Posts
    1,477

    Re: VB6 TLSCrypto

    For some reason it no longer works on my system. And I can't reach MikesToolBox either. Give me a couple of days to sort this out and transfer it to my Win 8.1.

    J.A. Coutts

  19. #19
    Member
    Join Date
    Dec 2009
    Posts
    45

    Re: VB6 TLSCrypto

    Thanks. I have been focussed on the server-side code and hadn't tried MikesToolBox with the TLSCrypto client. I can ping that server (174.75.34.16) but it can't be reached with IE-11, FF or Chrome -- HTTP or HTTPS. Even https://www.ssllabs.com/ssltest/anal...kestoolbox.org reports "Assessment failed: No secure protocols supported".

    Incidentally, I also tried accessing https://www.ssllabs.com/ssltest/viewMyClient.html with the TLSCrypto client. It connects and starts the handshake OK and then fails on the call to CryptVerifySignature in clsCrypt:VerifySig. LastDllError -2146893818 (0x80090006 NTE_BAD_SIGNATURE). This is on Win 8.1.

    I hope there's a clue in there somewhere...

    -- Fred

  20. #20

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2012
    Posts
    1,477

    Re: VB6 TLSCrypto

    When accessing "https://www.mikestoolbox.org", the site no longer supplies a CA certificate record. Therefore, the VerifySignature routine will fail. The easiest way around the problem is to comment out the "GoTo Done" statement in the "wClient_EncrDataArrival" routine and simply acknowledge the failure message.
    Code:
                    Case TLS1_MT_CERTIFICATE '2
                        Call DebugPrintString("Certificate", sTemp)
                        If Not VerifySignature(sTemp) Then
                            MsgBox "Unable to Verify Signature!", vbExclamation
    '                        GoTo Done
                        End If
    J.A. Coutts

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width