Vba excel шифрование текста

I am interested if it’s possible to do string encryption/decryption using Excel Visual Basic and some cryptographic service provider.

I have found a walk-through Encrypting and Decrypting Strings in Visual Basic, but it seems it’s valid for standalone Visual Basic only.

So would you suggest me another encryption method or show how the walk-through could be adopted for Excel Visual Basic?

braX's user avatar

braX

11.5k5 gold badges20 silver badges33 bronze badges

asked Sep 24, 2009 at 10:53

Alexander Prokofyev's user avatar

The link you provide shows how to perform string encryption and decryption using VB.NET, and thus, using the .NET Framework.

Currently, Microsoft Office products cannot yet use the Visual Studio Tools for Applications component which will enable Office products to access the .NET framework’s BCL (base class libraries) which, in turn, access the underlying Windows CSP (cryptographic server provider) and provide a nice wrapper around those encryption/decryption functions.

For the time being, Office products are stuck with the old VBA (Visual Basic for Applications) which is based on the old VB6 (and earlier) versions of visual Basic which are based upon COM, rather than the .NET Framework.

Because of all of this, you will either need to call out to the Win32 API to access the CSP functions, or you will have to «roll-your-own» encryption method in pure VB6/VBA code, although this is likely to be less secure. It all depends upon how «secure» you’d like your encryption to be.

If you want to «roll-your-own» basic string encryption/decryption routine, take a look at these link to get you started:

Encrypt a String Easily
Better XOR Encryption with a readable string

vb6 — encryption function
Visual Basic 6 / VBA String Encryption/Decryption Function

If you want to access the Win32 API and use the underlying Windows CSP (a much more secure option), see these links for detailed information on how to achieve this:

How to encrypt a string in Visual Basic 6.0

Access to CryptEncrypt (CryptoAPI/WinAPI) functions in VBA

That last link is likely the one you’ll want and includes a complete VBA Class module to «wrap» the Windows CSP functions.

Scott Holtzman's user avatar

answered Sep 24, 2009 at 11:29

CraigTP's user avatar

2

This code works well for me (3DES Encryption/Decryption):

I store INITIALIZATION_VECTOR and TRIPLE_DES_KEY as environment variables (obviously different values than those posted here) and get them using VBA Environ() function, so all sensitive data (passwords) in VBA code is encrypted.

Option Explicit

Public Const INITIALIZATION_VECTOR = "zlrs$5kd"  'Always 8 characters

Public Const TRIPLE_DES_KEY = ">tlF8adk=35K{dsa" 'Always 16 characters

Sub TestEncrypt()
    MsgBox "This is an encrypted string: -> " & EncryptStringTripleDES("This is an encrypted string:")
    Debug.Print EncryptStringTripleDES("This is an encrypted string:")
End Sub

Sub TestDecrypt()
    MsgBox "u99CVItCGiMQEVYHf8+S22QbJ5CPQGDXuS5n1jvEIgU= -> " & DecryptStringTripleDES("u99CVItCGiMQEVYHf8+S22QbJ5CPQGDXuS5n1jvEIgU=")
End Sub


Function EncryptStringTripleDES(plain_string As String) As Variant

    Dim encryption_object As Object
    Dim plain_byte_data() As Byte
    Dim encrypted_byte_data() As Byte
    Dim encrypted_base64_string As String

    EncryptStringTripleDES = Null

    On Error GoTo FunctionError

    plain_byte_data = CreateObject("System.Text.UTF8Encoding").GetBytes_4(plain_string)

    Set encryption_object = CreateObject("System.Security.Cryptography.TripleDESCryptoServiceProvider")
    encryption_object.Padding = 3
    encryption_object.key = CreateObject("System.Text.UTF8Encoding").GetBytes_4(TRIPLE_DES_KEY)
    encryption_object.IV = CreateObject("System.Text.UTF8Encoding").GetBytes_4(INITIALIZATION_VECTOR)
    encrypted_byte_data = _
            encryption_object.CreateEncryptor().TransformFinalBlock(plain_byte_data, 0, UBound(plain_byte_data) + 1)

    encrypted_base64_string = BytesToBase64(encrypted_byte_data)

    EncryptStringTripleDES = encrypted_base64_string

    Exit Function

FunctionError:

    MsgBox "TripleDES encryption failed"

End Function

Function DecryptStringTripleDES(encrypted_string As String) As Variant

    Dim encryption_object As Object
    Dim encrypted_byte_data() As Byte
    Dim plain_byte_data() As Byte
    Dim plain_string As String

    DecryptStringTripleDES = Null

    On Error GoTo FunctionError

    encrypted_byte_data = Base64toBytes(encrypted_string)

    Set encryption_object = CreateObject("System.Security.Cryptography.TripleDESCryptoServiceProvider")
    encryption_object.Padding = 3
    encryption_object.key = CreateObject("System.Text.UTF8Encoding").GetBytes_4(TRIPLE_DES_KEY)
    encryption_object.IV = CreateObject("System.Text.UTF8Encoding").GetBytes_4(INITIALIZATION_VECTOR)
    plain_byte_data = encryption_object.CreateDecryptor().TransformFinalBlock(encrypted_byte_data, 0, UBound(encrypted_byte_data) + 1)

    plain_string = CreateObject("System.Text.UTF8Encoding").GetString(plain_byte_data)

    DecryptStringTripleDES = plain_string

    Exit Function

FunctionError:

    MsgBox "TripleDES decryption failed"

End Function


Function BytesToBase64(varBytes() As Byte) As String
    With CreateObject("MSXML2.DomDocument").createElement("b64")
        .DataType = "bin.base64"
        .nodeTypedValue = varBytes
        BytesToBase64 = Replace(.Text, vbLf, "")
    End With
End Function


Function Base64toBytes(varStr As String) As Byte()
    With CreateObject("MSXML2.DOMDocument").createElement("b64")
         .DataType = "bin.base64"
         .Text = varStr
         Base64toBytes = .nodeTypedValue
    End With
End Function

Source code taken from here: https://gist.github.com/motoraku/97ad730891e59159d86c

Note the difference between the original code and my code, that is additional option encryption_object.Padding = 3 which forces VBA to not perform padding. With padding option set to 3 I get result exactly as in C++ implementation of DES_ede3_cbc_encrypt algorithm and which is in agreement with what is produced by this online tool.

answered Jan 2, 2018 at 1:35

OGCJN's user avatar

OGCJNOGCJN

3733 silver badges9 bronze badges

1

This code works fine in VBA and can easily be moved to VB.NET

Avoids dealing with not «normal» characters. You decide in AllowedChars what characters to allow.

Public Function CleanEncryptSTR(MyString As String, MyPassword As String, Encrypt As Boolean) As String
'Encrypts strings chars contained in Allowedchars
'MyString = String to decrypt
'MyPassword = Password
'Encrypt True: Encrypy   False: Decrypt
    Dim i As Integer
    Dim ASCToAdd As Integer
    Dim ThisChar As String
    Dim ThisASC As Integer
    Dim NewASC As Integer
    Dim MyStringEncrypted As String
    Dim AllowedChars As String

    AllowedChars = "&0123456789;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

    If Len(MyPassword) > 0 Then
        For i = 1 To Len(MyString)
'            ThisASC = Asc(Mid(MyString, i, 1))
'            ThisASC = IntFromArray(Asc(Mid(MyString, i, 1)), MyVector())

            ThisChar = Mid(MyString, i, 1)
            ThisASC = InStr(AllowedChars, ThisChar)

            If ThisASC > 0 Then
                ASCToAdd = Asc(Mid(MyPassword, i Mod Len(MyPassword) + 1, 1))
                If Encrypt Then
                    NewASC = ThisASC + ASCToAdd
                Else
                    NewASC = ThisASC - ASCToAdd
                End If
                NewASC = NewASC Mod Len(AllowedChars)
                If NewASC <= 0 Then
                    NewASC = NewASC + Len(AllowedChars)
                End If

                MyStringEncrypted = MyStringEncrypted & Mid(AllowedChars, NewASC, 1)
            Else
                MyStringEncrypted = MyStringEncrypted & ThisChar
            End If
        Next i
    Else
        MyStringEncrypted = MyString
    End If

    CleanEncryptSTR = MyStringEncrypted

End Function

answered Apr 24, 2018 at 20:34

user3579314's user avatar

Create a Class Module called clsCifrado:


Option Explicit
Option Compare Binary

Private clsClave As String

Property Get Clave() As String
    Clave = clsClave
End Property

Property Let Clave(value As String)
    clsClave = value
End Property


Function Cifrar(Frase As String) As String

    Dim Cachos() As Byte
    Dim LaClave() As Byte
    Dim i As Integer
    Dim Largo As Integer

    If Frase <> "" Then
        Cachos() = StrConv(Frase, vbFromUnicode)
        LaClave() = StrConv(clsClave, vbFromUnicode)
        Largo = Len(clsClave)

        For i = LBound(Cachos) To UBound(Cachos)
            Cachos(i) = (Cachos(i) Xor LaClave(i Mod Largo)) + 34
        Next i

        Cifrar = StrConv(Cachos(), vbUnicode)
    Else
        Cifrar = ""
    End If

End Function

Function Descifrar(Frase As String) As String

    Dim Cachos() As Byte
    Dim LaClave() As Byte
    Dim i As Integer
    Dim Largo As Integer

    If Frase <> "" Then
        Cachos() = StrConv(Frase, vbFromUnicode)
        LaClave() = StrConv(clsClave, vbFromUnicode)
        Largo = Len(clsClave)

        For i = LBound(Cachos) To UBound(Cachos)
            Cachos(i) = Cachos(i) - 34
            Cachos(i) = (Cachos(i) Xor LaClave(i Mod Largo))
        Next i

        Descifrar = StrConv(Cachos(), vbUnicode)
    Else
        Descifrar = ""
    End If

End Function

Now you can use it in your code:

to cipher


Private Sub btnCifrar_Click()

    Dim Texto As String
    Dim cCifrado As clsCifrado

    Set cCifrado = New clsCifrado

    '---poner la contraseña
    If tbxClave.Text = "" Then
        MsgBox "The Password is missing"
        End Sub
    Else
        cCifrado.Clave = tbxClave.Text
    End If

    '---Sacar los datos
    Texto = tbxFrase.Text

    '---cifrar el texto
    Texto = cCifrado.Cifrar(Texto)

    tbxFrase.Text = Texto

 End Sub

To descipher


Private Sub btnDescifrar_Click()

    Dim Texto As String
    Dim cCifrado As clsCifrado

    Set cCifrado = New clsCifrado

    '---poner la contraseña
    If tbxClave.Text = "" Then
        MsgBox "The Password is missing"
        End Sub
    Else
        cCifrado.Clave = tbxClave.Text
    End If

    '---Sacar los datos
    Texto = tbxFrase.Text

    '---cifrar el texto
    Texto = cCifrado.Descifrar(Texto)

    tbxFrase.Text = Texto
End Sub

Cameron's user avatar

Cameron

3,0981 gold badge24 silver badges40 bronze badges

answered Mar 12, 2014 at 17:07

user3407604's user avatar

You can call pipe excel cell data through any shell script.
Install the GPL Bert (http://bert-toolkit.com/) R language interface for Excel.
Use the R script below in Excel to pipe cell data to Bash / perl / gpg / openssl.

 c:> cat c:R322callable_from_excel.R
    CRYPTIT <- function( PLAINTEXT, MASTER_PASS ) {
    system(
      sprintf("bash -c 'echo '%s' |
        gpg --symmetric --cipher-algo blowfish --force-mdc --passphrase '%s' -q  |
        base64 -w 0'",
        PLAINTEXT, MASTER_PASS),
      intern=TRUE)
  }

DECRYPTIT <- function( CRYPTTEXT, MASTER_PASS ) {
    system(
      sprintf("bash -c 'echo '%s'|
        base64 -d |
        gpg --passphrase '%s' -q |
        putclip | getclip' ",CRYPTTEXT,MASTER_PASS),
      intern=TRUE)  
  } 

In Excel, you can try: C1=CRYPTIT(A1,A2) and C2=DECRYPTIT(C1,A2)
Optional: putclip saves decrypted text in clipboard.
Both functions types are: String -> String.
Usual caveats about escaping single-quotes in single-quoted strings.

answered Jun 1, 2016 at 13:59

mosh's user avatar

moshmosh

1,37214 silver badges16 bronze badges

Here is a basic symmetric encryption/decryption example:

Sub testit()
    Dim inputStr As String
    inputStr = "Hello world!"

    Dim encrypted As String, decrypted As String
    encrypted = scramble(inputStr)
    decrypted = scramble(encrypted)
    Debug.Print encrypted
    Debug.Print decrypted
End Sub


Function stringToByteArray(str As String) As Variant
    Dim bytes() As Byte
    bytes = str
    stringToByteArray = bytes
End Function

Function byteArrayToString(bytes() As Byte) As String
    Dim str As String
    str = bytes
    byteArrayToString = str
End Function


Function scramble(str As String) As String
    Const SECRET_PASSWORD As String = "K*4HD%f#nwS%sdf032#gfl!HLKN*pq7"

    Dim stringBytes() As Byte, passwordBytes() As Byte
    stringBytes = stringToByteArray(str)
    passwordBytes = stringToByteArray(SECRET_PASSWORD)

    Dim upperLim As Long
    upperLim = UBound(stringBytes)
    ReDim scrambledBytes(0 To upperLim) As Byte
    Dim idx As Long
    For idx = LBound(stringBytes) To upperLim
        scrambledBytes(idx) = stringBytes(idx) Xor passwordBytes(idx)
    Next idx
    scramble = byteArrayToString(scrambledBytes)
End Function

Be aware that this will crash if your given input string is longer than the SECRET_PASSWORD. This is just an example to get started with.

answered Dec 12, 2014 at 16:03

MathKid's user avatar

MathKidMathKid

1,7231 gold badge20 silver badges21 bronze badges

1

Sub Main()
    Dim Key As String
    Dim Msg As String
    Dim EncryptMsg As String
    Dim DecryptMsg As String

    Key = "мечта"
    Msg = "реализация шифра методом вертикальной перестановки с ключом мечта"

    EncryptMsg = VerticalShuffleEncrypt(Key, Msg)
    DecryptMsg = VerticalShuffleDecrypt(Key, EncryptMsg)

    ' реализация шифра методом вертикальной перестановки с ключом мечта '
    Cells(1, 1).Value = Msg
    ' иярт инеаил аеаш деайеосчерз аовкорн юмлифемтьптккмтациморл св оч '
    Cells(2, 1).Value = EncryptMsg
    ' реализация шифра методом вертикальной перестановки с ключом мечта '
    Cells(3, 1).Value = DecryptMsg
End Sub

Function VerticalShuffleEncrypt(ByVal Key As String, ByVal Msg As String) As String
    Dim KeyArr As Object
    Dim L As Long
    Dim Col As String
    Dim Res As String

    L = Len(Msg)  Len(Key)
    If (Len(Msg) Mod Len(Key) <> 0) Then
        L = L + 1
    End If

    Set KeyArr = CreateObject("System.Collections.ArrayList")

    For I = 1 To Len(Key)
        KeyArr.Add Mid(Key, I, 1)
    Next I

    KeyArr.Sort

    Res = ""
    For Each K In KeyArr
        I = InStr(1, Key, K, vbTextCompare)
        Col = ""
        'For J = I To Len(Msg) Step L
        '    Res = Res & Mid(Msg, J, 1)
        'Next J
        For J = I To Len(Msg) Step Len(Key)
            Col = Col & Mid(Msg, J, 1)
        Next J
        If (Len(Col) <> L) Then
            Col = Col & " "
        End If
        Res = Res & Col
    Next

    VerticalShuffleEncrypt = Res
End Function

Function VerticalShuffleDecrypt(ByVal Key As String, ByVal Msg As String) As String
    Dim KeyArr As Object
    Dim IndexArr As Object
    Dim L As Long
    Dim Res As String

    L = Len(Msg)  Len(Key)
    If (Len(Msg) Mod Len(Key) <> 0) Then
        L = L + 1
    End If

    Set KeyArr = CreateObject("System.Collections.ArrayList")
    Set IndexArr = CreateObject("System.Collections.ArrayList")

    For I = 1 To Len(Key)
        KeyArr.Add Mid(Key, I, 1)
    Next I

    KeyArr.Sort

    For I = 1 To Len(Key)
        IndexArr.Add KeyArr.IndexOf(Mid(Key, I, 1), 0) + 1
    Next I

    Res = ""
    For I = 1 To L
        For Each Index In IndexArr
            Res = Res & Mid(Msg, ((Index - 1) * L) + I, 1)
        Next
    Next I

    VerticalShuffleDecrypt = Res
End Function

Шифр вертикальной перестановки

м   е   ч   т   а

3   2   5   4   1

р   е   а   л   и
з   а   ц   и   я
    ш   и   ф   р
а       м   е   т
о   д   о   м   
в   е   р   т   и
к   а   л   ь   н
о   й       п   е
р   е   с   т   а
н   о   в   к   и
    с       к   л
ю   ч   о   м   
м   е   ч   т   а

Результат:

Исходное сообщение:

реализация шифра методом вертикальной перестановки с ключом мечта

Зашифрованное сообщение:

иярт инеаил аеаш деайеосчерз аовкорн юмлифемтьптккмтациморл св оч

Восстановленное сообщение:

реализация шифра методом вертикальной перестановки с ключом мечта

В этой статье опубликованы различные вспомогательные функции на VBA, которые порой помогают в работе.

1. Функция формирования инициалов из имени и отчества

Function CropFIO(ByVal FIO As String) As String
    ' получает в качестве параметра текстовую строку с виде "Фамилия имя отчество"
    ' обрезает имя и отчество, оставляя лишь инициалы - в виде "Фамилия И. О."
    CropFIO = Application.Trim(FIO): arr = Split(CropFIO, " ")
    If UBound(arr) <> 2 Then Exit Function    ' Если в ячейке не 3 слова - выход из процедуры
    CropFIO = Replace(CropFIO, " " & arr(1), " " & UCase(Left(arr(1), 1)) & ".")
    CropFIO = Replace(CropFIO, " " & arr(2), " " & UCase(Left(arr(2), 1)) & ".")
End Function

2. Шифрование строк на VBA

Dim s(0 To 255) As Integer, kep(0 To 255) As Integer
 
Public Function EnDeCrypt(ByVal plaintxt As String, ByVal Password As String) As String
    Dim temp As Integer, a As Integer, b As Integer, cipherby As Byte, cipher As String
    b = 0: For a = 0 To 255: b = b + 1: If b > Len(Password) Then b = 1
        kep(a) = Asc(Mid$(Password, b, 1)): Next a
    For a = 0 To 255: s(a) = a: Next a: b = 0
    For a = 0 To 255: b = (b + s(a) + kep(a)) Mod 256: temp = s(a): s(a) = s(b): s(b) = temp: Next a
    For a = 1 To Len(plaintxt): cipherby = EnDeCryptSingle(Asc(Mid$(plaintxt, a, 1)))
        cipher = cipher & Chr(cipherby): Next: EnDeCrypt = cipher
End Function
Public Function EnDeCryptSingle(plainbyte As Byte) As Byte
    Dim i As Integer, j As Integer, temp As Integer, k As Integer, cipherby As Byte
    i = (i + 1) Mod 256: j = (j + s(i)) Mod 256: temp = s(i): s(i) = s(j): s(j) = temp
    k = s((s(i) + s(j)) Mod 256): cipherby = plainbyte Xor k: EnDeCryptSingle = cipherby
End Function
 
' примеры использования
Sub Шифрование_с_расшифровкой()
    MsgBox EnDeCrypt(EnDeCrypt("123456", "passw"), "passw")
End Sub
 
Sub Тест_шифра()
    MsgBox EnDeCrypt("123456", "пароль")
End Sub

3. Сортировка двумерного массива по нулевому столбцу

Public Function CoolSort(SourceArr As Variant) As Variant
    Dim Check As Boolean, iCount As Integer, jCount As Integer, nCount As Integer
    ReDim tmpArr(UBound(SourceArr, 2)) As Variant
    Do Until Check
        Check = True
        For iCount = LBound(SourceArr, 1) To UBound(SourceArr, 1) - 1
            If Val(SourceArr(iCount, 0)) > Val(SourceArr(iCount + 1, 0)) Then
                For jCount = LBound(SourceArr, 2) To UBound(SourceArr, 2)
                    tmpArr(jCount) = SourceArr(iCount, jCount)
                    SourceArr(iCount, jCount) = SourceArr(iCount + 1, jCount)
                    SourceArr(iCount + 1, jCount) = tmpArr(jCount)
                    Check = False
                Next
            End If
        Next
    Loop
    CoolSort = SourceArr
End Function

4. Преобразование строки в набор ASC кодов

Function String2CharCodes(ByVal txt$) As String
    sep = " & "
    For i = 1 To Len(txt)
        charcode = "Chr(" & Asc(Mid(txt, i, 1)) & ")"
        String2CharCodes = String2CharCodes & sep & charcode
    Next i
    String2CharCodes = Mid(String2CharCodes, Len(sep) + 1)
End Function

5. Функции для определения нажатой клавиши

'============= Функции для определения нажатой клавиши =================================
Public Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As VirtualKeys) As Integer
 
Public Enum VirtualKeys    ' Virtual Keys, Standard Set
    VK_LBUTTON = &H1: VK_RBUTTON = &H2: VK_CANCEL = &H3: VK_MBUTTON = &H4    'VK_MBUTTON = &H4 -  NOT contiguous with L RBUTTON
    VK_BACK = &H8: VK_TAB = &H9: VK_CLEAR = &HC: VK_RETURN = &HD
    VK_SHIFT = &H10: VK_CONTROL = &H11: VK_MENU = &H12: VK_PAUSE = &H13: VK_CAPITAL = &H14: VK_ESCAPE = &H1B
    VK_SPACE = &H20: VK_PRIOR = &H21: VK_NEXT = &H22: VK_END = &H23: VK_HOME = &H24
    VK_LEFT = &H25: VK_UP = &H26: VK_RIGHT = &H27: VK_DOWN = &H28: VK_SELECT = &H29: VK_PRINT = &H2A
    VK_EXECUTE = &H2B: VK_SNAPSHOT = &H2C: VK_INSERT = &H2D: VK_DELETE = &H2E: VK_HELP = &H2F
 
    ' VK_A thru VK_Z are the same as their ASCII equivalents: 'A' thru 'Z'
    ' VK_0 thru VK_9 are the same as their ASCII equivalents: '0' thru '9'

    VK_NUMPAD0 = &H60: VK_NUMPAD1 = &H61: VK_NUMPAD2 = &H62: VK_NUMPAD3 = &H63: VK_NUMPAD4 = &H64
    VK_NUMPAD5 = &H65: VK_NUMPAD6 = &H66: VK_NUMPAD7 = &H67: VK_NUMPAD8 = &H68: VK_NUMPAD9 = &H69
    VK_MULTIPLY = &H6A: VK_ADD = &H6B: VK_SEPARATOR = &H6C: VK_SUBTRACT = &H6D: VK_DECIMAL = &H6E: VK_DIVIDE = &H6F
    VK_F1 = &H70: VK_F2 = &H71: VK_F3 = &H72: VK_F4 = &H73: VK_F5 = &H74: VK_F6 = &H75: VK_F7 = &H76
    VK_F8 = &H77: VK_F9 = &H78: VK_F10 = &H79: VK_F11 = &H7A: VK_F12 = &H7B
    VK_F13 = &H7C: VK_F14 = &H7D: VK_F15 = &H7E: VK_F16 = &H7F: VK_F17 = &H80: VK_F18 = &H81
    VK_F19 = &H82: VK_F20 = &H83: VK_F21 = &H84: VK_F22 = &H85: VK_F23 = &H86: VK_F24 = &H87
    VK_NUMLOCK = &H90: VK_SCROLL = &H91
 
    '   VK_L VK_R - left and right Alt, Ctrl and Shift virtual keys.
    '   Used only as parameters to GetAsyncKeyState() and GetKeyState().
    '   No other API or message will distinguish left and right keys in this way.
    VK_LSHIFT = &HA0: VK_RSHIFT = &HA1: VK_LCONTROL = &HA2: VK_RCONTROL = &HA3: VK_LMENU = &HA4: VK_RMENU = &HA5
 
    VK_ATTN = &HF6: VK_CRSEL = &HF7: VK_EXSEL = &HF8: VK_EREOF = &HF9: VK_PLAY = &HFA
    VK_ZOOM = &HFB: VK_NONAME = &HFC: VK_PA1 = &HFD: VK_OEM_CLEAR = &HFE
End Enum
'==========================================================================================

Public Function KeyPressed(ByVal VKey As VirtualKeys) As Boolean
    KeyPressed = IIf(GetKeyState(VKey) < 0, True, False)
End Function

6. Макрос для создания копии файла программы
(подразумевается наличие в программе глобальной константы или функции PROJECT_NAME)

Sub CreateBackup()
    On Error Resume Next: ThisWorkbook.Save
    BackupsPath = Replace(ThisWorkbook.FullName, ThisWorkbook.Name, PROJECT_NAME & " Backups")
    MkDir BackupsPath
    filename = PROJECT_NAME & "_BACKUP_" & Format(Now, "DD-MM-YYYY__HH-NN-SS") & ".xls"
    ThisWorkbook.SaveCopyAs BackupsPath & filename
    'Debug.Print BackupsPath & filename
End Sub

7. Изменяем форматирование цифр в ячейке (выделяем все цифры полужирным шрифтом)

Sub BoldingDigits(ByRef celll As Range)
    For i = 1 To celll.Characters.count
        letter = celll.Characters(start:=i, Length:=1).Text
        celll.Characters(start:=i, Length:=1).Font.Bold = IsNumeric(letter)
    Next
End Sub

8. Поиск артикула (последовательности цифр заданной длины) в текстовой строке
Ссылка на примеры использования Regexp: script-coding.com/WSH/RegExp.html

Function FindDigits(ByVal txt$, ByVal DigitsCount%) As String
    ' ищет в строке txt$ подстроку цифр длиной DigitsCount%
    Set expres = CreateObject("VBScript.RegExp")
    expres.Pattern = Replace(String(DigitsCount%, "%"), "%", "[0-9]")
    If expres.test(txt$) Then FindDigits = expres.Execute(txt$)(0).Value
End Function

Function FindDigits(ByVal txt$, ByVal DigitsCount%) As String
    ' ищет в строке txt$ подстроку цифр длиной DigitsCount%
    Set RegExp = CreateObject("VBScript.RegExp"): RegExp.Global = True
    RegExp.Pattern = "[D]": txt$ = " " & RegExp.Replace(txt$, " ") & " "
    RegExp.Pattern = " [d]{" & DigitsCount% & "} "
    If RegExp.test(txt$) Then FindDigits = RegExp.Execute(txt$)(0).Value
End Function

9. Добавление значений сразу во весь столбец двумерного массива

Sub AddValueIntoColumn(ByRef arr, ByVal ColumnIndex%, ByVal NewValue)
    ' добавляет значение NewValue в столбец ColumnIndex% всех строк
    ' переданного по ссылке двумерного массива arr
    For i = LBound(arr) To UBound(arr)
        arr(i, ColumnIndex%) = NewValue
    Next i
End Sub

10. Использование Application.OnTime с задержкой меньше секунды

Sub ЗапускМакросаСНебольшойЗадержкой() ' по мотивам макроса ZVI_Timer
    ЗадержкаВСекундах = 0.3    ' в секундах
    НазваниеМакроса$ = "test"    ' этот макрос будет запущен через 0.3 сек.
    ЗадержкаВЧасах$ = Replace(Format(CDbl(TimeSerial(0, 0, 1)) * ЗадержкаВСекундах, "0.000000000"), ",", ".")
    macro = "ON.TIME(NOW()+" & ЗадержкаВЧасах$ & ", """ & НазваниеМакроса$ & """)" ' формируем команду запуска
    ExecuteExcel4Macro macro ' macro = ON.TIME(NOW()+0.000003472, "test")
End Sub

11. Преобразование коллекции в массив

Function Collection2Array(ByVal coll As Collection) As Variant
    ReDim arr(0 To coll.Count - 1): Dim i As Long
    For i = 1 To coll.Count: arr(i - 1) = coll(i): Next i
    Collection2Array = arr
End Function

12. Разрешаем Excel доступ в Интернет путем отключения брандмауэра:

' включаем файрвол Windows (доступ в интернет ограничен)
CreateObject("HNetCfg.FwMgr").LocalPolicy.CurrentProfile.FirewallEnabled = True
 
' отключаем файрвол Windows (доступ в интернет открыт)
CreateObject("HNetCfg.FwMgr").LocalPolicy.CurrentProfile.FirewallEnabled = False

Перейти к содержимому

Шифровка:

Функция получает в качестве параметров открытый текст и смещения. Исходный текст разбивается на символы и получается ASCII код каждого символа. ASCII код символа смещается на величину смещения. С данного кода получается символ и добавляется к результирующей сроки возвращаемого функцией inchezar.

Function inchezar(inp As String, key As Integer)
Dim rez As String
Dim ls As Integer
Dim simv As String
Dim ks As Integer
Dim pr As String
key = key Mod 255
rez = «»
ls = Len(inp)
For i = 0 To ls — 1
simv = Mid(inp, i + 1, 1)
ks = Asc(simv)
pr = ks + key
If (pr > 255) Then pr = (pr Mod 255) + 31
rez = rez + Chr(pr)

Next i
inchezar = rez
End Function

Дешифровка:

Функция получает в качестве входных параметров зашифрованный текст и количество символов, на которое делается сдвиг. Аналогичными операциями как в функции inchezar (но со смещением кругу символа в другую сторону) получается открытый текст, который возвращается функцией outchezar.

Function outchezar(inp As String, key As Integer)
Dim rez As String
Dim ls As Integer
Dim simv As String
Dim ks As Integer
Dim pr As String
key = key Mod 255
rez = «»
ls = Len(inp)
For i = 0 To ls — 1
simv = Mid(inp, i + 1, 1)
ks = Asc(simv)
pr = ks — key

If (pr < 32) Then pr = (pr Mod 31) + 224

rez = rez + Chr(pr)
Next i
outchezar = rez
End FunctionБезымянныйБезымянный.png

Защита ячеек шифром Виженера

Парольная защита листов в Microsoft Excel давно стала притчей во языцех. В том плане, что ее, по-сути, нет. С регулярностью примерно раз в месяц я получаю вопросы по почте на тему «как мне защитить мои данные на листе Excel от просмотра/изменения?» и каждый раз не знаю что ответить. Можно, конечно, дать ссылочку на статью с подробным описанием всех способов защиты ячеек и листов в Excel, но такая защита остановит только начинающего. В сети можно найти кучу платных и бесплатных программ для взлома такой защиты тупым перебором за считанные минуты.

В какой-то момент мне это надоело и я стал искать способы более надежной защиты данных в Excel собственными силами. Самым простым и удобным оказался шифр Виженера.

Принцип шифра Виженера

Одним из самых древних и простых в реализации является шифр Цезаря, который использовал его для тайной переписки. Суть его в том, что каждая буква исходного шифруемого сообщения сдвигается в алфавите на заданное количество символов. Так, например, если сдвиг равен 3, то буква А превратится в Г, буква Б — в Д и так далее:

Шифр Цезаря

Символы в конце алфавита (Э, Ю, Я), соответственно, будут превращаться его начало (А, Б, В).

Реализовать такой шифр просто, но стойкость его невелика — найти нужное число сдвига и дешифровать сообщение можно даже прямым перебором за 20-30 итераций, что займет даже у человека не больше часа, а у современного компьютера доли секунды. Поэтому еще в 15 веке был впервые придуман, а потом в 16 веке французским дипломатом Блезом Виженером официально представлен более совершенный метод на основе шифра Цезаря, получивший впоследствии название «шифр Виженера». Его принцип в том, что каждая буква в исходном шифруемом тексте сдвигается по алфавиту не на фиксированное, а переменное количество символов. Величина сдвига каждой буквы задается ключом (паролем) — секретным словом или фразой, которая используется для шифрования и расшифровки. 

Допустим, мы хотим зашифровать фразу «КЛАД ЗАРЫТ В САДУ» используя слово ЗИМА в качестве ключа. Запишем это слово подряд несколько раз под исходной фразой:

vigenere-encription2.png

Для удобства шифрования используем так называемый «квадрат Виженера» — таблицу, где в каждой строке алфавит сдвигается на одну позицию вправо:

квадрат виженера

Если взять строку с первой буквой ключа (З) и столбец с первой буквой исходного текста (К), то на их пересечении увидим букву «Т» — это и будет первая буква нашего зашифрованного сообщения. Затем процедура повторяется для всех остальных пар букв ключа и исходного сообщения по очереди и в результате мы получаем зашифрованный вариант нашей исходной фразы:

шифр виженера результат

Заметьте, что одна и та же буква (например А) в исходном сообщений превратилась в разные буквы на выходе (Н, Й и Б), т.к. сдвиг при шифровании для них был разный. Именно поэтому вскрыть шифр Виженера простыми способами невозможно — вплоть до 19 века он считался невзламываемым и успешно использовался военными, дипломатами и шпионами многих стран, частности — конфедератами во время Гражданской войны в США.

Реализация формулами по квадрату Виженера

Если использовать готовый квадрат Виженера как в примере выше, то реализовать шифрование можно одной формулой с помощью функций ИНДЕКС (INDEX) и ПОИСКПОЗ (MATCH), как это было описано в статье про двумерный поиск в таблице. Выглядеть это может примерно так:

vigenere-encription5.png

Логика этой формулы следующая:

  • Первая функция ПОИСКПОЗ (подсвечена зеленым) ищет первую букву ключа (З) в зеленом столбце (B9:B40) и выдает порядковый номер ячейки, где она ее нашла, т.е. номер строки в квадрате Виженера по которому идет шифрование.
  • Вторая функция ПОИСКПОЗ (подсвечена розовым) аналогичным образом ищет первую букву исходного сообщения (К) в красной строке и выдает порядковый номер столбца.
  • Функция ИНДЕКС выдает содержимое ячейки из квадрата (C9:AH40) с пересечения строки и столбца с найденными номерами.

Реализация формулами по кодам символов

Легко сообразить, что в реальной жизни в документах могут использоваться не только буквы русского языка, но и латиница, цифры, знаки препинания и т.д. Делать квадрат Виженера с участием всех этих символов — та еще эпопея, но есть другой, гораздо более простой способ.

Внутри компьютера и операционной системы каждый символ имеет свой числовой код от 0 до 255 (его еще называют ASCII-кодом). Microsoft Excel имеет в своем стандартном наборе две функции, которые умеют с ними работать:

  • Функция КОДСИМВ (CODE) — выдает числовой код символа, указанного в качестве аргумента. Например КОДСИМВ(«Ж») выдаст 198.
  • Функция СИМВОЛ (CHAR) — выдает символ, соответствующий указанному в аргументе коду, т.е. наоборот СИМВОЛ(198) даст нам букву Ж. 

Для применения шифра Виженера запишем наш исходный текст и ключ друг под другом как раньше и выведем коды каждой буквы с помощью функции КОДСИМВ:

vigenere-encription6.png

Теперь сложим коды символов ключа и исходного текста, добавив функцию ОСТАТ (MOD), чтобы при превышении максимально допустимого количества символов (256) остаться в пределах 0-255:

vigenere-encription7.png

Теперь осталось использовать функцию СИМВОЛ, чтобы вывести символы по полученным кодам и сформировать зашифрованное сообщение:

vigenere-encription8.png

Само-собой, можно было бы обойтись и без дополнительных строк, уложив все функции в одну формулу для компактности:

vigenere-encription9.png

Расшифровка производится совершенно аналогично, только знак «плюс» в формуле меняется на «минус»:

vigenere-encription10.png

Для шпионских игр шифрование такими спецсимволами, конечно, не очень удобно — так и представляю себе глаза радистки Кэт при попытке передать третий и пятый символы нашей шифровки :) Но нам их, отстреливаясь из именного ТТ во время погони, на бумажке не писать, так что для наших целей — сойдет.

Макросы для шифрования-дешифрования

Ну, а теперь самое интересное. Чтобы применить шифр Виженера в реальной жизни лучше будет воспользоваться простым макросом, который проводит все описанные в предыдущем пункте операции с каждой ячейкой текущего листа автоматически. Откройте редактор Visual Basic с помощью сочетания клавиш Alt+F11 или кнопкой Visual Basic на вкладке Разработчик (Developer). Вставьте новый модуль с помощью команды меню Insert — Module и скопируйте туда текст наших макросов:

 
'Шифрование текущего листа
Sub Encrypt()
    Dim Pass$, Key$
    Pass = InputBox("Введите ключ для шифрования:")
    Key = WorksheetFunction.Rept(Pass, 100)
    
    For Each cell In ActiveSheet.UsedRange
        Out = ""
        Txt = cell.Formula
        For i = 1 To Len(Txt)
            Out = Out & Chr((Asc(Mid(Txt, i, 1)) + Asc(Mid(Key, i, 1))) Mod 256)
        Next i
        cell.Value = Out
    Next cell
End Sub

'Дешифрация текущего листа
Sub Decrypt()
    Dim Pass$, Key$
    Pass = InputBox("Введите ключ для расшифровки:")
    Key = WorksheetFunction.Rept(Pass, 100)
    
    For Each cell In ActiveSheet.UsedRange
        Out = ""
        Txt = cell.Value
        For i = 1 To Len(Txt)
            Out = Out & Chr((Asc(Mid(Txt, i, 1)) - Asc(Mid(Key, i, 1)) + 256) Mod 256)
        Next i
        cell.Formula = Out
    Next cell
End Sub
 

Первый макрос запрашивает у пользователя ключ и шифрует все ячейки текущего листа. Второй макрос производит обратную операцию дешифрования. Запустить получившиеся макросы можно с помощью сочетания клавиш Alt+F8 или кнопки Макросы (Macros) на вкладке Разработчик (Developer). Выглядеть все это может примерно так:

vigenere-encryption11.gif

Важные нюансы

  • ВНИМАНИЕ! Если вы внимательно прочитали статью, то должны четко понимать — не существует легкого способа узнать или подобрать ключ! Есть несколько методик взлома шифра Виженера, но все они весьма сложны для неспециалиста и не дают 100% гарантии. Если вы забудете ключ — потеряете данные навсегда с большой вероятностью. Если что — я вас предупредил.
  • При шифровании не нарушаются формулы, ссылки и форматирование — после дешифрации все отлично работает.
  • Если при дешифрации вы неправильно введете ключ, то получите бессмысленную «кашу» из спецсимволов вместо своего текста (т.к. сдвиг кодов будет неправильным). Тогда придется откатиться на шаг назад повторным шифрованием с тем же паролем и потом снова попробовать расшифровать документ еще раз (на этот раз используя правильный ключ).

Ссылки по теме

  • 4 способа защиты данных в Microsoft Excel
  • Суперскрытый лист в книге Excel
  • Выборочное отображение листов книги пользователям по паролю

excel-exposure-free-excel-course

This VBA macro is hopefully a bit more interesting than the last, and shows how I created a message encryptor/decryptor in Excel using VBA/macros.

The lesson covers these specific areas of VBA usage:

– For…Next loop (including nested loops)

– If…ElseIf…Then Statement

– Excel functions: CHAR() / LEN() / VLOOKUP()

– VBA functions: Mod / Mid / Asc / Chr

Download the Message Encryptor & Decryptor here to follow along with the video lesson.

Comments are closed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
Function MyEncode$(txt$, key$)
    Dim i&, j&, n&, m&, l&, s1$, s2$
    n = Len(key) 'длина ключа
    If n = 0 Then Exit Function 'если ключ нулевой длины, то выходим из функции
    l = Len(txt)
    m = -Int(-l / n)
    
    ReDim nKeys&(1 To n)
    For i = 1 To n 'определяем последовательность столбцов по ключу
        s1 = Mid$(key, i, 1)
        For j = 1 To n
            s2 = Mid$(key, j, 1)
            If s1 > s2 Or (s1 = s2 And j <= i) Then nKeys(i) = nKeys(i) + 1
    Next j, i
    
    ReDim out$(1 To n * m)
    For i = 1 To Len(txt) 'шифруем строку
        out(nKeys((i - 1) Mod n + 1) * m + (i - 1)  n - m + 1) = Mid(txt, i, 1)
    Next i
    MyEncode = Join(out, "")
End Function
 
Function MyDecode$(txt$, key$)
    Dim i&, j&, d&, k&, n&, m&, l&, nTmp&, sTmp$, outTxt$
    n = Len(key) 'длина ключа
    If n = 0 Then Exit Function 'если ключ нулевой длины, то выходим из функции
    l = Len(txt)
    m = -Int(-l / n)
    d = l Mod n
 
    ReDim nKeys&(1 To n), sKeys(1 To n)
    For i = 1 To n 'определяем последовательность столбцов по ключу
        nKeys(i) = i
        sKeys(i) = Mid$(key, i, 1)
        For j = 1 To i - 1
            If sKeys(i) < sKeys(j) Then
                sTmp = sKeys(i): sKeys(i) = sKeys(j): sKeys(j) = sTmp
                nTmp = nKeys(i): nKeys(i) = nKeys(j): nKeys(j) = nTmp
            End If
    Next j, i
    
    ReDim out$(1 To n, 1 To m)
    For i = 1 To n 'дешифруем строку
        For j = 1 To m + (nKeys(i) > d And d > 0)
            k = k + 1
            out(nKeys(i), j) = Mid$(txt, k, 1)
    Next j, i
    For j = 1 To m
        For i = 1 To n
            outTxt = outTxt & out(i, j)
    Next i, j
    MyDecode = outTxt
End Function

Понравилась статья? Поделить с друзьями:
  • Vba excel что такое boolean
  • Vba excel что делает
  • Vba excel что бы не могли копировать
  • Vba excel чтение ячеек
  • Vba excel числовые форматы