Posts: 12
Threads: 2
Joined: Dec 2022
Reputation:
0
08-22-2024, 12:25 AM
(This post was last modified: 08-22-2024, 12:32 AM by Ra7eN.)
ok FOUND the ROL,ROR
working on it now.... using the Phoenix version! didnt know it was out. I'm slow
3 out of 2 people have trouble with fractions
Posts: 734
Threads: 30
Joined: Apr 2022
Reputation:
43
Tread on those who tread on you
Posts: 12
Threads: 2
Joined: Dec 2022
Reputation:
0
thanks! will be looking into that tonight.
this morning went meticulously through any qb64 issue, couple things I found was the _SHL and _SHR the right doesn't pad a "0" if needed _shl seems to work ok. over all things are working. but I just cannot get the right answer - just using abc for now.
I'll take a look at the c. I want to make this integrated into my pwm. Python is nice, but hate _shell-ing out
so made a simple "simulated" one
Code: (Select All)
' Simulate SHL (Shift Left) shiftedValue = (value * (2 ^ shiftAmount)) AND &HFFFFFFFF PRINT RIGHT$("00000000" + HEX$(shiftedValue), 8) ' Expected: 23456780
' Simulate SHR (Shift Right) shiftedValue = (value \ (2 ^ shiftAmount)) AND &HFFFFFFFF PRINT RIGHT$("00000000" + HEX$(shiftedValue), 8) ' Expected: 01234567
I'll take a look at the c and see what I can snag from it :-) I think I have it working, just one of the qb64 functions are not working like I want. it is some tiny flaw somewhere
3 out of 2 people have trouble with fractions
Posts: 303
Threads: 10
Joined: Apr 2022
Reputation:
44
It's not a pure QB64 solution but I managed to hack this together for you from this C TOTP implementation. The only thing really 'missing' is a base32 converter, but that should be very easy to write in QB64 (and it looked like you already wrote that).
This is an example of using it from QB64 (I tested it with this website). To use it in your program you'll copy the `Declare Library` section into your code and then you can call the defined functions, I provided options to either have the C code get the time or for QB64 to provide the time (as Unix time):
Code: (Select All)
Declare Library "totp"
Function getTOTPAtTime~&(hmacKey As String, keyLength As _Unsigned Long, timeStep As _Unsigned Long, currentTime As _Unsigned _Integer64)
Function getTOTP~&(hmacKey As String, BYVAL keyLength As _Unsigned Long, BYVAL timeStep As _Unsigned Long)
End Declare
' The unencoded key
key$ = "Hello!" + CHR$(&HDE) + CHR$(&HAD) + CHR$(&HBE) + CHR$(&HEF)
Do
Locate 2, 2
' Use $Right to add the leading zeros
Print "Code: "; Right$("000000" + _Trim$(Str$(getTOTP(key$, LEN(key$), 30))), 6);
_Limit 2
Loop Until Inkey$ <> ""
And copy this C code into a file named `totp.h` and place it next to your `.bas` file. This C code is very messy but it works fine for me:
Code: (Select All) // MIT License
// Copyright (c) 2019 Weravech
#include <string.h>
#include <inttypes.h>
#include "time.h"
void TOTP(uint8_t* hmacKey, uint8_t keyLength, uint32_t timeStep);
uint32_t getCodeFromTimestamp(uint32_t timeStamp);
// Callable functions from QB64
uint32_t getTOTPAtTime(char *hmacKey, uint32_t keyLength, uint32_t timeStep, time_t timeStamp)
{
TOTP((uint8_t *)hmacKey, keyLength, timeStep);
return getCodeFromTimestamp(timeStamp);
}
uint32_t getTOTP(char *hmacKey, uint32_t keyLength, uint32_t timeStep)
{
return getTOTPAtTime(hmacKey, keyLength, timeStep, time(NULL));
}
#define HASH_LENGTH 20
#define BLOCK_LENGTH 64
union _buffer {
uint8_t b[BLOCK_LENGTH];
uint32_t w[BLOCK_LENGTH/4];
} buffer;
union _state {
uint8_t b[HASH_LENGTH];
uint32_t w[HASH_LENGTH/4];
} state;
uint8_t bufferOffset;
uint32_t byteCount;
uint8_t keyBuffer[BLOCK_LENGTH];
uint8_t innerHash[HASH_LENGTH];
void init(void);
void initHmac(const uint8_t* secret, uint8_t secretLength);
uint8_t* result(void);
uint8_t* resultHmac(void);
void write(uint8_t);
void writeArray(uint8_t *buffer, uint8_t size);
uint32_t getCodeFromSteps(uint32_t steps);
// TOTP.c
uint8_t* _hmacKey;
uint8_t _keyLength;
uint8_t _timeZoneOffset;
uint32_t _timeStep;
// Init the library with the private key, its length and the timeStep duration
void TOTP(uint8_t* hmacKey, uint8_t keyLength, uint32_t timeStep) {
_hmacKey = hmacKey;
_keyLength = keyLength;
_timeStep = timeStep;
}
// Generate a code, using the timestamp provided
uint32_t getCodeFromTimestamp(uint32_t timeStamp) {
uint32_t steps = timeStamp / _timeStep;
return getCodeFromSteps(steps);
}
// Generate a code, using the number of steps provided
uint32_t getCodeFromSteps(uint32_t steps) {
// STEP 0, map the number of steps in a 8-bytes array (counter value)
uint8_t _byteArray[8];
_byteArray[0] = 0x00;
_byteArray[1] = 0x00;
_byteArray[2] = 0x00;
_byteArray[3] = 0x00;
_byteArray[4] = (uint8_t)((steps >> 24) & 0xFF);
_byteArray[5] = (uint8_t)((steps >> 16) & 0xFF);
_byteArray[6] = (uint8_t)((steps >> 8) & 0XFF);
_byteArray[7] = (uint8_t)((steps & 0XFF));
// STEP 1, get the HMAC-SHA1 hash from counter and key
initHmac(_hmacKey, _keyLength);
writeArray(_byteArray, 8);
uint8_t* _hash = resultHmac();
// STEP 2, apply dynamic truncation to obtain a 4-bytes string
uint32_t _truncatedHash = 0;
uint8_t _offset = _hash[20 - 1] & 0xF;
uint8_t j;
for (j = 0; j < 4; ++j) {
_truncatedHash <<= 8;
_truncatedHash |= _hash[_offset + j];
}
// STEP 3, compute the OTP value
_truncatedHash &= 0x7FFFFFFF; //Disabled
_truncatedHash %= 1000000;
return _truncatedHash;
}
// sha1.c
#define SHA1_K0 0x5a827999
#define SHA1_K20 0x6ed9eba1
#define SHA1_K40 0x8f1bbcdc
#define SHA1_K60 0xca62c1d6
uint8_t sha1InitState[] = {
0x01,0x23,0x45,0x67, // H0
0x89,0xab,0xcd,0xef, // H1
0xfe,0xdc,0xba,0x98, // H2
0x76,0x54,0x32,0x10, // H3
0xf0,0xe1,0xd2,0xc3 // H4
};
void init(void) {
memcpy(state.b,sha1InitState,HASH_LENGTH);
byteCount = 0;
bufferOffset = 0;
}
uint32_t rol32(uint32_t number, uint8_t bits) {
return ((number << bits) | (uint32_t)(number >> (32-bits)));
}
void hashBlock() {
uint8_t i;
uint32_t a,b,c,d,e,t;
a=state.w[0];
b=state.w[1];
c=state.w[2];
d=state.w[3];
e=state.w[4];
for (i=0; i<80; i++) {
if (i>=16) {
t = buffer.w[(i+13)&15] ^ buffer.w[(i+8)&15] ^ buffer.w[(i+2)&15] ^ buffer.w[i&15];
buffer.w[i&15] = rol32(t,1);
}
if (i<20) {
t = (d ^ (b & (c ^ d))) + SHA1_K0;
} else if (i<40) {
t = (b ^ c ^ d) + SHA1_K20;
} else if (i<60) {
t = ((b & c) | (d & (b | c))) + SHA1_K40;
} else {
t = (b ^ c ^ d) + SHA1_K60;
}
t+=rol32(a,5) + e + buffer.w[i&15];
e=d;
d=c;
c=rol32(b,30);
b=a;
a=t;
}
state.w[0] += a;
state.w[1] += b;
state.w[2] += c;
state.w[3] += d;
state.w[4] += e;
}
void addUncounted(uint8_t data) {
buffer.b[bufferOffset ^ 3] = data;
bufferOffset++;
if (bufferOffset == BLOCK_LENGTH) {
hashBlock();
bufferOffset = 0;
}
}
void write(uint8_t data) {
++byteCount;
addUncounted(data);
return;
}
void writeArray(uint8_t *buffer, uint8_t size){
while (size--) {
write(*buffer++);
}
}
void pad() {
// Implement SHA-1 padding (fips180-2 ˜5.1.1)
// Pad with 0x80 followed by 0x00 until the end of the block
addUncounted(0x80);
while (bufferOffset != 56) addUncounted(0x00);
// Append length in the last 8 bytes
addUncounted(0); // We're only using 32 bit lengths
addUncounted(0); // But SHA-1 supports 64 bit lengths
addUncounted(0); // So zero pad the top bits
addUncounted(byteCount >> 29); // Shifting to multiply by 8
addUncounted(byteCount >> 21); // as SHA-1 supports bitstreams as well as
addUncounted(byteCount >> 13); // byte.
addUncounted(byteCount >> 5);
addUncounted(byteCount << 3);
}
uint8_t* result(void) {
// Pad to complete the last block
pad();
// Swap byte order back
uint8_t i;
for (i=0; i<5; i++) {
uint32_t a,b;
a=state.w[i];
b=a<<24;
b|=(a<<8) & 0x00ff0000;
b|=(a>>8) & 0x0000ff00;
b|=a>>24;
state.w[i]=b;
}
// Return pointer to hash (20 characters)
return state.b;
}
#define HMAC_IPAD 0x36
#define HMAC_OPAD 0x5c
void initHmac(const uint8_t* key, uint8_t keyLength) {
uint8_t i;
memset(keyBuffer,0,BLOCK_LENGTH);
if (keyLength > BLOCK_LENGTH) {
// Hash long keys
init();
for (;keyLength--;) write(*key++);
memcpy(keyBuffer,result(),HASH_LENGTH);
} else {
// Block length keys are used as is
memcpy(keyBuffer,key,keyLength);
}
// Start inner hash
init();
for (i=0; i<BLOCK_LENGTH; i++) {
write(keyBuffer[i] ^ HMAC_IPAD);
}
}
uint8_t* resultHmac(void) {
uint8_t i;
// Complete inner hash
memcpy(innerHash,result(),HASH_LENGTH);
// Calculate outer hash
init();
for (i=0; i<BLOCK_LENGTH; i++) write(keyBuffer[i] ^ HMAC_OPAD);
for (i=0; i<HASH_LENGTH; i++) write(innerHash[i]);
return result();
}
Note that the C code does not give an option to change the digit length of the code. I believe that detail is hardcoded into `getCodeFromSteps` where it does a MOD 1000000 at the end. Assuming I'm correct on that it should be easy to support longer digit codes if needed by modifying the C code to let you pass in that value.
Posts: 12
Threads: 2
Joined: Dec 2022
Reputation:
0
I tried the c method, same issue I am currently experiencing. It produces good code, but not correct.
But I like the fact that qb64 can almost work with C
thanks for the idea. !!
3 out of 2 people have trouble with fractions
Posts: 303
Threads: 10
Joined: Apr 2022
Reputation:
44
(08-22-2024, 11:41 PM)Ra7eN Wrote: I tried the c method, same issue I am currently experiencing. It produces good code, but not correct.
But I like the fact that qb64 can almost work with C
thanks for the idea. !! Can you clarify what issue you're having, did you try the code I posted? When I tested it, it produced correct TOTPs for me.
Posts: 12
Threads: 2
Joined: Dec 2022
Reputation:
0
(08-23-2024, 12:32 AM)DSMan195276 Wrote: (08-22-2024, 11:41 PM)Ra7eN Wrote: I tried the c method, same issue I am currently experiencing. It produces good code, but not correct.
But I like the fact that qb64 can almost work with C
thanks for the idea. !! Can you clarify what issue you're having, did you try the code I posted? When I tested it, it produced correct TOTPs for me.
It produced codes but not the correct one. I put my secretkey in FFXIV for example, and kept failing, went back to the python/qb64 worked perfect
I switched the following:
Code: (Select All)
key$ = "Hello!" + CHR$(&HDE) + CHR$(&HAD) + CHR$(&HBE) + CHR$(&HEF)
to
Code: (Select All)
key$ = "1234MYSECRETKEY567890" + CHR$(&HDE) + CHR$(&HAD) + CHR$(&HBE) + CHR$(&HEF)
again, codes kept popping up like normal. but they were not correct
Let me know if i did this wrong.
Thanks!
3 out of 2 people have trouble with fractions
Posts: 303
Threads: 10
Joined: Apr 2022
Reputation:
44
(08-23-2024, 12:43 AM)Ra7eN Wrote: It produced codes but not the correct one. I put my secretkey in FFXIV for example, and kept failing, went back to the python/qb64 worked perfect
I switched the following:
Code: (Select All)
key$ = "Hello!" + CHR$(&HDE) + CHR$(&HAD) + CHR$(&HBE) + CHR$(&HEF)
to
Code: (Select All)
key$ = "1234MYSECRETKEY567890" + CHR$(&HDE) + CHR$(&HAD) + CHR$(&HBE) + CHR$(&HEF)
again, codes kept popping up like normal. but they were not correct
Sorry, it's not super clear from your example, is `1234MYSECRETKEY567890` the base32 version or the binary version of your key? The C code does not do the decoding, so you have to provide it the decoded binary key.
Ex. The actual key for my test was `JBSWY3DPEHPK3PXP`, which when decoded as base32 produces the "Hello!" plus DEADBEEF string that I put in `key$`. The chances are high that your key will not be ASCII like my example one when decoded, so your key will just be a series of `CHR$()`s.
Posts: 12
Threads: 2
Joined: Dec 2022
Reputation:
0
(08-23-2024, 06:30 AM)DSMan195276 Wrote: (08-23-2024, 12:43 AM)Ra7eN Wrote: It produced codes but not the correct one. I put my secretkey in FFXIV for example, and kept failing, went back to the python/qb64 worked perfect
I switched the following:
Code: (Select All)
key$ = "Hello!" + CHR$(&HDE) + CHR$(&HAD) + CHR$(&HBE) + CHR$(&HEF)
to
Code: (Select All)
key$ = "1234MYSECRETKEY567890" + CHR$(&HDE) + CHR$(&HAD) + CHR$(&HBE) + CHR$(&HEF)
again, codes kept popping up like normal. but they were not correct
Sorry, it's not super clear from your example, is `1234MYSECRETKEY567890` the base32 version or the binary version of your key? The C code does not do the decoding, so you have to provide it the decoded binary key.
Ex. The actual key for my test was `JBSWY3DPEHPK3PXP`, which when decoded as base32 produces the "Hello!" plus DEADBEEF string that I put in `key$`. The chances are high that your key will not be ASCII like my example one when decoded, so your key will just be a series of `CHR$()`s. Ah good point, I did not decode the key first, I just ran the code as is. ' 1234MYSECRETKEY567890 ' this was just the represent my FFXIV key. As it did not work. However, this month long project has actually allowed me to create my own custom hash, and almost AES quality - not quite due to the lack of HMAC_SHA1 but still very happy with it. Will rewrite some of my code to accept this.
The TOTP feature, I found that I can just run a portable python and include it with my distro.; So it will run faily seamlessly. QB64 is just too challenging for me to get a TOTP. The following is almost exactly as per RFC 3174 . But for some reason, it will toss up a a code, but will not be correct.
But I will put it here for anyone else to take a stab at it. I am TOTALLY exhausted. Its all per RFC 3174 , but yet qb will not throw the right code.
Code: (Select All)
Option _Explicit
Dim shstr As String
shstr$ = SHA1("abc")
Print shstr
'for debug copying to textfile since I can't copy from terminal window
Open "sha1.txt" For Output As #1
Print #1, shstr$
Close #1
End
Dim Shared hA As _Unsigned Long
Dim Shared hB As _Unsigned Long
Dim Shared hC As _Unsigned Long
Dim Shared hD As _Unsigned Long
Dim Shared hE As _Unsigned Long
Sub InitializeHashValues
hA = &H67452301
hB = &HEFCDAB89
hC = &H98BADCFE
hD = &H10325476
hE = &HC3D2E1F0
End Sub
Function PadMessage$ (message As String)
Dim messageLength As _Unsigned Long
messageLength = Len(message) * 8 ' Length in bits
message = message + Chr$(128) ' Append a '1' bit (0x80 in hex)
While (Len(message) * 8) Mod 512 <> 448
message = message + Chr$(0) ' Append '0' bits
Wend
Dim highPart As _Unsigned Long, lowPart As _Unsigned Long
highPart = 0 ' For messages shorter than 2^32 bits, highPart is 0
lowPart = messageLength And &HFFFFFFFF
Dim lengthBytes As String
lengthBytes = CHR$((lowPart \ &H1000000) AND &HFF) + _
CHR$((lowPart \ &H10000) AND &HFF) + _
CHR$((lowPart \ &H100) AND &HFF) + _
CHR$(lowPart AND &HFF)
' Ensure each part is correctly interpreted as 8 bits
' lengthBytes = Right$("00000000" + Hex$(Val(lengthBytes)), 8)
message = message + String$(4, 0) + lengthBytes ' Append length
PadMessage$ = message
End Function
Sub ProcessBlock (block As String)
Dim i As _Unsigned Long
Dim t As _Unsigned Long
Dim TEMP As _Unsigned Long
Dim W(79) As _Unsigned Long
For i = 0 To 15
W(i) = CVL(Mid$(block, i * 4 + 1, 4))
Next
For t = 16 To 79
W(t) = _RoL(W(t - 3) Xor W(t - 8) Xor W(t - 14) Xor W(t - 16), 1)
Next
Dim aTemp As _Unsigned Long, bTemp As _Unsigned Long
Dim cTemp As _Unsigned Long, dTemp As _Unsigned Long, eTemp As _Unsigned Long
aTemp = hA: bTemp = hB: cTemp = hC: dTemp = hD: eTemp = hE
For t = 0 To 79
For t = 0 To 79
Select Case t
Case 0 To 19
TEMP = (_RoL(aTemp, 5) + ((bTemp And cTemp) Or ((Not bTemp) And dTemp)) + eTemp + W(t) + &H5A827999) And &HFFFFFFFF
Case 20 To 39
TEMP = (_RoL(aTemp, 5) + (bTemp Xor cTemp Xor dTemp) + eTemp + W(t) + &H6ED9EBA1) And &HFFFFFFFF
Case 40 To 59
TEMP = (_RoL(aTemp, 5) + ((bTemp And cTemp) Or (bTemp And dTemp) Or (cTemp And dTemp)) + eTemp + W(t) + &H8F1BBCDC) And &HFFFFFFFF
Case 60 To 79
TEMP = (_RoL(aTemp, 5) + (bTemp Xor cTemp Xor dTemp) + eTemp + W(t) + &HCA62C1D6) And &HFFFFFFFF
End Select
Next
eTemp = dTemp
dTemp = cTemp
cTemp = _RoL(bTemp, 30)
bTemp = aTemp
aTemp = TEMP
Next
hA = (hA + aTemp) And &HFFFFFFFF
hB = (hB + bTemp) And &HFFFFFFFF
hC = (hC + cTemp) And &HFFFFFFFF
hD = (hD + dTemp) And &HFFFFFFFF
hE = (hE + eTemp) And &HFFFFFFFF
End Sub
Function SHA1$ (message As String)
' Initialize the hash constants
InitializeHashValues
' Preprocess the message (pad it)
message = PadMessage(message)
' Process each 512-bit block
Dim i As Long
For i = 1 To Len(message) Step 64
ProcessBlock Mid$(message, i, 64)
Next
' Convert each part of the hash to a hexadecimal string and trim it
Dim hashA As String, hashB As String, hashC As String, hashD As String, hashE As String
hashA = LCase$(_Trim$(Hex$(hA)))
hashB = LCase$(_Trim$(Hex$(hB)))
hashC = LCase$(_Trim$(Hex$(hC)))
hashD = LCase$(_Trim$(Hex$(hD)))
hashE = LCase$(_Trim$(Hex$(hE)))
' Concatenate the final hash string explicitly
Dim finalHash As String
finalHash = hashA + hashB + hashC + hashD + hashE
' Return the concatenated and trimmed hash
SHA1$ = finalHash
End Function
3 out of 2 people have trouble with fractions
Posts: 1,002
Threads: 50
Joined: May 2022
Reputation:
27
Why still use SHA1? Microsoft has withdrawn support for it since 2021 due to problems was with it.
AKTUALISIERUNG: SHA-1-signierte Inhalte werden zurückgezogen
|