Cipher usage

Just starting out? Need help? Post your questions and find answers here.
User avatar
Erich
User
User
Posts: 49
Joined: Thu Sep 30, 2010 9:21 pm

Cipher usage

Post 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! :oops:

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?
"I have never let my schooling interfere with my education." - Mark Twain
firace
Addict
Addict
Posts: 946
Joined: Wed Nov 09, 2011 8:58 am

Re: Cipher usage

Post 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))

User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Cipher usage

Post 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
BERESHEIT
User avatar
Erich
User
User
Posts: 49
Joined: Thu Sep 30, 2010 9:21 pm

Re: Cipher usage

Post 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.
"I have never let my schooling interfere with my education." - Mark Twain
User avatar
Crusiatus Black
Enthusiast
Enthusiast
Posts: 389
Joined: Mon May 12, 2008 1:25 pm
Location: The Netherlands
Contact:

Re: Cipher usage

Post 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
Image
Bas Groothedde,
Imagine Programming

I live in a philosophical paradoxal randome filled with enigma's!
User avatar
Erich
User
User
Posts: 49
Joined: Thu Sep 30, 2010 9:21 pm

Re: Cipher usage

Post 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! :D
"I have never let my schooling interfere with my education." - Mark Twain
infratec
Always Here
Always Here
Posts: 7584
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Cipher usage

Post 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
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: Cipher usage

Post 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)
User avatar
heartbone
Addict
Addict
Posts: 1058
Joined: Fri Apr 12, 2013 1:55 pm
Location: just outside of Ferguson

Re: Cipher usage

Post by heartbone »

Good stuff. :D

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.
Keep it BASIC.
User avatar
kenmo
Addict
Addict
Posts: 2033
Joined: Tue Dec 23, 2003 3:54 am

Re: Cipher usage

Post 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!
GPI
PureBasic Expert
PureBasic Expert
Posts: 1394
Joined: Fri Apr 25, 2003 6:41 pm

Re: Cipher usage

Post 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.
User avatar
Erich
User
User
Posts: 49
Joined: Thu Sep 30, 2010 9:21 pm

Re: Cipher usage

Post 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"
"I have never let my schooling interfere with my education." - Mark Twain
User avatar
Erich
User
User
Posts: 49
Joined: Thu Sep 30, 2010 9:21 pm

Re: Cipher usage

Post by Erich »

Short update: GPI's hex2mem is the clear winner. ~2600 ms in my benchmark! :)
User avatar
heartbone
Addict
Addict
Posts: 1058
Joined: Fri Apr 12, 2013 1:55 pm
Location: just outside of Ferguson

Re: Cipher usage

Post by heartbone »

Erich wrote:Short update: GPI's hex2mem is the clear winner. ~2600 ms in my benchmark! :)
To GPI,
Image
Good stuff.
Thanks.
Keep it BASIC.
GPI
PureBasic Expert
PureBasic Expert
Posts: 1394
Joined: Fri Apr 25, 2003 6:41 pm

Re: Cipher usage

Post 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.
Post Reply