Skip to content
This repository has been archived by the owner on Oct 12, 2023. It is now read-only.

Commit

Permalink
v2.0 release:
Browse files Browse the repository at this point in the history
- Improved the test suite
- Added an extra example in the implementation documentation
- Bugfix in the example server implementation leading to count not always being updated correctly
- Bugfix in the update of count in the python device simulator
  • Loading branch information
benmod committed Oct 10, 2019
1 parent e56e0af commit 81b7bbf
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 51 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,28 @@
**Hardware implementation with generic C version + Arduino + schematics:** https://github.com/EnAccess/OpenPAYGO-HW

**See the documentation folder for a general overview of the system as well as for information on how to use the examples.**

# NOTE:
If you have pulled or downloaded this implementation before the official OpenPAYGO Token release on the 10th of October 2019,
please make sure to update to the latest version before using in production.

# CHANGELOG:

2019-10-10: v2.0 release
- Improved the test suite
- Added an extra example in the implementation documentation
- Bugfix in the example server implementation leading to count not always being updated correctly
- Bugfix in the update of count in the python device simulator

2019-09-27:
- Added signed independent security audit
- Added documentation as PDF

2019-09-06: v2.0 rc1
- Added extended token example implementation

2019-08-28: v2.0 beta
- Fully functional version with all v2.0 features

2019-07-19: v2.0 alpha
- First functional pre-release version
5 changes: 2 additions & 3 deletions decode_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@ def get_activation_value_count_and_type_from_token(cls, token, starting_code, ke
for count in range(0, max_count_try):
masked_token = OPAYGOShared.put_base_in_token(current_code, token_base)
if masked_token == token and cls._count_is_valid(count, last_count, value):
clean_count = count-1
if clean_count % 2:
if count % 2:
type = OPAYGOShared.TOKEN_TYPE_SET_TIME
else:
type = OPAYGOShared.TOKEN_TYPE_ADD_TIME
return value, clean_count, type
return value, count, type
current_code = OPAYGOShared.generate_next_token(current_code, key) # If not we go to the next token
return None, None, None

Expand Down
Binary file modified documentation/example_implementation_documentation.pdf
Binary file not shown.
8 changes: 4 additions & 4 deletions encode_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ def generate_standard_token(cls, starting_code, key, value, count,
new_count = count+1
else:
new_count = count+2
for xn in range(1, new_count):
for xn in range(0, new_count):
current_token = OPAYGOShared.generate_next_token(current_token, key)
final_token = OPAYGOShared.put_base_in_token(current_token, token_base)
if restricted_digit_set:
final_token = OPAYGOShared.convert_to_4_digit_token(final_token)
return final_token
return new_count, final_token

@classmethod
def _encode_base(cls, base, number):
Expand All @@ -42,12 +42,12 @@ def generate_extended_token(cls, starting_code, key, value, count, restricted_di
token_base = cls._encode_base_extended(starting_code_base, value)
current_token = OPAYGOSharedExtended.put_base_in_token(starting_code, token_base)
new_count = count + 1
for xn in range(1, new_count):
for xn in range(0, new_count):
current_token = OPAYGOSharedExtended.generate_next_token(current_token, key)
final_token = OPAYGOSharedExtended.put_base_in_token(current_token, token_base)
if restricted_digit_set:
final_token = OPAYGOSharedExtended.convert_to_4_digit_token(final_token)
return final_token
return new_count, final_token

@classmethod
def _encode_base_extended(cls, base, number):
Expand Down
34 changes: 30 additions & 4 deletions example/example_scenario.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
from datetime import datetime, timedelta


def assert_time_equals(time1, time2):
assert time1.replace(second=0, microsecond=0) == time2.replace(second=0, microsecond=0)


if __name__ == '__main__':
# ------ IMPORTANT WARNING --------
# DO NOT USE THIS KEY IN PRODUCTION
# IT IS JUST AN EXAMPLE
# ---------------------------------
# device_key = b'\xa2\x9a\xb8.\xdc_\xbb\xc4\x1e\xc9S\x0fm\xac\x86\xb1'
# device_starting_code = 123456789 # Generated by fair dice roll
device_key = b'\xa2\x9a\xb8.\xdc_\xbb\xc4\x1e\xc9S\x0fm\xac\x86\xb1'
device_starting_code = 123456789 # Generated by fair dice roll
raise Exception("Please change the key and starting code and remove this exception. ")
restricted_digit_set = False

Expand All @@ -30,28 +34,43 @@
print('\n')
print('Server: We add 1 days of activation for the device')
this_token = server_simulator.generate_token_from_date(datetime.now() + timedelta(days=1))
this_token = str(this_token)
print('Token: '+this_token)
print('Device: We enter the generated token into the device')
device_simulator.enter_token(this_token)
print('Device: We check the device status (should be active with 1 day)')
device_simulator.print_status()
assert device_simulator.count == server_simulator.count
assert_time_equals(device_simulator.expiration_date, datetime.now() + timedelta(days=1))

print('\n')
print('Device: We enter the token a second time to make sure it doesnt add the days again')
device_simulator.enter_token(this_token)
print('Device: We check the device status (should be active with 1 day)')
device_simulator.print_status()
assert device_simulator.count == server_simulator.count
assert_time_equals(device_simulator.expiration_date, datetime.now() + timedelta(days=1))

print('\n')
print('Server: We set it to expire in 30 days')
this_token = server_simulator.generate_token_from_date(datetime.now() + timedelta(days=30))
this_token = str(this_token)
print('Token: ' + this_token)
print('Device: We enter the generated token into the device')
device_simulator.enter_token(this_token)
print('Device: We check the device status (should be active with 30 days)')
device_simulator.print_status()
assert device_simulator.count == server_simulator.count
assert_time_equals(device_simulator.expiration_date, datetime.now() + timedelta(days=30))

print('\n')
print('Server: We set it to expire in 7 days (removing 23 days)')
this_token = server_simulator.generate_token_from_date(datetime.now() + timedelta(days=7))
print('Token: ' + this_token)
print('Device: We enter the generated token into the device')
device_simulator.enter_token(this_token)
print('Device: We check the device status (should be active with 7 days)')
device_simulator.print_status()
assert device_simulator.count == server_simulator.count
assert_time_equals(device_simulator.expiration_date, datetime.now() + timedelta(days=7))

print('\n')
print('Server: We generate a token for putting the device in PAYG-OFF mode')
Expand All @@ -62,6 +81,8 @@
device_simulator.enter_token(this_PAYG_OFF_code)
print('Device: We check the device status (should be active forver)')
device_simulator.print_status()
assert device_simulator.count == server_simulator.count
assert device_simulator.payg_enabled is False

print('\n')
print('Server: We generate a token for putting the device back PAYG-ON mode with 0 days')
Expand All @@ -72,6 +93,9 @@
device_simulator.enter_token(this_token)
print('Device: We check the device status (should not be active)')
device_simulator.print_status()
assert device_simulator.count == server_simulator.count
assert device_simulator.payg_enabled is True
assert_time_equals(device_simulator.expiration_date, datetime.now() + timedelta(days=0))

print('\n')
print('Server: We generate a bunch of 1 day tokens, but only enter the latest one')
Expand All @@ -87,3 +111,5 @@
device_simulator.enter_token(this_token)
print('Device: We check the device status (should be active with 1 day and the count synchronised with the server)')
device_simulator.print_status()
assert device_simulator.count == server_simulator.count
assert_time_equals(device_simulator.expiration_date, datetime.now() + timedelta(days=1))
22 changes: 16 additions & 6 deletions example/token_generator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from encode_token import OPAYGOEncoder
from encode_token import OPAYGOEncoder, OPAYGOShared
from decode_token import OPAYGODecoder
import codecs

Expand All @@ -10,7 +10,8 @@
# ---------------------------------
device_key_hex = 'a29ab82edc5fbbc41ec9530f6dac86b1'
device_starting_code = 123456789
device_last_count = 2
raise Exception("Please change the key and starting code and remove this exception. ")
device_last_count = 4
days_to_activate = 7


Expand All @@ -19,13 +20,22 @@
print('The code will have the count (number of codes generated before) of '+str(device_last_count)+'. ')
print('The code will contain ' + str(days_to_activate) + ' days of activation. ')

activation_code = OPAYGOEncoder.generate_standard_token(
new_count, token = OPAYGOEncoder.generate_standard_token(
starting_code=device_starting_code,
key=codecs.decode(device_key_hex, 'hex'),
value=days_to_activate,
count=device_last_count+1,
restricted_digit_set=False
count=device_last_count,
restricted_digit_set=False,
mode=OPAYGOShared.TOKEN_TYPE_ADD_TIME
)

print(str(activation_code))
print(token)

value, count, type = OPAYGODecoder.get_activation_value_count_and_type_from_token(
starting_code=device_starting_code,
key=codecs.decode(device_key_hex, 'hex'),
token=token,
last_count=device_last_count
)
print(value, count, type)

18 changes: 9 additions & 9 deletions security_audit/bruteforce_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
# We know the starting code, and we know 3 tokens with count and value

known_value = 7
code_count_1 = int('016609796')
code_count_1 = int('16609796')
code_count_2 = int('395084796')
code_count_3 = int('566856796')
code_count_3 = int('682637796')
starting_code = 123456789


if __name__ == '__main__':
print('Trying to bruteforce the starting code...')
print('Trying to bruteforce the key...')

token_base = OPAYGOShared.get_token_base(code_count_1) - known_value

Expand All @@ -23,33 +23,33 @@
device_key = i.to_bytes(16, 'big')
#print(device_key)

activation_code = OPAYGOEncoder.generate_standard_token(
count, activation_code = OPAYGOEncoder.generate_standard_token(
starting_code=starting_code,
key=device_key,
value=known_value,
count=1+1
count=1
)

if activation_code == code_count_1:
print('Level 1 Match found!')
print(device_key)

activation_code_2 = OPAYGOEncoder.generate_standard_token(
count, activation_code_2 = OPAYGOEncoder.generate_standard_token(
starting_code=starting_code,
key=device_key,
value=known_value,
count=2+1
count=count
)

if activation_code_2 == code_count_2:
print('Level 2 Match found!')
print(device_key)

activation_code_3 = OPAYGOEncoder.generate_standard_token(
count, activation_code_3 = OPAYGOEncoder.generate_standard_token(
starting_code=starting_code,
key=device_key,
value=known_value,
count=3+1
count=count
)

if activation_code_3 == code_count_3:
Expand Down
28 changes: 20 additions & 8 deletions security_audit/bruteforce_starting_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
known_value = 7
code_count_1 = int('016609796')
code_count_2 = int('395084796')
code_count_3 = int('566856796')
code_count_3 = int('682637796')
device_key_hex = 'a29ab82edc5fbbc41ec9530f6dac86b1'
device_key = codecs.decode(device_key_hex, 'hex')

Expand All @@ -22,23 +22,35 @@

starting_code = OPAYGOShared.put_base_in_token(i*1000, token_base)

activation_code = OPAYGOEncoder.generate_standard_token(
count, activation_code = OPAYGOEncoder.generate_standard_token(
starting_code=starting_code,
key=device_key,
value=known_value,
count=1+1
count=1,
mode=OPAYGOShared.TOKEN_TYPE_ADD_TIME
)

if activation_code == code_count_1:

activation_code_2 = OPAYGOEncoder.generate_standard_token(
count, activation_code_2 = OPAYGOEncoder.generate_standard_token(
starting_code=starting_code,
key=device_key,
value=known_value,
count=2+1
count=count,
mode=OPAYGOShared.TOKEN_TYPE_ADD_TIME
)

if activation_code_2 == code_count_2:
print('Starting code found')
print(starting_code)
break

count, activation_code_3 = OPAYGOEncoder.generate_standard_token(
starting_code=starting_code,
key=device_key,
value=known_value,
count=count,
mode=OPAYGOShared.TOKEN_TYPE_ADD_TIME
)

if activation_code_3 == code_count_3:
print('Starting code found')
print(starting_code)
break
Loading

0 comments on commit 81b7bbf

Please sign in to comment.