RC4 Encryption Algorithm for VBA and VBScript

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • ADezii
    Recognized Expert Expert
    • Apr 2006
    • 8834

    #31
    What is the specific purpose of the Disp() Function in the example?

    Comment

    • NeoPa
      Recognized Expert Moderator MVP
      • Oct 2006
      • 32668

      #32
      It shows the result ADezii.

      If you look at the code you'll see it has a second parameter so that you can use it to convert one way or another.

      In the worksheet you'll see it used to take whatever is in A1, and with a key from A2, convert it to a value in A3. It is then used to take that value (in A3) and convert it back - again using the same key in A2 - to a value in A4. If all goes to plan (It does.) then A4 is the same as A1, regardless of what that is.

      You can change the values of A1, and even the key in A2, but A3 & A4 are formula results using =Disp(...).

      Comment

      • ADezii
        Recognized Expert Expert
        • Apr 2006
        • 8834

        #33
        Thank you for the explanation, apparently just went blank for awhile. Getting old I guess!

        Comment

        • NeoPa
          Recognized Expert Moderator MVP
          • Oct 2006
          • 32668

          #34
          I must be too then :-D

          I had to update it recently and I was a while trying to work out how the darn thing even used the code.

          Comment

          • NeoPa
            Recognized Expert Moderator MVP
            • Oct 2006
            • 32668

            #35
            Hi Rabbit.

            I hope you like my slightly modified version of your RC4() procedure. The changes I've made are to speed it up where possible by saving the buffer data where it doesn't change and to build the result string up in place rather than using repeated recreations of the value with code of the form X = X & ....

            Your original s() & k() arrays are reproduced exactly whenever it's run so I keep the k() one, named aintKey() in my version, in Static memory as it never changes. Your s(), named aintBuf() in my version, changes as the process runs but is always re-initialised to the same data so I keep the original version of that in Static memory and copy it across quickly whenever it's required.

            Let me know if you see any problems with this. I should add that I've been using this for many years without this change and the performance has been almost too quick to measure anyway. I just woke up one day & decided it should be optimised a bit anyway.
            Code:
            Private Function RC4(strText As String, strKey As String _
                               , Optional ByVal intSalt As Integer = 3072) As String
                Static aintKey(&HFF) As Integer, aintBufSav(&HFF) As Integer
                Static strUsedKey As String
                Dim intKeyLen As Integer, intTemp As Integer
                Dim intX1 As Integer, intX2 As Integer, intX3 As Integer
                Dim aintBuf(&HFF) As Integer
            
                If strKey <> strUsedKey Then
                    strUsedKey = strKey
                    'Initialise buffer and keystream
                    intKeyLen = Len(strKey)
                    For intX1 = LBound(aintBuf) To UBound(aintBuf)
                        aintBuf(intX1) = intX1
                        aintKey(intX1) = Asc(Mid(strKey, (intX1 Mod intKeyLen) + 1))
                    Next
            
                    'Scramble up the data in the buffer a bit
                    intX2 = 0
                    For intX1 = LBound(aintBuf) To UBound(aintBuf)
                        intX2 = (intX2 + aintBuf(intX1) + aintKey(intX1)) Mod &H100
                        intTemp = aintBuf(intX2)
                        aintBuf(intX2) = aintBuf(intX1)
                        aintBufSav(intX2) = aintBuf(intX1)
                        aintBuf(intX1) = intTemp
                        aintBufSav(intX1) = intTemp
                    Next
                Else
                    For intX1 = LBound(aintBuf) To UBound(aintBuf)
                        aintBuf(intX1) = aintBufSav(intX1)
                    Next
                End If
            
                'Encode/Decode (but process intSalt bytes through the stream before
                '   we start).
                intX2 = 0
                intX3 = 0
                RC4 = Space(Len(strText))
                For intX1 = 1 To intSalt + Len(strText)
                    intX2 = (intX2 + 1) Mod &H100
                    intX3 = (intX3 + aintBuf(intX2)) Mod &H100
                    intTemp = aintBuf(intX2)
                    aintBuf(intX2) = aintBuf(intX3)
                    aintBuf(intX3) = intTemp
                    If intX1 > intSalt Then
                        Mid(RC4, intX1 - intSalt, 1) = _
                            Chr(Asc(Mid(strText, intX1 - intSalt)) Xor _
                                aintBuf((aintBuf(intX2) + aintBuf(intX3)) Mod &H100))
                    End If
                Next
            End Function
            Last edited by NeoPa; Aug 9 '21, 05:39 PM.

            Comment

            • Rabbit
              Recognized Expert MVP
              • Jan 2007
              • 12517

              #36
              Hi NeoPa,

              It's been awhile since I've looked at this code and it's been over 6 years since I've worked in Access with any regularity so let me dust off my memory banks.

              I noticed you turned the drop bytes into something like a salt. While not a standard way of incorporating a salt, it's certainly a good and needed addition to the original code.

              I don't think the saving of the buffers gains you a whole lot in performance, probably just a tiny amount. I suspect the larger performance gain would be to factor out the string appending that's happening and return an array of integers instead.

              Comment

              • NeoPa
                Recognized Expert Moderator MVP
                • Oct 2006
                • 32668

                #37
                Hi Rabbit.

                Great to hear you're still around - even if not busy in Access. You were always more of a SQL expert than Access specifically so no great surprise there I expect.
                Originally posted by Rabbit
                Rabbit:
                I noticed you turned the drop bytes into something like a salt. While not a standard way of incorporating a salt, it's certainly a good and needed addition to the original code.
                Not really, but thank you anyway. All I did was merge some of your code together that did the same work. Logically it's exactly the same as yours I believe.
                Originally posted by Rabbit
                Rabbit:
                I don't think the saving of the buffers gains you a whole lot in performance, probably just a tiny amount. I suspect the larger performance gain would be to factor out the string appending that's happening and return an array of integers instead.
                If you look at the latest version I've posted I think you should find that avoids the string appending and associated delay (by using Mid() = ...). It also allows users to work with strings rather than having to convert when used so I'm pretty happy with that.

                Mostly I use it for storing passwords but recently I had to convert large volumes of data so I decided the performance, though already pretty good, needed to be improved if I could. It was only when I looked at it more carefully that I realised I'd mis-translated the 256s in your original to 255s in the earlier version of my code and the new version also fixes that.
                Last edited by NeoPa; Aug 9 '21, 06:20 PM.

                Comment

                Working...