1. George Mikhailovsky
  2. PowerServer 2020 or older (Obsolete)
  3. Saturday, 10 October 2020 23:39 PM UTC

I need to incorporate Two Factor Authentication (2FA) into my PowerBuilder 2019 R2 application and I used for this twofactorauth.pbl created by Bruce Armstrong that I found in Appeon community.

 The objects from this PBL works fine in C/S version of the application but when I deployed it as web application (locally to the same server with IIS that has PowerServer 2020), the returned token became “000000”. Then, according advice by Bruce Armstrong, I found in “Two Factor Authentication using PowerBuilder tutorial in Articles & Blogs of Appeon Community” a workaround to solve this problem by using of_copylongtobytes() and of_blob() functions instead of CopyLongToBytes() and Blob(). I created these new functions and replaced the old ones with them. After this, the returned token in both C/S and web applications became a random 6-digits number instead of ‘000000’. However, this token never matches the token in DuoMobile on my iPhone. At the same time, these tokens in the C / S version of the same application (with the old CopyLongToBytes () and Blob () functions) always match.

I would really appreciate it if you could help me solve this problem.

My best regards,

George Mikhailovsky

George Mikhailovsky Accepted Answer Pending Moderation
  1. Thursday, 15 October 2020 14:36 PM UTC
  2. PowerServer 2020 or older (Obsolete)
  3. # 1

Good morning Marco,

I wrote code addition in of_copylongtobytes() function (see below), and counterbytes[] array that it returns by ref looks exactly as it looks in the working variant. And this fixed the problem! Pin and token began match one another as in C/S as in web application.

Thank you a lot for all your help!

George 

long li_number
integer i = 1, j, li_byte[], li_ibyte[], li_data[]
string ls_msg = ''

li_number = al_number

Do While Truncate(li_number / 256, 0) > 0
li_byte[i] = Mod(li_number, 256)
i++
li_number = Truncate(li_number/256, 0)
Loop
li_byte[i] = Mod(li_number, 256)

//Copy over data in inverse order

for i = 4 to 1 STEP -1
j ++
li_ibyte[j] = li_byte[i]
next

For i = 1 To 4
li_data[i] = 0
Next
For i = 5 To 8
li_data[i] = li_ibyte[i - 4]
Next

For j = 1 to 8
a_byte[j] += Byte(String(li_data[j]))
Next

 

Comment
There are no comments made yet.
George Mikhailovsky Accepted Answer Pending Moderation
  1. Thursday, 15 October 2020 03:14 AM UTC
  2. PowerServer 2020 or older (Obsolete)
  3. # 2

Hi Marco,

First of all, sorry for the mistake in my previous message. I sent you one the modified codes that I tried. Original version was

of_copylongtobytes( counter, counterBytes )
counterBlob = of_blob ( counterBytes )

and it didn't work, either. I didn't debug the codes before, because thought that all the numbers are random and, in any case, they will be different in working and not working variants.

After your recommendation, however, I decided to debug both options and found one difference. Huhushbytes[] array contained 20 random numbers in both variants (2nd and 4th screenshots in the attached document). But counterbytes[] array had 8 elements in the working variant, first 4 of which were zeros and remained 4 were random numbers (1st  screenshots), while in the not working variant this array had only 4 elements without any zeros (3rd screenshot). 

 

Can this make the difference?  What do you think?

Tomorrow, I will try to rewrite code of of_copylongtobytes() function making it to return array of 8 elements with first 4 zeros. But you wrote that this function works for you as it is now. How many elements counterbytes[] has in your application?

Thank you a lot!

George

Attachments (1)
Comment
There are no comments made yet.
Marco Meoni Accepted Answer Pending Moderation
  1. Wednesday, 14 October 2020 20:21 PM UTC
  2. PowerServer 2020 or older (Obsolete)
  3. # 3

Hi George,

your code

of_copylongtobytes( counter, counterBytes )
counterBlob = Blob ( counterBytes )

should be 

of_copylongtobytes( counter, counterBytes )
counterBlob = of_blob ( counterBytes )

When I deployed 2FA to my PowerServer I remember I went through a line-by-line debug comparison between PB and PS execution. I suggest you do the same.

Best,

.m

Comment
There are no comments made yet.
George Mikhailovsky Accepted Answer Pending Moderation
  1. Monday, 12 October 2020 20:52 PM UTC
  2. PowerServer 2020 or older (Obsolete)
  3. # 4

Hi Marco,
Thank you for your help. Unfortunately, I still didn't solve my problem. Code of my of_copylongtobytes() function is exactly the same as you provide in my message. Code in my of_blob() function is following:

Integer i
Blob lblb

lblb = Blob ( Space(UpperBound(a_byte)), EncodingUTF8! )
for i = 1 to UpperBound(a_byte)
SetByte(lblb, i, a_byte[i])
Next
Return lblb

I called these functions in generatepin() function:

byte hashBytes[], counterBytes[], offset, selectedByte
blob counterHashBlob, counterBlob, keyBlob
string counterHash, pin
integer li_count, i, pinLen
long selectedLong
long selectedMod
CrypterObject co

//Convert the counter to byte array and then to blob
of_copylongtobytes( counter, counterBytes )
counterBlob = Blob ( counterBytes )

//Convert key to blob and has counter
keyBlob= Blob ( key, EncodingUTF8! )
co = create CrypterObject
counterHashBlob = co.Hmac( HMACSHA1! , counterBlob, keyBlob )
Destroy co

//Convert result back to byte array
hashBytes = GetByteArray ( counterHashBlob )

//Get the last byte
li_count = UpperBound ( hashBytes )

//And use that to determine the offset into the byte array that we'll start with
offset = bitwiseand ( hashBytes[li_count], 15 )

//Calculate the selectedLong value using the selected bytes
for i = 1 to 4
selectedByte = hashBytes[offset + i]
CHOOSE CASE i
CASE 1
//Strip the most significant bit
selectedByte = bitwiseand ( selectedByte, 127 )
selectedLong = selectedLong + selectedByte * 2^24
CASE 2
selectedLong = selectedLong + selectedByte * 2^16
CASE 3
selectedLong = selectedLong + selectedByte * 2^8
CASE 4
selectedLong = selectedLong + selectedByte
END CHOOSE
next

selectedMod = Mod ( selectedLong, 1000000 )

pin = String ( selectedMod )
pinLen = Len ( pin )
pin = Fill ( '0', 6 - pinLen ) + pin

Return pin

However, the returned pin doesn't match to one returned on mu IPhone by DuoMobile application. I tried to call of_blob() before of_copylongtobytes() function but this didn't help, either.

Do you see errors in my code? Or, if your code works, can you please send me all the changes you made to Bruce's code?

I would really appreciate any help,

George

 

Comment
There are no comments made yet.
Marco Meoni Accepted Answer Pending Moderation
  1. Monday, 12 October 2020 08:14 AM UTC
  2. PowerServer 2020 or older (Obsolete)
  3. # 5

Hi George,

I have also started from Bruce's article and, by fixing two unsupported features, I can use 2FA from PowerServer.

As you said, they are:

- of_blob: you must convert blob into byte array

- CopyLongToBytes: you must loop in the byte array and do the mathematics below:

long li_number
integer i = 1, j, li_byte[]
string ls_msg = ''

li_number = al_number

Do While Truncate(li_number / 256, 0) > 0
li_byte[i] = Mod(li_number, 256)
i++
li_number = Truncate(li_number/256, 0)
Loop
li_byte[i] = Mod(li_number, 256)

For j = 1 to i
a_byte[j] += Byte(String(li_byte[j]))
Next

 

Best,

.m

Comment
There are no comments made yet.
Armeen Mazda @Appeon Accepted Answer Pending Moderation
  1. Sunday, 11 October 2020 05:50 AM UTC
  2. PowerServer 2020 or older (Obsolete)
  3. # 6

There must be some unsupported feature.  Anything showing up in the unsupported features analysis report?

We are enhancing PowerServer in the next version to natively support all PowerBuilder features so this should work fine in next version without having to “massage” the code.

Comment
  1. George Mikhailovsky
  2. Sunday, 11 October 2020 18:23 PM UTC
Hi Armeen,

Thank you for your response!

Unfortunately, there are nothing in Unsupported features related to objects added for 2FA.

Best regards,

George
  1. Helpful
  1. Armeen Mazda @Appeon
  2. Sunday, 11 October 2020 21:58 PM UTC
Maybe next step would be to use the debugger and step through the code. My guess is some line of code is not executing properly, which would cause the code generated in your app not matching the code Google generates on the iPhone/Android token app.
  1. Helpful
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.