Decryption function gives wrong result with special characters - vbscript

I'm building an encryption/decryption function in VBScript / Classic ASP.
It all works as long as the string to be encrypted/decrypted does not contain special characters.
' str = "Bayern München"
' key = "ab34ehyd67hy6752daskjh"
Function EncryptString(val, key)
valLen = Len(val)
keyLen = Len(key)
keyPos = 1
newVal = ""
revVal = val
For x = 1 To valLen
calc = AscW(Mid(revVal, x, 1)) + AscW(Mid(key, keyPos, 1))
'Response.Write ":" & AscW(Mid(revVal, x, 1)) & " + " & AscW(Mid(key, keyPos, 1)) & " = " & calc & "<br />"
newVal = newVal & Hex(calc)
keyPos = keyPos + 1
If keyPos > keyLen Then keyPos = 1
Next
EncryptString = newVal
End Function
Function DecryptString(val, key)
' The workaround - start
For i = 160 To 255
val = Replace(val, Chr(i), "&#" & i & ";")
Next
' The workaround - end
valLen = Len(val)
keyLen = Len(key)
keyPos = 1
newVal = ""
revVal = val
chrVal = ""
' I suspect this to be the error
For y = 1 To valLen Step 2
chrVal = chrVal & ChrW("&h" & Mid(revVal, y, 2))
Next
For x = 1 To Len(chrVal)
calc = AscW(Mid(chrVal, x, 1)) - AscW(Mid(key, keyPos, 1))
'Response.Write "::" & AscW(Mid(chrVal, x, 1)) & " - " & AscW(Mid(key, keyPos, 1)) & " = " & calc & "<br />"
newVal = newVal & ChrW(calc)
keyPos = keyPos + 1
If keyPos > keyLen Then keyPos = 1
Next
DecryptString = newVal
End Function
If I do an encryption of the string "Bayern München" and afterwards call the DecryptString function on the encrypted string, it returns Bayern M?À?vU?.
If I output the data (the Response.Write's in the example), the decryption function returns a negative number for the character ü, so I'm doing something wrong - but what?
The system encoding is Windows-1252.
UPDATE:
I did this workaround in the DecryptString function. I'm not sure if it covers all possible problems, but from my testing so far it does:
For i = 160 To 255
val = Replace(val, Chr(i), "&#" & i & ";")
Next

Don't know if you still need to fix it, but all above is because hex() returns a string longer than 2 for any decimal over 255:
(255)10 = (FF)16
(256)10 = (100)16
i.e. when original string + salt is over 255(10)
("ü" 252) + ("6" 54) = 252+54 = 306(10)=132(16) (3 characters long)
then "For y=1 To valLen Step 2" will take only "13" of "132" which will result to improper decryption.
Depends on the need, it can be "fixed", for example, by checking if encrypted code is over 255 and when true, do not add salt:
Function EncryptString(val, key)
...
'newVal = newVal & Hex(calc) <-- replace this by following code
if calc > 255 then
newVal = newVal & "01" & Hex(Asc(Mid(revVal, x, 1))) ' no salt
else
newVal = newVal & Hex(calc)
end if
where "01" is just a "signal" character that tells that the next char will be without salt.
Respectively,
Function DecryptString(val, key)
...
'calc = Asc(Mid(chrVal, x, 1)) - Asc(Mid(key, keyPos, 1))
if Asc(Mid(chrVal, x, 1))=1 then 'determine "signal"
ignorenext = true 'flag that next char has no salt
else
if ignorenext then
calc = Asc(Mid(chrVal, x, 1)) 'no salt
ignorenext = false
else
calc = Asc(Mid(chrVal, x, 1)) - Asc(Mid(key, keyPos, 1))
end if
newVal = newVal & Chr(calc)
keyPos = keyPos + 1
If keyPos > keyLen Then keyPos = 1
end if
Note, for Windows-1252 no need to use AscW()/ChrW() which are unicode specific.
Another approach will be to replace hexadecimal by something more "stable" i.e. base32. Taking sample code from Classic ASP/VBScript implementation of Crockford's Base32 Encoding your code can look like
Function EncryptString(val, key)
valLen = Len(val)
keyLen = Len(key)
keyPos = 1
newVal = ""
revVal = val
For x = 1 To valLen
calc = Asc(Mid(revVal, x, 1)) + Asc(Mid(key, keyPos, 1))
newVal = newVal & ToBase32(calc)
keyPos = keyPos + 1
If keyPos > keyLen Then keyPos = 1
Next
EncryptString = ucase(newVal)
End Function
Function DecryptString(val, key)
valLen = Len(val)
keyLen = Len(key)
keyPos = 1
newVal = ""
revVal = val
chrVal = ""
For y = 1 To valLen Step 2
chrVal = chrVal & fromBase32(Mid(revVal, y, 2))
calc = fromBase32(Mid(revVal, y, 2)) - Asc(Mid(key, keyPos, 1))
newVal = newVal & Chr(calc)
keyPos = keyPos + 1
If keyPos > keyLen Then keyPos = 1
Next
DecryptString = newVal
End Function

Related

Subscript Out off range vb6

I'm making an antivirus. Now I want my antivirus to change color, so I'm making a form and .ini file (A save). So after a long time coding with Modules and functions. I wan tot test it out until I click the setting form button. I have a subscript out of range error(9).
Private Sub GetSetting(Path As String)
Dim Line As String, tmp() As String, ValueX(10) As String, a As Byte
a = 0
If IsFileX(Path) = True Then
Open Path For Input As #1
Do
Line Input #1, Line
tmp = Split(Line, "=")
If UBound(tmp) = 1 Then
a = a + 1
ValueX(a) = tmp(1)
Ck1.value = CInt(Left(Replace(ValueX(a), " ", ""), 1))
End If
If UBound(tmp) = 1 Then
a = a + 2
ValueX(a) = tmp(1)
Ck2.value = CInt(Left(Replace(ValueX(a), " ", ""), 1))
End If
If UBound(tmp) = 1 Then
a = a + 3
ValueX(a) = tmp(1)
Ck3.value = CInt(Left(Replace(ValueX(a), " ", ""), 1))
End If
If UBound(tmp) = 1 Then
a = a + 4
ValueX(a) = tmp(1)
Ck4.value = CInt(Left(Replace(ValueX(a), " ", ""), 1))
End If
If UBound(tmp) = 1 Then
a = a + 5
ValueX(a) = tmp(1)
Ck5.value = CInt(Left(Replace(ValueX(a), " ", ""), 1))
End If
If UBound(tmp) = 1 Then
a = a + 6
ValueX(a) = tmp(1)
Ck6.value = CInt(Left(Replace(ValueX(a), " ", ""), 1))
End If
Loop Until EOF(1)
Close #1
Else
MsgBox " Read Antivirus Setting is ERROR !" & vbNewLine & "Because the file [ MurderAV.ini ] is not found!", vbCritical, "MurderAV Error"
End If
End Sub
The Highlighted part is the ValueX(a) in ck5. (Ck is checkbox)
I'll photo it so it can be clearer:
The problem is that each If statement has an identical condition:
If UBound(tmp) = 1 Then
So, as you go through the code, you execute:
a = 0
a = a + 1
a = a + 2
a = a + 3
a = a + 4
a = a + 5
So a is 15, so you have:
ValueX(15) = tmp(1)
But since ValueX(10) As String, you are off the end of the array.

Read the quantity of carriage return used in Word

I am calculating accuracy from a word document by calculating the total number of changes made once track review is on. Incorrect use of punctuation is calculated as 1/4 mark, while for contextual or grammar errors a full 1 mark is deducted.
Right now all carriage returns are being calculated as 1 full mark. I want this either to be removed completely or can pass it along as 1/4 mark deduction. I am using the following for counting . ; and , as 1/4 mark deduction.
For Each myRevision In ActiveDocument.Revisions
myRevision.Range.Select
If myRevision.Type = wdRevisionInsert Then
lngRevisions = Len(Selection.Text)
For i = 1 To lngRevisions
If Mid(Selection.Text, i, 1) = "," Then
punct = punct + 1
Else
End If
If Mid(Selection.Text, i, 1) = "." Then
punct = punct + 1
Else
End If
If Mid(Selection.Text, i, 1) = ";" Then
punct = punct + 1
Else
End If
If Mid(Selection.Text, i, 1) = "" Then
punct = punct + 1
Else
End If
Next i
Count = Count + 1
Else
End If
Next
tCorrections = Count + punct * 0.25 - punct
Accuracy = ((tWords - tCorrections) / tWords) * 100
Accuracy = Round(Accuracy, 1)
Use an array of types names (aLabels) and a string of the types occurring in your data (sC) via a mapping (aMap) of types to counting slots for a flexible way to classify your string(s). As in this demo:
Option Explicit
Dim aLabels : aLabels = Split("Vowels Consants Digits Punctuations EOLs Unclassified")
ReDim aCounts(UBound(aLabels))
Dim sC : sC = "abce1,2." & vbCr
Dim aMap : aMap = Array(0, 1, 1, 0, 2, 3, 2, 3, 4)
Dim sD : sD = sC & "d" & sC & "bb111."
Dim p, i
For p = 1 To Len(sD)
i = Instr(sC, Mid(sD, p, 1))
If 0 = i Then
i = UBound(aLabels)
Else
i = aMap(i - 1)
End If
aCounts(i) = aCounts(i) + 1
Next
For i = 0 To UBound(aLabels)
WScript.Echo Right(" " & aCounts(i), 3), aLabels(i)
Next
output:
cscript 42505210.vbs
4 Vowels
6 Consants
7 Digits
5 Punctuations
2 EOLs
1 Unclassified
Based on such raw data (frequencies of types) you an add specials weights.
Update wrt comment:
As I said: Add weights after calculating the raw frequencies:
... as above ...
Dim nSum
' Std - all weights = 1
nSum = 0 : For Each i In aCounts : nSum = nSum + i : Next
WScript.Echo "all pigs are equal:", nSum
' No EOLs
nSum = 0 : For Each i In aCounts : nSum = nSum + i : Next : nSum = nSum - aCounts(4)
WScript.Echo "EOLs don't count:", nSum
nSum = 0 : aCounts(0) = aCounts(0) * 4 : For Each i In aCounts : nSum = nSum + i : Next
WScript.Echo "vowels count * 4:", nSum
additional output:
all pigs are equal: 25
EOLs don't count: 23
vowels count * 4: 37

What does &HF7 mean in vbs?

I've been searching Google for awhile and on this site but I can't figure out what &HF7 means? Can someone please explain? Sorry if its a dumb question. I'm very new to this stuff...
Here is the code I'm studying.
Set WshShell = CreateObject("WScript.Shell")
Key = "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\"
DigitalID = WshShell.RegRead(key & "DigitalProductId")
ProductName = "Product Name: " & WshShell.RegRead(Key & "ProductName") & vbNewLine
ProductID = "Product ID: " & WshShell.RegRead(Key & "ProductID") & vbNewLine
ProductKey = "Installed Key: " & ConvertToKey(DigitalID)
ProductID = ProductName & ProductID & ProductKey
If vbYes = MsgBox(ProductId & vblf & vblf & "Save to a file?", vbYesNo + vbQuestion, "Windows Key Information") then
Save ProductID
End if
Function ConvertToKey(Key)
Const KeyOffset = 52
isWin8 = (Key(66) \ 6) And 1
Key(66) = (Key(66) And &HF7) Or ((isWin8 And 2) * 4)
i = 24
Chars = "BCDFGHJKMPQRTVWXY2346789"
Do
Cur = 0
X = 14
Do
Cur = Cur * 256
Cur = Key(X + KeyOffset) + Cur
Key(X + KeyOffset) = (Cur \ 24)
Cur = Cur Mod 24
X = X -1
Loop While X >= 0
i = i -1
KeyOutput = Mid(Chars, Cur + 1, 1) & KeyOutput
Last = Cur
Loop While i >= 0
If (isWin8 = 1) Then
keypart1 = Mid(KeyOutput, 2, Last)
insert = "N"
KeyOutput = Replace(KeyOutput, keypart1, keypart1 & insert, 2, 1, 0)
If Last = 0 Then KeyOutput = insert & KeyOutput
End If
a = Mid(KeyOutput, 1, 5)
b = Mid(KeyOutput, 6, 5)
c = Mid(KeyOutput, 11, 5)
d = Mid(KeyOutput, 16, 5)
e = Mid(KeyOutput, 21, 5)
ConvertToKey = a & "-" & b & "-" & c & "-" & d & "-" & e
End Function
Function Save(Data)
Const ForWRITING = 2
Const asASCII = 0
Dim fso, f, fName, ts
fName = "Windows Key.txt"
Set fso = CreateObject("Scripting.FileSystemObject")
fso.CreateTextFile fName
Set f = fso.GetFile(fName)
Set f = f.OpenAsTextStream(ForWRITING, asASCII)
f.Writeline Data
f.Close
End Function
&HF7 is used as a mask here.
The byte in position 66 of the array Key is compared with the byte &HF7
Written in binary form &HF7 becomes 11110111. If you "And" the value of Key(66) with 11110111 then you'll get a new byte made up of all the bits in Key(66) except the bit in the 4th position from the right.
For example if Key(66) is 10101010 then 10101010 And 11110111 will be 10100010.
It's the number 247.
In VBScript, the &H prefix indicates a hexadecimal number, similar to the 0x prefix in C/C++. The number is F7, which is equivalent of the decimal value 247.
It's a public constant: http://www.vbforums.com/showthread.php?277384-VB-Key-COnsts
Typically used to detect modifier keys being held (ctrl, alt etc)
http://microsoft.public.word.vba.general.narkive.com/28vVYW5c/detect-modifier-keys-from-vba
That specific one is Public Const VK_CRSEL which I assume to be Ctrl select.

ASP: I can´t decode some character from utf-8 to iso-8859-1

I use this function to decode UTF-8:
function DecodeUTF8(s)
dim i
dim c
dim n
i = 1
do while i <= len(s)
c = asc(mid(s,i,1))
if c and &H80 then
n = 1
do while i + n < len(s)
if (asc(mid(s,i+n,1)) and &HC0) <> &H80 then
exit do
end if
n = n + 1
loop
if n = 2 and ((c and &HE0) = &HC0) then
c = asc(mid(s,i+1,1)) + &H40 * (c and &H01)
else
c = 191
end if
s = left(s,i-1) + chr(c) + mid(s,i+n)
end if
i = i + 1
loop
DecodeUTF8 = s
end function
But there are some probles to decode that characters:
€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ
In that case
c=191-->c='¿'
I found some info related with this problem:
http://www.i18nqa.com/debug/utf8-debug.html
Do you know any function to decode correctly?
Public Function DecodeUTF8(s)
Set stmANSI = Server.CreateObject("ADODB.Stream")
s = s & ""
On Error Resume Next
With stmANSI
.Open
.Position = 0
.CharSet = "Windows-1252"
.WriteText s
.Position = 0
.CharSet = "UTF-8"
End With
DecodeUTF8 = stmANSI.ReadText
stmANSI.Close
If Err.number <> 0 Then
lib.logger.error "str.DecodeUTF8( " & s & " ): " & Err.Description
DecodeUTF8 = s
End If
On error Goto 0
End Function

Convert hex string (image) to base64 (for browser rendering) in VBScript

I have a script that outputs a .bmp captcha image.
The image is built in hexadecimal, and converted to binary and sent to the browser via response.binaryWrite chrB(CByte(myHexImage)) (as an image mime type = bmp)
I want the option to move away from that (changing mime type, etc) and toward just sending something to the output like this:
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2 ...
(except that my images are BMP)
Is there a quick and easy way to convert that hex or binary to base64 in vbscript? Here is a snippet of what I have implmented now as described above.
how can I change this so I output, to the screen, valid hex format (which i can then easily convert to base64) or base64 directly?
Dim sBmpEndLine, sBmpInfoHeader, sBmpHeader, sTmpHex
If (m_iBmpWidth Mod 4) <> 0 Then
sBmpEndLine = string((4 - (m_iBmpWidth Mod 4)) * 2, "0")
Else
sBmpEndLine = vbNullString
End If
sBmpInfoHeader = array("28000000", "00000000", "00000000", "0100", "0800", "00000000", "00000000", "120B0000", "120B0000", "00000000", "00000000")
sBmpInfoHeader(1) = formatHex(hex(m_iBmpWidth), 4, 0, True)
sBmpInfoHeader(2) = formatHex(hex(m_iBmpHeight), 4, 0, True)
sBmpInfoHeader(6) = formatHex(hex((m_iBmpHeight * m_iBmpWidth) + (m_iBmpHeight * (len(sBmpEndLine) / 2))), 4, 0, True)
sBmpInfoHeader(9) = formatHex(hex(len(m_sBmpColorMap) / 8), 4, 0, True)
sBmpInfoHeader(10) = sBmpInfoHeader(9)
sBmpHeader = array("424D", "00000000", "0000", "0000", "00000000")
sBmpHeader(1) = formatHex(hex((len(join(sBmpHeader, "")) / 2) + (len(join(sBmpInfoHeader, "")) / 2) + (len(m_sBmpColorMap) / 2) + (m_iBmpHeight * m_iBmpWidth) + (m_iBmpHeight * (len(sBmpEndLine) / 2))), 4, 0, True)
sBmpHeader(4) = formatHex(hex((len(join(sBmpHeader, "")) / 2) + (len(join(sBmpInfoHeader, "")) / 2) + (len(m_sBmpColorMap) / 2)), 4, 0, True)
sendHex(join(sBmpHeader, ""))
sendHex(join(sBmpInfoHeader, ""))
sendHex(m_sBmpColorMap)
For y = m_iBmpHeight To 1 Step -1
For x = 1 To m_iBmpWidth
sTmpHex = m_aBitmap(y, x)
If sTmpHex = vbNullString Then
sendHex(m_sBgColor)
Else
sendHex(sTmpHex)
End If
Next
sendHex(sBmpEndLine)
Next
Response.Flush
And here is the sendHex() function:
Private Sub sendHex(valHex)
Dim iCntHex
For iCntHex = 1 To len(valHex) Step 2
'Response.BinaryWrite chrB(CByte("&H" & mid(valHex, iCntHex, 2)))
response.Write "&H" & mid(valHex, iCntHex, 2)
Next
End Sub
The Microsoft.XMLDOM has built in converters for bin.base64 and bin.hex. I wrote functions that demonstrate how to use this:
Function TextToBinary(text, dataType)
Dim dom
Set dom = CreateObject("Microsoft.XMLDOM")
dom.loadXML("<HELLO/>")
dom.documentElement.nodeTypedValue = text
dom.documentElement.dataType = dataType
TextToBinary = dom.documentElement.nodeTypedValue
End Function
Function BinaryToText(binary, dataType)
Dim dom
Set dom = CreateObject("Microsoft.XMLDOM")
dom.loadXML("<HELLO/>")
dom.documentElement.dataType = dataType
dom.documentElement.nodeTypedValue = binary
dom.documentElement.removeAttribute("dt:dt")
BinaryToText = dom.documentElement.nodeTypedValue
End Function
Function HexToBase64(strHex)
HexToBase64 = BinaryToText(TextToBinary(strHex, "bin.hex"), "bin.base64")
End Function
Function Base64ToHex(strBase64)
Base64ToHex = BinaryToText(TextToBinary(strBase64, "bin.base64"), "bin.hex")
End Function
Here's an example of their usage:
MsgBox HexToBase64("41")
MsgBox Base64ToHex("QQ==")
Also look at the ADODB.Stream as a means of working with binary files. It'll work with these routines.
I was able to get this working. Here is how.
In sendHex, I removed the &H portion, and wrapped my string in hex():
Private Sub sendHex(valHex)
Dim iCntHex
For iCntHex = 1 To len(valHex) Step 2
If len( mid(valHex, iCntHex, 2)) = 1 Then
response.write "0"
end if
response.write mid(valHex, iCntHex, 2)
Next
End Sub
This results in a string output like this (in byte strings of 2 hexidecimal chars):
424d1e050000000000003e00000028000000340000001800000001000
I can then dump that proper hex string into a HEX to base64 function as follows (not written by me, but rather, by Richard Mueller - http://www.rlmueller.net/Base64.htm)
Function HexToBase64(strHex)
' Function to convert a hex string into a base64 encoded string.
' Constant B64 has global scope.
Dim lngValue, lngTemp, lngChar, intLen, k, j, strWord, str64, intTerm
intLen = Len(strHex)
' Pad with zeros to multiple of 3 bytes.
intTerm = intLen Mod 6
If (intTerm = 4) Then
strHex = strHex & "00"
intLen = intLen + 2
End If
If (intTerm = 2) Then
strHex = strHex & "0000"
intLen = intLen + 4
End If
' Parse into groups of 3 hex bytes.
j = 0
strWord = ""
HexToBase64 = ""
For k = 1 To intLen Step 2
j = j + 1
strWord = strWord & Mid(strHex, k, 2)
If (j = 3) Then
' Convert 3 8-bit bytes into 4 6-bit characters.
lngValue = CCur("&H" & strWord)
lngTemp = Fix(lngValue / 64)
lngChar = lngValue - (64 * lngTemp)
str64 = Mid(B64, lngChar + 1, 1)
lngValue = lngTemp
lngTemp = Fix(lngValue / 64)
lngChar = lngValue - (64 * lngTemp)
str64 = Mid(B64, lngChar + 1, 1) & str64
lngValue = lngTemp
lngTemp = Fix(lngValue / 64)
lngChar = lngValue - (64 * lngTemp)
str64 = Mid(B64, lngChar + 1, 1) & str64
str64 = Mid(B64, lngTemp + 1, 1) & str64
HexToBase64 = HexToBase64 & str64
j = 0
strWord = ""
End If
Next
' Account for padding.
If (intTerm = 4) Then
HexToBase64 = Left(HexToBase64, Len(HexToBase64) - 1) & "="
End If
If (intTerm = 2) Then
HexToBase64 = Left(HexToBase64, Len(HexToBase64) - 2) & "=="
End If
End Function
This converts the above to base64, and I can use the output like this (e.g. in a browser url bar) to view it as an image:
data:image/bmp;base64,Qk0eBQAAAAAAAD4AAAAo...

Resources