Page 1 of 1
Cipher usage
Posted: Tue Sep 15, 2015 6:51 pm
by Erich
Let's say I want to use AES 256. So I first need to securely hash the passphrase to a 32 byte memory area. There are different key derivation scheme, usually this is done iteratively (e.g. 1024 times). But SHA1Fingerprint hashes to a 40 character long hex string!
Okay, so SHA1 is broken anyway. But the problem is that any version of SHA2 or SHA3 for PB I've found produces hex string output, too!
Does somebody have a cryptographically secure hash function that outputs to raw memory so it can be used as a key for AES? An implementation that passes the test vectors?
Re: Cipher usage
Posted: Tue Sep 15, 2015 7:25 pm
by firace
Don't know if someone has that, but in the meantime, here's a quick'n'dirty way to "poke" the hex string to a raw buffer. So you convert the hex string back to a raw buffer at each iteration. Of course it adds an unnecessary step, but it gets the job done
EDIT: Or, you could perhaps just hash the hex string itself each time. I think it would be just as secure for this purpose (albeit not really "by the book")...
Code: Select all
x = AllocateMemory(16)
r$ = "AB56B4D92B40713ACC5AF89985D4B786" ; just an arbitrary hex string for testing
For i = 0 To Len(r$) : pokea(@X+i, Val("$"+PeekS(@R$ + i*4 ,2)) ) : Next
debug r$
debug hex(peeka(@x))
debug hex(peeka(@x+1))
debug hex(peeka(@x+2))
debug hex(peeka(@x+3))
Re: Cipher usage
Posted: Tue Sep 15, 2015 7:42 pm
by netmaestro
Erich wrote:Does somebody have a cryptographically secure hash function that outputs to raw memory so it can be used as a key for AES?
There's a native one:
PureBasic Doc Example for CryptRandomData() wrote:
Syntax
Result = CryptRandomData(*Buffer, Length)
Description
Fills the specified memory buffer with random data from the cryptographic safe pseudorandom number generator.
Parameters
*Buffer The buffer to fill.
Length The size of the buffer in bytes.
Return value
Returns nonzero if the random data was generated successfully and zero otherwise.
Remarks
The generator has to be opened first with the OpenCryptRandom() command.
To generate random data from the faster but not cryptographic safe pseudorandom number generator, use the RandomData() function.
Example
*Key = AllocateMemory(16)
If OpenCryptRandom() And *Key
CryptRandomData(*Key, 16)
Text$ = "Generated Key:"
For i = 0 To 15
Text$ + " " + RSet(Hex(PeekB(*Key+i), #PB_Byte), 2, "0")
Next i
CloseCryptRandom()
Else
Text$ = "Key generation is not available"
EndIf
MessageRequester("Example", Text$)
See Also
OpenCryptRandom(), CryptRandom(), CloseCryptRandom() RandomData()
Supported OS
All
Re: Cipher usage
Posted: Tue Sep 15, 2015 7:49 pm
by Erich
CryptRandomData is not a hash function, it useful for creating an initialization vector, but can be used for a key only if you have a safe device to store it on -- even then I'd rather password protect it. You have to hash and keystretch the user-supplied passphrase into a key to correctly use the cipher.
I guess I'll have to resort to converting from hex to memory like firace has suggested. Anyway, the API has it weirdly backwards, IMHO.
Re: Cipher usage
Posted: Wed Sep 16, 2015 10:13 pm
by Crusiatus Black
I agree it's a bit backwards, but a workaround is quite simple indeed:
Code: Select all
Structure RAW_SHA1
state.a[20]
EndStructure
Procedure SHA1FingerprintRaw(*lpBuffer, cbBufferSize.i, *hash.RAW_SHA1)
Protected szHash.s = SHA1Fingerprint(*lpBuffer, cbBufferSize)
For i = 0 To (SizeOf(RAW_SHA1) - 1)
*hash\state[i] = Val("$" + Mid(szHash, (1 + (i * 2)), 2))
Next
EndProcedure
Define result.RAW_SHA1
SHA1FingerprintRaw(@"bas", 3, @result)
For i = 0 To (SizeOf(RAW_SHA1) - 1)
Debug result\state[i]
Next
Place any generator in there. There should be plenty resources online that provide you with SHA1, 256 etc solutions that produce raw hashes after the Finalize routine. They might be in the form of static / dynamic libraries compiled in c/c++ environments, however there is plenty source code available for SH algorithms to work with.
If that's too time consuming, the workaround should solve the problem.
*edit* the code above is for Ascii, but unicode shouldn't be too much trouble
Re: Cipher usage
Posted: Thu Sep 17, 2015 2:11 pm
by Erich
Yes, converting back is fast enough for my purposes. I'm actually using a hash table like so:
Code: Select all
Global NewMap hx.i()
hx("00")=0
hx("01")=1
hx("02")=2
hx("03")=3
hx("04")=4
hx("05")=5
hx("06")=6
hx("07")=7
hx("08")=8
hx("09")=9
hx("0a")=10
hx("0b")=11
hx("0c")=12
hx("0d")=13
hx("0e")=14
hx("0f")=15
hx("10")=16
hx("11")=17
hx("12")=18
hx("13")=19
hx("14")=20
hx("15")=21
hx("16")=22
hx("17")=23
hx("18")=24
hx("19")=25
hx("1a")=26
hx("1b")=27
hx("1c")=28
hx("1d")=29
hx("1e")=30
hx("1f")=31
hx("20")=32
hx("21")=33
hx("22")=34
hx("23")=35
hx("24")=36
hx("25")=37
hx("26")=38
hx("27")=39
hx("28")=40
hx("29")=41
hx("2a")=42
hx("2b")=43
hx("2c")=44
hx("2d")=45
hx("2e")=46
hx("2f")=47
hx("30")=48
hx("31")=49
hx("32")=50
hx("33")=51
hx("34")=52
hx("35")=53
hx("36")=54
hx("37")=55
hx("38")=56
hx("39")=57
hx("3a")=58
hx("3b")=59
hx("3c")=60
hx("3d")=61
hx("3e")=62
hx("3f")=63
hx("40")=64
hx("41")=65
hx("42")=66
hx("43")=67
hx("44")=68
hx("45")=69
hx("46")=70
hx("47")=71
hx("48")=72
hx("49")=73
hx("4a")=74
hx("4b")=75
hx("4c")=76
hx("4d")=77
hx("4e")=78
hx("4f")=79
hx("50")=80
hx("51")=81
hx("52")=82
hx("53")=83
hx("54")=84
hx("55")=85
hx("56")=86
hx("57")=87
hx("58")=88
hx("59")=89
hx("5a")=90
hx("5b")=91
hx("5c")=92
hx("5d")=93
hx("5e")=94
hx("5f")=95
hx("60")=96
hx("61")=97
hx("62")=98
hx("63")=99
hx("64")=100
hx("65")=101
hx("66")=102
hx("67")=103
hx("68")=104
hx("69")=105
hx("6a")=106
hx("6b")=107
hx("6c")=108
hx("6d")=109
hx("6e")=110
hx("6f")=111
hx("70")=112
hx("71")=113
hx("72")=114
hx("73")=115
hx("74")=116
hx("75")=117
hx("76")=118
hx("77")=119
hx("78")=120
hx("79")=121
hx("7a")=122
hx("7b")=123
hx("7c")=124
hx("7d")=125
hx("7e")=126
hx("7f")=127
hx("80")=128
hx("81")=129
hx("82")=130
hx("83")=131
hx("84")=132
hx("85")=133
hx("86")=134
hx("87")=135
hx("88")=136
hx("89")=137
hx("8a")=138
hx("8b")=139
hx("8c")=140
hx("8d")=141
hx("8e")=142
hx("8f")=143
hx("90")=144
hx("91")=145
hx("92")=146
hx("93")=147
hx("94")=148
hx("95")=149
hx("96")=150
hx("97")=151
hx("98")=152
hx("99")=153
hx("9a")=154
hx("9b")=155
hx("9c")=156
hx("9d")=157
hx("9e")=158
hx("9f")=159
hx("a0")=160
hx("a1")=161
hx("a2")=162
hx("a3")=163
hx("a4")=164
hx("a5")=165
hx("a6")=166
hx("a7")=167
hx("a8")=168
hx("a9")=169
hx("aa")=170
hx("ab")=171
hx("ac")=172
hx("ad")=173
hx("ae")=174
hx("af")=175
hx("b0")=176
hx("b1")=177
hx("b2")=178
hx("b3")=179
hx("b4")=180
hx("b5")=181
hx("b6")=182
hx("b7")=183
hx("b8")=184
hx("b9")=185
hx("ba")=186
hx("bb")=187
hx("bc")=188
hx("bd")=189
hx("be")=190
hx("bf")=191
hx("c0")=192
hx("c1")=193
hx("c2")=194
hx("c3")=195
hx("c4")=196
hx("c5")=197
hx("c6")=198
hx("c7")=199
hx("c8")=200
hx("c9")=201
hx("ca")=202
hx("cb")=203
hx("cc")=204
hx("cd")=205
hx("ce")=206
hx("cf")=207
hx("d0")=208
hx("d1")=209
hx("d2")=210
hx("d3")=211
hx("d4")=212
hx("d5")=213
hx("d6")=214
hx("d7")=215
hx("d8")=216
hx("d9")=217
hx("da")=218
hx("db")=219
hx("dc")=220
hx("dd")=221
hx("de")=222
hx("df")=223
hx("e0")=224
hx("e1")=225
hx("e2")=226
hx("e3")=227
hx("e4")=228
hx("e5")=229
hx("e6")=230
hx("e7")=231
hx("e8")=232
hx("e9")=233
hx("ea")=234
hx("eb")=235
hx("ec")=236
hx("ed")=237
hx("ee")=238
hx("ef")=239
hx("f0")=240
hx("f1")=241
hx("f2")=242
hx("f3")=243
hx("f4")=244
hx("f5")=245
hx("f6")=246
hx("f7")=247
hx("f8")=248
hx("f9")=249
hx("fa")=250
hx("fb")=251
hx("fc")=252
hx("fd")=253
hx("fe")=254
hx("ff")=255
hx("0A")=10
hx("0B")=11
hx("0C")=12
hx("0D")=13
hx("0E")=14
hx("0F")=15
hx("1A")=26
hx("1B")=27
hx("1C")=28
hx("1D")=29
hx("1E")=30
hx("1F")=31
hx("2A")=42
hx("2B")=43
hx("2C")=44
hx("2D")=45
hx("2E")=46
hx("2F")=47
hx("3A")=58
hx("3B")=59
hx("3C")=60
hx("3D")=61
hx("3E")=62
hx("3F")=63
hx("4A")=74
hx("4B")=75
hx("4C")=76
hx("4D")=77
hx("4E")=78
hx("4F")=79
hx("5A")=90
hx("5B")=91
hx("5C")=92
hx("5D")=93
hx("5E")=94
hx("5F")=95
hx("6A")=106
hx("6B")=107
hx("6C")=108
hx("6D")=109
hx("6E")=110
hx("6F")=111
hx("7A")=122
hx("7B")=123
hx("7C")=124
hx("7D")=125
hx("7E")=126
hx("7F")=127
hx("8A")=138
hx("8B")=139
hx("8C")=140
hx("8D")=141
hx("8E")=142
hx("8F")=143
hx("9A")=154
hx("9B")=155
hx("9C")=156
hx("9D")=157
hx("9E")=158
hx("9F")=159
hx("A0")=160
hx("A1")=161
hx("A2")=162
hx("A3")=163
hx("A4")=164
hx("A5")=165
hx("A6")=166
hx("A7")=167
hx("A8")=168
hx("A9")=169
hx("AA")=170
hx("AB")=171
hx("AC")=172
hx("AD")=173
hx("AE")=174
hx("AF")=175
hx("B0")=176
hx("B1")=177
hx("B2")=178
hx("B3")=179
hx("B4")=180
hx("B5")=181
hx("B6")=182
hx("B7")=183
hx("B8")=184
hx("B9")=185
hx("BA")=186
hx("BB")=187
hx("BC")=188
hx("BD")=189
hx("BE")=190
hx("BF")=191
hx("C0")=192
hx("C1")=193
hx("C2")=194
hx("C3")=195
hx("C4")=196
hx("C5")=197
hx("C6")=198
hx("C7")=199
hx("C8")=200
hx("C9")=201
hx("CA")=202
hx("CB")=203
hx("CC")=204
hx("CD")=205
hx("CE")=206
hx("CF")=207
hx("D0")=208
hx("D1")=209
hx("D2")=210
hx("D3")=211
hx("D4")=212
hx("D5")=213
hx("D6")=214
hx("D7")=215
hx("D8")=216
hx("D9")=217
hx("DA")=218
hx("DB")=219
hx("DC")=220
hx("DD")=221
hx("DE")=222
hx("DF")=223
hx("E0")=224
hx("E1")=225
hx("E2")=226
hx("E3")=227
hx("E4")=228
hx("E5")=229
hx("E6")=230
hx("E7")=231
hx("E8")=232
hx("E9")=233
hx("EA")=234
hx("EB")=235
hx("EC")=236
hx("ED")=237
hx("EE")=238
hx("EF")=239
hx("F0")=240
hx("F1")=241
hx("F2")=242
hx("F3")=243
hx("F4")=244
hx("F5")=245
hx("F6")=246
hx("F7")=247
hx("F8")=248
hx("F9")=249
hx("FA")=250
hx("FB")=251
hx("FC")=252
hx("FD")=253
hx("FE")=254
hx("FF")=255
Procedure ConvertHexStringToBuffer(s.s, *buff)
Protected.i i
If MemorySize(*buff)<Len(s)/2
ProcedureReturn #False
Else
For i = 1 To Len(s) Step 2
PokeB(*buff+((i-1)/2), hx(Mid(s, i, 2)))
Next
ProcedureReturn #True
EndIf
EndProcedure
Procedure$ ConvertBufferToHexString(*buff)
Protected.s result
Protected.i i
For i = 0 To MemorySize(*buff)-1
result + RSet(LCase(Hex(PeekB(*buff+i), #PB_Byte)), 2, "0")
Next
ProcedureReturn result
EndProcedure
If anybody spots an error, please let me know!

Re: Cipher usage
Posted: Thu Sep 17, 2015 2:33 pm
by infratec
If speed is your concern ...
I'm 100% sure that the stuff with your map takes much longer than a 'standard' conversion.
Needs more RAM, needs more code and and and ...
Bernd
Re: Cipher usage
Posted: Thu Sep 17, 2015 2:43 pm
by Keya
it seems strange how every item maps to... well, itself!
hx("02")=2
hx("03")=3
etc... 512 times! There are too many starving people in the world to do that! you can just do it in realtime. There's probably a million different varieties of this -
(compile in ascii)
Code: Select all
Procedure.s StrToHex(buf, bufsize.i)
If bufsize = 0: ProcedureReturn "": EndIf
Protected i.i, sOut.s, *pchar.ASCII = buf
For i = 0 To bufsize-1
sOut = sOut + RSet(Hex(*pchar\a),2,"0")
*pchar + 1
Next i
ProcedureReturn sOut
EndProcedure
Procedure.s HexToStr(buf.s)
Protected i.i, lenbuf.i, sOut.s
lenbuf = Len(buf)
If lenbuf = 0: ProcedureReturn "": EndIf
For i = 1 To lenbuf Step 2
sOut + Chr(Val("$" + Mid(buf,i,2)))
Next i
ProcedureReturn sOut
EndProcedure
charstr.s = "my buf"
hexstr.s = StrToHex(@charstr, Len(charstr))
Debug("Hex=" + hexstr)
origstr.s = HexToStr(hexstr)
Debug("Str=" + origstr)
Re: Cipher usage
Posted: Thu Sep 17, 2015 2:51 pm
by heartbone
Good stuff.
I truly hope the federal government of the US does not follow through with
making this activity illegal. It would make programming a lot more difficult satisfying government bureaucrats.
The current trend of fear based leadership decisions is not good, and thankfully right now our privacy is still protected, for the most part.
"The Fifth Amendment to the United States Constitution protects witnesses from being forced to incriminate themselves, and there is currently no law regarding key disclosure in the United States. However, the federal case In re Boucher may be influential as case law. In this case, a man's laptop was inspected by customs agents and child pornography was discovered. The device was seized and powered-down, at which point disk encryption technology made the evidence unavailable. The judge held that it was a foregone conclusion that the content exists since it had already been seen by the customs agents, Boucher's encryption password "adds little or nothing to the sum total of the Government's information about the existence and location of files that may contain incriminating information."
In another case, a district court judge ordered a Colorado woman to decrypt her laptop so prosecutors can use the files against her in a criminal case: "I conclude that the Fifth Amendment is not implicated by requiring production of the unencrypted contents of the Toshiba Satellite M305 laptop computer," Colorado U.S. District Judge Robert Blackburn ruled on January 23, 2012. In Commonwealth v. Gelfgatt, the court ordered a suspect to decrypt his computer, citing exception to Fifth Amendment can be invoked because "an act of production does not involve testimonial communication where the facts conveyed already are known to the government...".
However, in United States v. Doe, the United States Court of Appeals for the Eleventh Circuit ruled on 24 February 2012 that forcing the decryption of one's laptop violates the Fifth Amendment.
The Federal Bureau of Investigation may also issue national security letters that require the disclosure of keys for investigative purposes. One company, Lavabit, chose to shut down rather than surrender its master private keys."
Unfortunately there are not too many big players with good ethics like Lavabit.
Keya wrote:it seems strange how every item maps to... well, itself!
hx("02")=2
hx("03")=3
etc... 512 times! There are too many starving people in the world to do that! you can just do it in realtime. There's probably a million different varieties of this -
(compile in ascii)
Code: Select all
Procedure.s StrToHex(buf, bufsize.i)
Procedure.s HexToStr(buf.s)
You beat me to it. Thanks.
Re: Cipher usage
Posted: Thu Sep 17, 2015 4:05 pm
by kenmo
If you really want to use a Map... you can still save 500 lines of code.
Code: Select all
Global NewMap hx.i()
For i = 0 To 255
hx(RSet( Hex(i) , 2, "0")) = i
hx(RSet(LCase(Hex(i)), 2, "0")) = i
Next i
Debug hx("5a")
Debug hx("5A")
But I would not recommend the Map method!
Re: Cipher usage
Posted: Thu Sep 17, 2015 4:31 pm
by GPI
Keya wrote:it seems strange how every item maps to... well, itself!
hx("02")=2
hx("03")=3
etc... 512 times! There are too many starving people in the world to do that! you can just do it in realtime. There's probably a million different varieties of this -
(compile in ascii)
The idea behind his code: It is faster than your routines.
But I would create the map like this:
Code: Select all
Global NewMap hx.i()
For i=0 To 255
hx(LCase(RSet(Hex(i),2,"0")))=i
hx(UCase(RSet(Hex(i),2,"0")))=i
Next
I have written my own version of "hex2mem" - it should be faster than the map-version and only need a 127 byte-array
Code: Select all
Global Dim hx2.a(127)
For i='0' To '9'
hx2(i)=(i-'0')
Next
For i='a' To 'f'
hx2(i)=(i-'a'+10)
Next
For i='A' To 'F'
hx2(i)=(i-'A'+10)
Next
For i=0 To 15
hx2(i)=Asc(Hex(i))
Next
Structure doublechar
c1.c
c2.c
EndStructure
Procedure.s mem2hex(*mem.ascii,memlen)
Protected *hex.doublechar
Protected *pos.doublechar
Protected shex.s
*hex=AllocateMemory(memlen*SizeOf(doublechar)+SizeOf(character))
If *hex
*pos=*hex
While memlen>0
*pos\c1=hx2(*mem\a >>4)
*pos\c2=hx2(*mem\a &$f)
*pos+SizeOf(doublechar)
*mem+1
memlen-1
Wend
shex=PeekS(*hex)
FreeMemory(*hex)
EndIf
ProcedureReturn shex
EndProcedure
Procedure hex2mem(*phex.doublechar,*mem=0,memlen=0)
Protected *pos.ascii
Protected hexlen
hexlen=MemoryStringLength(*phex)
If hexlen & %1
ProcedureReturn 0
EndIf
If *mem=0
memlen=hexlen/2
*mem=AllocateMemory(memlen)
ElseIf memlen=0
memlen=MemorySize(*mem)
EndIf
If memlen>=hexlen/2
*pos=*mem
While *phex\c1>0 And *phex\c2>0
*pos\a=hx2(*phex\c1&$7f)<<4+hx2(*phex\c2&$7f)
*phex+SizeOf(doublechar)
*pos+1
Wend
ProcedureReturn *mem
EndIf
ProcedureReturn 0
EndProcedure
Works in Unicode and Ascii-Mode.
Re: Cipher usage
Posted: Thu Sep 17, 2015 4:41 pm
by Erich
Yo, you guys are right, that was a clearcut case of premature opimization, the root of all evil
This (adopted from someone's post to memory buffer):
Code: Select all
Procedure HexToBuf(buf.s, *buff)
Protected i.i, lenbuf.i
lenbuf = Len(buf)
If lenbuf = 0: ProcedureReturn : EndIf
For i = 1 To lenbuf Step 2
PokeA(*buff+((i-1)/2), Val("$" + Mid(buf,i,2)))
Next i
EndProcedure
Takes around 14700 ms on my machine, whereas my method takes around 15600 ms.
By the way, of course I didn't enter the hash table by hand, I used a loop like GPI did to generate the code for copy&paste. I often generate code like that, but this time it was really unnecessary. My guess is that hardcoded nested select statements could be fastest, but I might be wrong.
Benchmark (my monster map not included again in order not to clutter the forum):
Code: Select all
Procedure HexToBuf(buf.s, *buff)
Protected i.i, lenbuf.i
lenbuf = Len(buf)
If lenbuf = 0: ProcedureReturn : EndIf
For i = 1 To lenbuf Step 2
PokeA(*buff+((i-1)/2), Val("$" + Mid(buf,i,2)))
Next i
EndProcedure
Define *buff = AllocateMemory(1024)
Define.s s
Define.i mt1, mt2
RandomData(*buff, 1024)
s = ConvertBufferToHexString(*buff)
mt1=ElapsedMilliseconds()
For i = 1 To 20000
ConvertHexStringToBuffer(s,*buff)
Next
mt2=ElapsedMilliseconds()
Debug "Method one: "+Str(mt2-mt1)+" ms"
mt1=ElapsedMilliseconds()
For i = 1 To 20000
HexToBuf(s, *buff)
Next
mt2=ElapsedMilliseconds()
Debug "Method two: "+Str(mt2-mt1)+ " ms"
Re: Cipher usage
Posted: Thu Sep 17, 2015 5:02 pm
by Erich
Short update: GPI's hex2mem is the clear winner. ~2600 ms in my benchmark!

Re: Cipher usage
Posted: Thu Sep 17, 2015 5:10 pm
by heartbone
Erich wrote:Short update: GPI's hex2mem is the clear winner. ~2600 ms in my benchmark!

To
GPI,

Good stuff.
Thanks.
Re: Cipher usage
Posted: Thu Sep 17, 2015 8:23 pm
by GPI
Thanks
The Reason why HexToBuf is so slow is: It use a string in the parameter. PB makes then a complete copy of the string for the procedure. When you don't want to change the string, it is better to use a pointer. For Example:
Code: Select all
Procedure HexToBuf(*buf.character, *buff.ascii)
While *buf\c>0
*buff\a= Val("$" +PeekS(*buf,2))
*buf+SizeOf(character)*2
*buff+1
Wend
EndProcedure
My Testcode:
Code: Select all
;*
;* Module misc
;*
;* Version: 1.0
;* Date: 2015-09-17
;*
;* Written by GPI
;*
DeclareModule misc
EnableExplicit
Declare.s mem2hex(*mem,memlen)
Declare hex2mem(*phex,*mem=0,memlen=0)
Macro str2hex(str)
misc::mem2hex(@str,StringByteLength(str))
EndMacro
Declare.s hex2str(*phex)
EndDeclareModule
Module misc
Global Dim HexTable.a(127)
Procedure init()
Protected i
For i='0' To '9'
HexTable(i)=(i-'0')
Next
For i='a' To 'f'
HexTable(i)=(i-'a'+10)
Next
For i='A' To 'F'
HexTable(i)=(i-'A'+10)
Next
For i=0 To 15
HexTable(i)=Asc(Hex(i))
Next
EndProcedure
init()
Structure doublechar
c1.c
c2.c
EndStructure
Procedure.s mem2hex(*mem.ascii,memlen)
Protected *pos.doublechar
Protected shex.s
shex=Space(memlen*2)
*pos=@shex
While memlen>0
*pos\c1=HexTable(*mem\a >>4)
*pos\c2=HexTable(*mem\a &$f)
*pos+SizeOf(doublechar)
*mem+1
memlen-1
Wend
ProcedureReturn shex
EndProcedure
Procedure hex2mem(*phex.doublechar,*mem=0,memlen=0)
Protected *pos.ascii
Protected hexlen
hexlen=MemoryStringLength(*phex)
If hexlen & %1
ProcedureReturn 0
EndIf
If *mem=0
memlen=hexlen/2
*mem=AllocateMemory(memlen)
ElseIf memlen=0
memlen=MemorySize(*mem)
EndIf
If memlen>=hexlen/2
*pos=*mem
While *phex\c1>0 And *phex\c2>0
*pos\a=HexTable(*phex\c1&$7f)<<4+HexTable(*phex\c2&$7f)
*phex+SizeOf(doublechar)
*pos+1
Wend
ProcedureReturn *mem
EndIf
ProcedureReturn 0
EndProcedure
Procedure.s hex2str(*hex.doublechar)
Protected str.s,len
len=MemoryStringLength(*hex)/SizeOf(character)/2
str=Space(len)
hex2mem(*hex,@str,StringByteLength(str))
ProcedureReturn str
EndProcedure
EndModule
CompilerIf #PB_Compiler_IsMainFile
EnableExplicit
Procedure HexToBufOld(buf.s, *buff)
Protected i.i, lenbuf.i
lenbuf = Len(buf)
If lenbuf = 0: ProcedureReturn : EndIf
For i = 1 To lenbuf Step 2
PokeA(*buff+((i-1)/2), Val("$" + Mid(buf,i,2)))
Next i
EndProcedure
Procedure HexToBuf(*buf.character, *buff.ascii)
While *buf\c>0
*buff\a= Val("$" +PeekS(*buf,2))
*buf+SizeOf(character)*2
*buff+1
Wend
EndProcedure
Define *buf = AllocateMemory(1024)
Define *buf2
Define.s s
Define time
Define i
OpenConsole()
RandomData(*buf, 1024)
time=ElapsedMilliseconds()
For i=1 To 20000
s=MISC::mem2hex(*buf,1024)
Next
time-ElapsedMilliseconds()
PrintN(s)
PrintN("mem2hex Time:"+Str(-time)+"ms")
time=ElapsedMilliseconds()
For i=1 To 20000
*buf2=MISC::hex2mem(@s,*buf2)
Next
time-ElapsedMilliseconds()
PrintN("hex2mem Time:"+Str(-time)+"ms")
If CompareMemory(*buf,*buf2,1024)
PrintN("OK")
Else
PrintN("DIFF!!!")
EndIf
FillMemory(*buf2,1024)
time=ElapsedMilliseconds()
For i=1 To 20000
HexToBuf(@s,*buf2)
Next
time-ElapsedMilliseconds()
PrintN("HexToBuf Time:"+Str(-time)+"ms")
If CompareMemory(*buf,*buf2,1024)
PrintN("OK")
Else
PrintN("DIFF!!!")
EndIf
FillMemory(*buf2,1024)
time=ElapsedMilliseconds()
For i=1 To 20000
HexToBufOld(s,*buf2)
Next
time-ElapsedMilliseconds()
PrintN("HexToBufOld Time:"+Str(-time)+"ms")
If CompareMemory(*buf,*buf2,1024)
PrintN("OK")
Else
PrintN("DIFF!!!")
EndIf
PrintN("")
PrintN("end")
Input()
CompilerEndIf
with this results:
Code: Select all
mem2hex Time:208ms
hex2mem Time:80ms
HexToBuf Time:678ms
HexToBufOld Time:7016ms
Important: Disable the debugger! And the code is unicode and ascii.
Btw. and OT: I like the "code-competition" - how to make a code smaller or faster - maybe has someone an another code (in a new thread of course)? It is also fun to see, how diffrent persons solve the same problem.