Πέμπτη, 15 Φεβρουαρίου 2018

Base64 Using Crypt32 in M2000 (rev 4)

This is an example of using functions of Windows to perform Base64 convertion for data. This code can run in Wine, Linux, but we can't use CRYPT_STRING_BASE64HEADER for CryptBinaryToString, so we turn it to
CRYPT_STRING_BASE64 (0x1)

We use Buffer, a special object which hold memory block, and return addresses to be used as pointers

We make module a from console typing Edit a and copy this:


Declare CryptStringToBinary Lib "Crypt32.CryptStringToBinaryW" {pszString$, Long cchString, Long dwFlags, Long pbBinary, Long pcbBinary, Long pdwSkip, long pdwFlags}
Declare CryptBinaryToString Lib "Crypt32.CryptBinaryToStringW" {Long pbBinary, Long cbBinary, Long dwFlags, Long pszString, Long pcchString}

Buffer Clear Buf1 as integer*1000
\\ Buf2 for output delcared after evaluation of output length
Buffer Clear Buf3 as Long

A$={Hello There, this is M2000 Interpreter,
            Yes No
            Hello There too
            Anything
            }
LengthInTchars=Len(A$)*2 ' as 2 bytes
Return Buf1, 0:=A$
CRYPT_STRING_BASE64HEADER=0x0
If IsWine then CRYPT_STRING_BASE64HEADER=0x1 ' no header - Wine has fault
\\ read length for output buffer
Print CryptBinaryToString(Buf1(0), LengthInTchars, CRYPT_STRING_BASE64HEADER, 0, Buf3(0))
Print Eval(Buf3, 0)
Buffer Clear Buf2 as Integer*Eval(Buf3, 0)
Print CryptBinaryToString(Buf1(0), LengthInTchars, CRYPT_STRING_BASE64HEADER, Buf2(0), Buf3(0))
ClipBoard Eval$(Buf2, 0, Eval(Buf3, 0)*2)
Report Eval$(Buf2, 0, Eval(Buf3, 0)*2)+"_Next Line_"    ' third parameter is size in bytes
M$=Eval$(Buf2, 0, Eval(Buf3, 0)*2)
Clear Buf1
Rem 1 : Print Len(Buf1) , " len is 0", Buf1(0)=0 ' is null
Buffer Clear Buf1 as integer*1000 ' now Buf1 cleared
Rem 2 : Print Len(Buf1) , " len is 2000", Buf1(0) ' is not null
Clear Buf3
Buffer Clear Buf3 as Long
Return Buf3, 0:=1000*2 ' number of bytes
Print CryptStringToBinary(M$, Len(M$), CRYPT_STRING_BASE64HEADER, Buf1(0), Buf3(0), 0,0)
Report Eval$(Buf1, 0,Eval(Buf3,0)*2)+"_Next Line_"


The above module make in buf2 the convertion the convertion of buf1 binary data. Here out data are text, but can be anything. So we place text in Buf1 and first we call CryptBinaryToString() to get the length of output buffer. So we define Buf2 as output buffer. And then we call again
CryptBinaryToString() and we get the result. We place result to clipboard for later use and we print the result to console. After that we clear buffers buf1 and buf3 and make the reverse operation.

We can make a second module, say b, using edit b and place this code:

Declare CryptStringToBinary Lib "Crypt32.CryptStringToBinaryW" {pszString$, Long cchString, Long dwFlags, Long pbBinary, Long pcbBinary, Long pdwSkip, long pdwFlags}
const CRYPT_STRING_BASE64HEADER=0x0


A$={-----BEGIN CERTIFICATE-----
SABlAGwAbABvACAAVABoAGUAcgBlACwAIAB0AGgAaQBzACAAaQBzACAATQAyADAA
MAAwACAASQBuAHQAZQByAHAAcgBlAHQAZQByACwADQAKAFkAZQBzACAATgBvAA0A
CgBIAGUAbABsAG8AIABUAGgAZQByAGUAIAB0AG8AbwANAAoAQQBuAHkAdABoAGkA
bgBnAA0ACgA=
-----END CERTIFICATE-----
}
Buffer Clear Buf1 as integer*1000
Buffer Clear Buf3 as Long
Return Buf3, 0:=1000*2 ' number of bytes
\\ CryptStringToBinary() return 1 or 0. Not 0 is true for M2000
If CryptStringToBinary(A$, Len(A$), CRYPT_STRING_BASE64HEADER, Buf1(0), Buf3(0), 0,0) Then {
      Report Eval$(Buf1, 0,Eval(Buf3,0))  ' has wrong *2 in rev<4
}


For the above code we make a paste from clipboard and place Base64 string in A$. So we can make them back as binary data, and finally the string as for this example.


Use these functions in your program


Function StringToBase64$(A$) {
      If Len(A$)=0 then Error "Empty String"
      Declare CryptBinaryToString Lib "Crypt32.CryptBinaryToStringW" {Long pbBinary, Long cbBinary, Long dwFlags, Long pszString, Long pcchString}
      Const CRYPT_STRING_BASE64=0x1
      Long LengthInBytes=Len(A$)*2
      Buffer Clear Buf1 as integer*Len(A$) ' integer has 2 bytes
      Buffer Clear Buf2 as Long ' say 4 bytes but for unsigned long
      Return Buf1, 0:=A$ ' set buffer with string bytes at offset 0
      if CryptBinaryToString(Buf1(0), LengthInBytes, CRYPT_STRING_BASE64, 0, Buf2(0)) then {
            ' So now we count the size of third buffer
            Buffer Clear Buf3 as Integer*Eval(Buf2, 0) ' we peek value from Buf2 as unsigned long
            if CryptBinaryToString(Buf1(0), LengthInBytes, CRYPT_STRING_BASE64, Buf3(0), Buf2(0)) then {
                  =Eval$(Buf3, 0, Eval(Buf2, 0)*2) ' so now we read Utf-16LE from offset 0 for Eval(Buf2, 0)*2 butes
            }
      }
}


Function Base64toString$(A$) {
      Declare CryptStringToBinary Lib "Crypt32.CryptStringToBinaryW" {pszString$, Long cchString, Long dwFlags, Long pbBinary, Long pcbBinary, Long pdwSkip, long pdwFlags}
      Const CRYPT_STRING_BASE64=0x1
      Buffer Clear Buf1 as integer*Len(A$)*2 ' bigger 2 times buffer
      Buffer Clear Buf2 as Long
      Long LengthInTchars=Len(A$)
      Return Buf2, 0:=LengthInTchars*2
      If CryptStringToBinary(A$, LengthInTchars, CRYPT_STRING_BASE64, Buf1(0), Buf2(0), 0,0) then {
                  = Eval$(Buf1, 0,Eval(Buf2,0))
      } Else Error "No valid string"
}

Remove "Crypt32"  ' We have to use same case for letters, as in declare, so "CRYPT32" not free the dll

Με ελληνικές εντολές:


Όρισε Βάση64σεΔυαδικό Από "Crypt32.CryptStringToBinaryW" {pszString$, Μακρύς cchString, Μακρύς dwFlags, Μακρύς pbBinary, Μακρύς pcbBinary, Μακρύς pdwSkip, Μακρύς pdwFlags}
Όρισε ΔυαδικόσεΒάση64 Από "Crypt32.CryptBinaryToStringW" {Μακρύς pbBinary, Μακρύς cbBinary, Μακρύς dwFlags, Μακρύς pszString, Μακρύς pcchString}

Διάρθρωση κενή Μνήμη1 ως Ακέραιος*1000
Διάρθρωση κενή Μνήμη3 ως Μακρύς
α$={Γεια χαρά. Αυτός είναι ο διερμηνευτής Μ2000
            Ναι Όχι
            Γεια χαρά επίσης!
            Οτιδήποτε
            }
ΜήκοςσεTchars=Μήκος(α$)*2 ' επί 2 για να τα κάνουμε ψηφία μνήμης (bytes)
Επιστροφή Μνήμη1, 0:=α$
CRYPT_STRING_BASE64HEADER=0x0
Αν IsWine Τότε CRYPT_STRING_BASE64HEADER=0x1 ' χωρίς επικεφαλίδα - Wine 1.8 έχει πρόβλημα
\\ εύρεση μήκους για να φτιάξουμε το μήκος της Διάρθρωσης για εξαγωγή.
\\ το Μνήμη3(0) είναι η διεύθυνση του Μακρύ (ο δείκτης του)
Τύπωσε ΔυαδικόσεΒάση64(Μνήμη1(0), ΜήκοςσεTchars, CRYPT_STRING_BASE64HEADER, 0, Μνήμη3(0))
\\ το Εκφρ(Μνήμη3, 0) διαβάζει το μακρύ ως αριθμό 32Bit  χωρίς πρόσημο.
Τύπωσε Εκφρ(Μνήμη3, 0)
Διάρθρωση κενή Μνήμη2 ως Ακέραιος*Εκφρ(Μνήμη3, 0)
Τύπωσε ΔυαδικόσεΒάση64(Μνήμη1(0), ΜήκοςσεTchars, CRYPT_STRING_BASE64HEADER, Μνήμη2(0), Μνήμη3(0))
\\ εδώ το γράφουμε στο πρόχειρο
Πρόχειρο Εκφρ$(Μνήμη2, 0, Εκφρ(Μνήμη3, 0)*2)
\\ η τρίτη παράμετρος έχει το μήκος σε ψηφία μνήμης (Bytes), άρα οι χαρακτήρες επί δύο
\\ κάθε χαρακτήρας είναι δυο ψηφία (bytes), ισοδυναμή με έναν ακέραιο (μνήμης).
Αναφορά Εκφρ$(Μνήμη2, 0, Εκφρ(Μνήμη3, 0)*2)+"_Επόμενη Γραμμή_"
M$=Εκφρ$(Μνήμη2, 0, Εκφρ(Μνήμη3, 0)*2)
Καθαρό Μνήμη1
Σημ 1 : Τύπωσε Μήκος(Μνήμη1) , " Μήκος είναι 0", Μνήμη1(0)=0 ' σημαίνει ότι δεν έχει καθόλου μνήμη
Διάρθρωση κενή Μνήμη1 ως Ακέραιος*1000 ' τώρα η Μνήμη1καθάρισε
Σημ 2 : Τύπωσε Μήκος(Μνήμη1) , " len is 2000", Μνήμη1(0)
Καθαρό Μνήμη3
Διάρθρωση κενή Μνήμη3 ως Μακρύς
Επιστροφή Μνήμη3, 0:=1000*2 ' αριθμός σε ψηφία μνήμης (bytes)
Τύπωσε Βάση64σεΔυαδικό(M$, Μήκος(M$), CRYPT_STRING_BASE64HEADER, Μνήμη1(0), Μνήμη3(0), 0,0)
Αναφορά Εκφρ$(Μνήμη1, 0,Εκφρ(Μνήμη3,0))+"_Επόμενη Γραμμή_"