![]() |
Forum Index : Microcontroller and PC projects : SHA-1 Hashing & base64 Encoding Function
Author | Message | ||||
HardingJohn![]() Regular Member ![]() Joined: 28/07/2017 Location: AustraliaPosts: 78 |
The following code applies the SHA-1 hashing function, and then encodes the result using base64. I wrote it as part of a websocket server in a much larger program running on the ARMite H7. The problem is that it takes a long time to complete even at 400Mhz. Would it be possible to provide this as a Micromite function due to Cfunction support not being available? Users might want to utilise the SHA-1 hashing function and base64 conversion separately so feel free to split the ServerKey$ function from the base64 conversion(encode_in$ encode_out$) function ServerKey$(message$) message$ = message$ + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" h0% = &H67452301 h1% = &HEFCDAB89 h2% = &H98BADCFE h3% = &H10325476 h4% = &HC3D2E1F0 n% = &H1 l% = LEN(message$)*8 message$ = message$ + CHR$(&H80) do WHILE (LEN(message$) MOD 64) <> 56 message$ = message$ + CHR$(0) loop FOR i% = 1 to 15 step 2 message$ = message$ + CHR$(VAL("&H" + mid$(hex$(l%,16), i%, 2))) NEXT i% FOR j% = 0 TO (LEN(message$) \ 64) -1 for i% = 0 to 15 BigEndian$ = "" for m% = 1 to 4 BigEndian$ = BigEndian$ + Hex$(asc(mid$(message$, m% + (j%*64) + (i%*4), 1)),2) next m% w%(i%+1) = val("&H" + BigEndian$) next i% FOR i% = 17 TO 80 w%(i%) = w%(i%-3) XOR w%(i%-8) XOR w%(i%-14) XOR w%(i%-16) w%(i%) = Bit32ShiftLeft%(w%(i%), 1) OR Bit32ShiftRight%(w%(i%), 31) NEXT i% a% = h0% b% = h1% c% = h2% d% = h3% e% = h4% FOR i% = 0 TO 79 if i% <= 19 then f% = d% xor (b% and (c% xor d%)) k% = &H5A827999 else if i% <= 39 then f% = b% XOR c% XOR d% k% = &H6ED9EBA1 end if end if if i% <= 59 then if i% > 39 then f% = ((b% and c%) + (d% and (b% xor c%))) mod &H100000000 k% = &H8F1BBCDC end if else if i% <= 79 then f% = b% XOR c% XOR d% k% = &HCA62C1D6 end if end if t% = ((Bit32ShiftLeft%(a%, 5) OR Bit32ShiftRight%(a%, 27))+ f% + e% + k% + w%(i%+1)) mod &H100000000 e% = d% d% = c% c% = Bit32ShiftLeft%(b%, 30) OR Bit32ShiftRight%(b%, 2) b% = a% a% = t% NEXT i% h0% = (h0% + a%) mod &H100000000 h1% = (h1% + b%) mod &H100000000 h2% = (h2% + c%) mod &H100000000 h3% = (h3% + d%) mod &H100000000 h4% = (h4% + e%) mod &H100000000 NEXT j% encode_in$ = hex$(h0%,8) + hex$(h1%,8) + hex$(h2%,8) + hex$(h3%,8) + hex$(h4%,8) encode_ref$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" encode_in$ = encode_in$ + "00" binary$ = "" for x% = 1 to 42 step 2 binary$ = binary$ + bin$(val("&H" + mid$(encode_in$, x%, 2)),8) next x% encode_out$ = "" FOR encode_part% = 1 TO 160 step 6 encode_sixbitval% = val("&B" + mid$(binary$, (encode_part%), 6)) encode_out$ = encode_out$ + MID$(encode_ref$, encode_sixbitval%+1, 1) NEXT encode_part% ServerKey$ = encode_out$ + "=" end function function Bit32ShiftRight%(value%, Num%) pad$ = "" for z% = 1 to Num% pad$ = pad$ + "0" next z% Bit32ShiftRight% = val("&B"+pad$+left$(bin$(value%,32),32-Num%)) end function function Bit32ShiftLeft%(value%, Num%) pad$ = "" for z% = 1 to Num% pad$ = pad$ + "0" next z% Bit32ShiftLeft% = val("&B"+right$(bin$(value%,32),32-Num%)+Pad$) end function Just know enough to get me in trouble, but not quite enough to get me out. |
||||
CaptainBoing![]() Guru ![]() Joined: 07/09/2016 Location: United KingdomPosts: 2170 |
Morning John. you are well I trust? I have a passing interest in hashing and encrypt/coding so thanks for the above. When you say it takes a "long time" I appreciate this is probably relative - could you provide any actual timings? I converted some Base64 en/decode routines from VB versions I have had for years. If you are interetsted you can find them in the library here I also have some VB for SHA256 hashing but I never converted this to MMBasic, maybe I should and put it in the library too - would you consider adding your SHA1 algorithm as well? just to cover the bases. I have also written RC4 en/decryption functions. RC4 is deprecated but still provides a decent level of privacy from all but the most determined hackers. I use this in 433MHz radio comms but the smaller micromites do take a while - I found that on longer strings it was difficult to keep within a 1.5 second cycle time, hence I also wrote a simpler rotating XOR encryption which I just added (thought I had done it a while back ![]() |
||||
HardingJohn![]() Regular Member ![]() Joined: 28/07/2017 Location: AustraliaPosts: 78 |
I have yet to time it, but it holds up my main loop for maybe as long as second. It would be so good to be able to use CFunctions with the ARMmite H7, so this function could be completed in negligible time. If SHA-1 hashing algorithm could be added to the inbuilt functions of ARMmite H7 firmware this would be greatly appreciated. I do appreciate that this takes some effort and the question will of course arise, how many users will benefit?? Happy to add the MMbasic version I have written, however it probably could do with improvements by a more capable programmer. I should really re-write it using the bit shift >> operators, which might shave a mS or two off, but the real issue is that hashing takes a lot of processing and will never be done at speed using MMbasic. I am happy to re-write it in C to reduce the work load in placing it inside the ARMmite Firmware, but SHA-1 hashing should be readily available in C already. Just know enough to get me in trouble, but not quite enough to get me out. |
||||
HardingJohn![]() Regular Member ![]() Joined: 28/07/2017 Location: AustraliaPosts: 78 |
I timed the code to do the SHA-1 and base64 on the following key "x3JJHMbDL1EzLkh9GBhXDw==" The result is correct "HSmrc0sMlYUkAGmm5OPpG2HaGWk=" This server key generation is an example of what is created when a Websocket Server responds to a Websocket connection request from a web client. The time taken was 321 mS as per the timer in MMBasic running on ARM H7 400Mhz This is still a very long time and causes problems with the main loop in my program that can not afford to be held up for this long. Any help with this would be greatly appreciated. I can help with code for the Wiznet 5500 Ethernet Module for serving wages, TCP Modbus, multicasting UDP packets etc, which I have adapted from code originally started by big mick on an earlier Wiznet Chip. Serving Web pages works quite well, especially using Websockets as this allows fast bi-directional data communication between a web client and your web server running on a MMbasic platform. It would be too difficult to setup AJAX on a MMbasic platform I think, so Websockets is the way to go. Once the TCP connection is upgraded to a Websocket, ArrayBuffers can be sent or received allowing a block of variables in the previous Javascript/HTML loaded by your web server to the client, to then be changed at will in both directions. A fast, live, fully interactive web page can be written all served by a Micromite MMBasic device. Just know enough to get me in trouble, but not quite enough to get me out. |
||||
HardingJohn![]() Regular Member ![]() Joined: 28/07/2017 Location: AustraliaPosts: 78 |
Have changed to bit shift operators << >> instead of the dodgy bit32shift functions and it now takes just 45mS to run. Still a bit slow, but a lot better than before. Also separated the two processes for other people to use as they wish. dim w%(80) message$ = "x3JJHMbDL1EzLkh9GBhXDw==" timer = 0 print BASE64$(SHA1$(message$)) print timer end function SHA1$(message$) message$ = message$ + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" h0% = &H67452301 h1% = &HEFCDAB89 h2% = &H98BADCFE h3% = &H10325476 h4% = &HC3D2E1F0 n% = &H1 l% = LEN(message$)*8 message$ = message$ + CHR$(&H80) do WHILE (LEN(message$) MOD 64) <> 56 message$ = message$ + CHR$(0) loop FOR i% = 1 to 15 step 2 message$ = message$ + CHR$(VAL("&H" + mid$(hex$(l%,16), i%, 2))) NEXT i% FOR j% = 0 TO (LEN(message$) \ 64) -1 for i% = 0 to 15 BigEndian$ = "" for m% = 1 to 4 BigEndian$ = BigEndian$ + Hex$(asc(mid$(message$, m% + (j%*64) + (i%*4), 1)),2) next m% w%(i%+1) = val("&H" + BigEndian$) next i% FOR i% = 17 TO 80 w%(i%) = w%(i%-3) XOR w%(i%-8) XOR w%(i%-14) XOR w%(i%-16) w%(i%) = ((w%(i%)<<1)<<32)>>32 OR w%(i%)>> 31 NEXT i% a% = h0% b% = h1% c% = h2% d% = h3% e% = h4% FOR i% = 0 TO 79 if i% <= 19 then f% = d% xor (b% and (c% xor d%)) k% = &H5A827999 else if i% <= 39 then f% = b% XOR c% XOR d% k% = &H6ED9EBA1 end if end if if i% <= 59 then if i% > 39 then f% = ((b% and c%) + (d% and (b% xor c%))) mod &H100000000 k% = &H8F1BBCDC end if else if i% <= 79 then f% = b% XOR c% XOR d% k% = &HCA62C1D6 end if end if 't% = ((Bit32ShiftLeft%(a%, 5) OR Bit32ShiftRight%(a%, 27))+ f% + e% + k% + w%(i%+1)) mod &H100000000 t% = ((((a%<<5)<<32)>>32 OR a%>>27)+ f% + e% + k% + w%(i%+1)) mod &H100000000 e% = d% d% = c% c% = ((b%<<30)<<32)>>32 OR b%>>2 b% = a% a% = t% NEXT i% h0% = (h0% + a%) mod &H100000000 h1% = (h1% + b%) mod &H100000000 h2% = (h2% + c%) mod &H100000000 h3% = (h3% + d%) mod &H100000000 h4% = (h4% + e%) mod &H100000000 NEXT j% SHA1$ = hex$(h0%,8) + hex$(h1%,8) + hex$(h2%,8) + hex$(h3%,8) + hex$(h4%,8) end function function BASE64$(encode_in$) encode_ref$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" encode_in$ = encode_in$ + "00" binary$ = "" for x% = 1 to 42 step 2 binary$ = binary$ + bin$(val("&H" + mid$(encode_in$, x%, 2)),8) next x% encode_out$ = "" FOR encode_part% = 1 TO 160 step 6 encode_sixbitval% = val("&B" + mid$(binary$, (encode_part%), 6)) encode_out$ = encode_out$ + MID$(encode_ref$, encode_sixbitval%+1, 1) NEXT encode_part% BASE64$ = encode_out$ + "=" end function Just know enough to get me in trouble, but not quite enough to get me out. |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5091 |
Wauw….. From 321mSec to 45mSec by just replacing your 32 bit shift function by >> and <<. That is impressive. I saw it was used in double nested loops, so yes...that has impact. I assume you wrote the Bit32ShiftLeft% yourself. It includes a loop that is executed 32 times (32 bits) and includes string conversions. Could explain a lot. Volhout. PicomiteVGA PETSCII ROBOTS |
||||
seco61 Senior Member ![]() Joined: 15/06/2011 Location: AustraliaPosts: 205 |
This version is about 4mS faster and does not corrupt the variables passed to the functions. But the code is not as readable as the original version... ![]() option explicit dim string a="x3JJHMbDL1EzLkh9GBhXDw==",b dim integer c,d for d=0 to 10 timer=0:b=BASE64(SHA1(a)):c=timer ? a+" -> "+b+" in "+str$(c)+"mS" next d end function SHA1(s as string) as string local string h,o=s+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" local integer h0=&H67452301,h1=&HEFCDAB89,h2=&H98BADCFE,h3=&H10325476,h4=&HC3D2E1F0,a,b,c,d,e,f,g,i,j,k,l,m,n(80) l=len(o)*8:o=o+chr$(&H80) do while (len(o) and 63)<>56:o=o+chr$(0):loop for i=1 to 15 step 2:o=o+chr$(VAL("&H"+mid$(hex$(l,16),i,2))):next i for j=0 to (len(o)>>6)-1 for i=0 to 15 h="" for m=1 to 4:h=h+hex$(asc(mid$(o,m+(j*64)+(i*4),1)),2):next m n(i+1)=val("&H"+h) next i for i=17 to 80:n(i)=n(i-3) xor n(i-8) xor n(i-14) xor n(i-16):n(i)=(n(i)<<33)>>32 or n(i)>>31:next i a=h0:b=h1:c=h2:d=h3:e=h4 for i=0 to 79 if i<=19 then f=d xor (b and (c xor d)):k=&H5A827999 else if i<=39 then f=b xor c xor d:k=&H6ED9EBA1 end if if i<=59 then if i>39 then f=((b and c)+(d and (b xor c))) and &Hffffffff:k=&H8F1BBCDC else if i<=79 then f=b xor c xor d:k=&HCA62C1D6 end if g=(((a<<37)>>32 or a>>27)+f+e+k+n(i+1)) and &Hffffffff:e=d:d=c:c=(b<<62)>>32 or b>>2:b=a:a=g next i h0=(h0+a) and &Hffffffff:h1=(h1+b) and &Hffffffff:h2=(h2+c) and &Hffffffff:h3=(h3+d) and &Hffffffff:h4=(h4+e) and &Hffffffff next j SHA1=hex$(h0,8)+hex$(h1,8)+hex$(h2,8)+hex$(h3,8)+hex$(h4,8) end function function BASE64(f as string) as string static string r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" local integer a,b local string c,d,e=f+"00" for a=1 to 42 step 2:c=c+bin$(val("&H"+mid$(e,a,2)),8):next a for a=1 to 160 step 6:b=val("&B"+mid$(c,(a),6)):d=d+mid$(r,b+1,1):next a BASE64=d+"=" end function Regards Gerard (vk3cg/vk3grs) |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4044 |
I suspect quite a lot of time is going in endless conversions to/from chars/strings (with val of &H or &B, or hex$ or mid$ or, well you get the idea). Using an array of integers the whole time ought to be much faster. Then finally convert to base64. It all depends whether you really want speed or not. John |
||||
HardingJohn![]() Regular Member ![]() Joined: 28/07/2017 Location: AustraliaPosts: 78 |
Thanks Seco61. Your formatting is certainly efficient, if a little harder to follow. I will adopt some of your coding improvements, thankyou. I guess adding new functions to the ARMmite firmware is something only Peter can do and unless it is a function everyone really wants to use, its a bit much to ask. Just know enough to get me in trouble, but not quite enough to get me out. |
||||
CaptainBoing![]() Guru ![]() Joined: 07/09/2016 Location: United KingdomPosts: 2170 |
The problem with adding new commands is that the tables that define the names for both functions and statements (commands) are only 127 entries long each - because the tokenising uses a single byte... the "bad" news is they are both almost completely full with only a couple of entries each available. Going to a 16bit token would fix this but it is such a fundamental part of MMBasic that you run a serious risk of introducing bugs to something that has been stable for years... it would be major re-write for the core, never mind the time taken up for someone to do this - for FREE!!!! New function/statements are only added when absolutely necessary - although your hashing function is useful, it is likely only to a few - the command tables in MMBasic need to serve the many. CFunctions and CSubs are an amazing way to extend the capability with the flexibility of Subs/Functions plus the core speed of the CPU. Unfortunately because of architecture changes in (I think) the IDE, it is really difficult to do on non 32MX chips. This is offset by the speed up in CPU and the increase in memory for basic code. I have been in the situation you find above. I have a radio network that uses a 1.5 second cycle period and by the time a MK2 has decrypted a packet, decided to respond (with any attendant work) and then encrypted its reply it was hit n miss whether it could do it in time for larger messages (100chars +) hence adopting a much simpler encryption which wasn't as maths intensive (read: faster). Sadly though you have a genuine need, I really don't think that democratically you'll get it in the firmware... but with Seco's mods, 40+mS isn't bad and you can probably live with it now? The problem is, your requirement won't fit with eveyone's needs... you want SHA1, others (me) will want SHA256 etc... where do we draw the line? Well, the simple answer here is "with the primitives" that way you can build everything else... it's like lego or airfix... with an airfix kit you can build a model Spitfire... and that is it... with lego you can build anything - might be a bit knobbly and not quite as refined but certainly recognisable. I have seen (and contributed) to this request for new commands in the past... it took a while for me to realise why it isn't as easy as I had hoped. I know this probably isn't what you want to hear but we have a fantastic set of "primitives" with MMBasic and I have yet to find a problem I couldn't solve. My approach to MMBasic now is "It is what it is" anything else is a bonus. We aren't in a bad place. Actually, coming from an assembler background, I still get a buzz out of trying different ways to do things and shave a couple of milli-seconds off here and there and reduce code to the simplest possible. The old adage in ASM of "small and slow or big and fast" - alluding to the trade-off between value calculation or lookup still holds and lots of my code shows this mentality. I am such a geek! ![]() all the best h |
||||
seco61 Senior Member ![]() Joined: 15/06/2011 Location: AustraliaPosts: 205 |
Hi. Thought I would tweak the code a little bit more ![]() This has shaved about another 5mS from the time ![]() option explicit dim string a="x3JJHMbDL1EzLkh9GBhXDw==",b,c dim integer d,e,f ? "Average of 1000 executions" timer=0 for d=1 to 1000:b=BASE64(SHA1(a)):next d e=timer:? a+" -> "+b+" in "+str$(e/1000.0)+"mS" timer=0 for d=1 to 1000:b=SHA1(a):c=BASE64(b):next d e=timer:? a+" -> "+c+" in "+str$(e/1000.0)+"mS" timer=0 for d=1 to 1000:b=SHA1(a):next d e=timer:timer=0 for d=1 to 1000:c=BASE64(b):next d f=timer ? a+" -> "+c+" in "+str$(e/1000.0)+"mS"+", "+str$(f/1000.0)+"mS"+", total: "+str$((e+f)/1000.0)+"mS" end function SHA1(s as string) as string local string h,o=s+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" local integer h0=&H67452301,h1=&HEFCDAB89,h2=&H98BADCFE,h3=&H10325476,h4=&HC3D2E1F0,a,b,c,d,e,f,g,i,j,k,l,m,n(80) h=hex$(len(o)<<3,16):o=o+chr$(&H80) do while (len(o) and 63)<>56:o=o+chr$(0):loop for i=1 to 15 step 2:o=o+chr$(VAL("&H"+mid$(h,i,2))):next i for j=0 to (len(o)>>6)-1 for i=0 to 15 l=0 for m=1 to 4:l=(l<<8)+asc(mid$(o,m+(j<<6)+(i<<2),1)):next m n(i+1)=l next i for i=17 to 80:n(i)=n(i-3) xor n(i-8) xor n(i-14) xor n(i-16):n(i)=n(i)<<33>>32 or n(i)>>31:next i a=h0:b=h1:c=h2:d=h3:e=h4 for i=0 to 79 select case i case 0 to 19 f=d xor (b and (c xor d)):k=&H5A827999 case 20 to 39 f=b xor c xor d:k=&H6ED9EBA1 case 40 to 59 f=(b and c)+(d and (b xor c)) and &HFFFFFFFF:k=&H8F1BBCDC case else f=b xor c xor d:k=&HCA62C1D6 end select g=((a<<37>>32 or a>>27)+f+e+k+n(i+1)) and &HFFFFFFFF:e=d:d=c:c=b<<62>>32 or b>>2:b=a:a=g next i h0=h0+a and &HFFFFFFFF:h1=h1+b and &HFFFFFFFF:h2=h2+c and &HFFFFFFFF:h3=h3+d and &HFFFFFFFF:h4=h4+e and &HFFFFFFFF next j SHA1=hex$(h0,8)+hex$(h1,8)+hex$(h2,8)+hex$(h3,8)+hex$(h4,8) end function function BASE64(f as string) as string static string r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" local integer a,b local string c,d,e=f+"00" for a=1 to 42 step 2:c=c+bin$(val("&H"+mid$(e,a,2)),8):next a for a=1 to 160 step 6:b=val("&B"+mid$(c,a,6)):d=d+mid$(r,b+1,1):next a BASE64=d+"=" end function Regards Gerard (vk3cg/vk3grs) |
||||
HardingJohn![]() Regular Member ![]() Joined: 28/07/2017 Location: AustraliaPosts: 78 |
Thankyou again, ![]() Just know enough to get me in trouble, but not quite enough to get me out. |
||||
seco61 Senior Member ![]() Joined: 15/06/2011 Location: AustraliaPosts: 205 |
It is interesting to play around with the different basic constructs to see which are quicker... Another tweak - it is about another 2mS faster... option explicit dim string a="x3JJHMbDL1EzLkh9GBhXDw==",b,c dim integer d,e,f ? "Average of 1000 executions" timer=0 for d=1 to 1000:b=BASE64(SHA1(a)):next d e=timer:? a+" -> "+b+" in "+str$(e/1000.0)+"mS" timer=0 for d=1 to 1000:b=SHA1(a):c=BASE64(b):next d e=timer:? a+" -> "+c+" in "+str$(e/1000.0)+"mS" timer=0 for d=1 to 1000:b=SHA1(a):next d e=timer:timer=0 for d=1 to 1000:c=BASE64(b):next d f=timer ? a+" -> "+c+" in "+str$(e/1000.0)+"mS"+", "+str$(f/1000.0)+"mS"+", total: "+str$((e+f)/1000.0)+"mS" end function SHA1(s as string) as string local string h,o=s+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" local integer h0=&H67452301,h1=&HEFCDAB89,h2=&H98BADCFE,h3=&H10325476,h4=&HC3D2E1F0,a,b,c,d,e,f,g,i,j,k,l,m,n(80) h=hex$(len(o)<<3,16):o=o+chr$(&H80) do while (len(o) and 63)<>56:o=o+chr$(0):loop for i=1 to 15 step 2:o=o+chr$(VAL("&H"+mid$(h,i,2))):next i for j=0 to (len(o)>>6)-1 for i=0 to 15:l=0:for m=1 to 4:l=(l<<8)+asc(mid$(o,m+(j<<6)+(i<<2),1)):next m:n(i+1)=l:next i for i=17 to 80:n(i)=n(i-3) xor n(i-8) xor n(i-14) xor n(i-16):n(i)=n(i)<<33>>32 or n(i)>>31:next i a=h0:b=h1:c=h2:d=h3:e=h4 for i=0 to 19:f=d xor (b and (c xor d)):k=&H5A827999:g=((a<<37>>32 or a>>27)+f+e+k+n(i+1)) and &HFFFFFFFF:e=d:d=c:c=b<<62>>32 or b>>2:b=a:a=g:next i for i=20 to 39:f=b xor c xor d:k=&H6ED9EBA1:g=((a<<37>>32 or a>>27)+f+e+k+n(i+1)) and &HFFFFFFFF:e=d:d=c:c=b<<62>>32 or b>>2:b=a:a=g:next i for i=40 to 59:f=(b and c)+(d and (b xor c)) and &HFFFFFFFF:k=&H8F1BBCDC:g=((a<<37>>32 or a>>27)+f+e+k+n(i+1)) and &HFFFFFFFF:e=d:d=c:c=b<<62>>32 or b>>2:b=a:a=g:next i for i=60 to 79:f=b xor c xor d:k=&HCA62C1D6:g=((a<<37>>32 or a>>27)+f+e+k+n(i+1)) and &HFFFFFFFF:e=d:d=c:c=b<<62>>32 or b>>2:b=a:a=g:next i h0=h0+a and &HFFFFFFFF:h1=h1+b and &HFFFFFFFF:h2=h2+c and &HFFFFFFFF:h3=h3+d and &HFFFFFFFF:h4=h4+e and &HFFFFFFFF next j SHA1=hex$(h0,8)+hex$(h1,8)+hex$(h2,8)+hex$(h3,8)+hex$(h4,8) end function function BASE64(f as string) as string static string r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" local integer a,b local string c,d,e=f+"00" for a=1 to 42 step 2:c=c+bin$(val("&H"+mid$(e,a,2)),8):next a for a=1 to 160 step 6:b=val("&B"+mid$(c,a,6)):d=d+mid$(r,b+1,1):next a BASE64=d+"=" end function Regards Gerard (vk3cg/vk3grs) |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |