Date to date code generator

George
George used Ask the Experts™
on
Hello,
First at all sorry for my bad English.
I would like to create a kind of lock with no internet connexion and a RTC inside.
The lock will open with a code 8 chars long. The chars can be from 0 to 9 and from A to D. (I use a 16 key keypad)
The main idea is to have a code generator that encrypt with this 14 chars (0-9 and A-D) a code that says to the lock : you will have to open from this date until this date. And because i want the code to work only with the serial of one lock the code have to be compatible only with the lock I create the code for.

So to resume :
I have a lock with a 16 keys that are 0-9 and A-D the last two are R for reset and V like run :)
The lock have a serial number could be 000 to 999
When I create the code the code have to contain on max 8 chars : the start date, end date and the serial of the lock.

I've tried some ideas like work with a base 14 or something like. Use a kind of offset from the a defined date that is the same on the lock and the generator and then use the difference from this date to create the start date. Use the serial of the lock to do a CRC so when the lock check the code if the CRC is not ok then it won't open.

Well as you see I'm getting lost so if you have a simple idea please help

Thanks a lot
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
14**8 = 1475789056 which is about three and a half bytes of information


Which means, that after reserving 1000 for the code ID you have about 1475789 possibilities left


now you have share this available 'space' between the start date and the end date and security / redundancy

what kind of resolution do you need. days ? hours? minutes? seconds?

you can define the earliest date yo want to have a lock working e.g. Jan 1st 2020 and specify the start date relative to this point.
You had to decide how long the locks shall work before you will do maintenance / update their software.
e.g. resolution of 1 day life time for 5 years means 5*365 = 1825 possibilities 1475789 / 1825 = 808 possibilities left for duration.|
Now which max duration shall a lock be open? what resolution do you need?
and only the rest can be used as checksum / validity detection.

if you want to protect people from guessing / tampering with codes you had probably to encrypt with a commun secret, but almost all advice depends on the exact specification. 14**8 is not a lot so you have to really know the exact limits and constraints.
nociSoftware Engineer
Distinguished Expert 2018

Commented:
With 14 keys to enter the data you will need to use a base 14 number.
you should probably use a longer lock number.  concatenate:

[lockid][from][to] and calclulate a hash on this.
you publish [from][to][part of hash]  as your key....

the lock can insert its own lockid + the entered string and use the [lockid][from][to]   part to calculate the hash again and then use the same part of the hash to verify.   (hash like sha1 or sha2 have multiple characters  so you can specify a the part wanted as: [n][4 digits]   is the n'th set of 4 digits from the hash.

Be aware that if your lock does not synchronize its clocks then the time WILL drift. depending on temperature as the most influential factor after the clock's inaccuracy.

Date+time (in seconds since 1970 unix Epoch)  of today in Radix 14 (base 14).   Unix binary time
$ echo "obase=14; $(date +%s) "| bc
10C7329CB

Open in new window


This is time same to reduced to hours since 1970.
$ echo "obase=14; $(( $(date +%s) / (60*60) )) "| bc
B4D15

Open in new window

Author

Commented:
I see someone that already use this kind of lock and I even try it. The code you can get is a 1/2 day, 1 day code, 15 days, 1 month code even more. (more seems not to work very well)
The strange thing is that the code length is some time 5chars sometime 6 or 7chars  long.

All that they explain is that they use a serial number for the lock and a 32 chars key the rest is secret defense :)

I'm wondering if the code is not a kind of key used to encrypt/decrypt this 32 chars key ...
Expert Spotlight: Joe Anderson (DatabaseMX)

We’ve posted a new Expert Spotlight!  Joe Anderson (DatabaseMX) has been on Experts Exchange since 2006. Learn more about this database architect, guitar aficionado, and Microsoft MVP.

Well after having read your post multiple times I'm getting more and more confused about what you try to achieve excactly.
And knowing exactly what you want is essential to give you a decent answer.

Example 1, but I'm sure I did not get it right:
- You have 1000 locks perhaps they are door locks in a building or locks of some lockers in a storage room.
- At any time you start your code generator program, enter the lock id, the start time and a an end time (a duration) and you will  generate a code.
- Whoever has this code can open the lock with the given id between the start date and the end date.

This is kind of the implementation of a time based one time password however the algorithms I know have a fixed duration and i the moment
I don't have the idea how to tune / adapt it to your requirements.


Another approach would be to create a 30 bit dataset containing all information and encrypt it with a common shared secret.

with a code length of max 8 characters and each digit having 14 options you have 14**8 states to encode, which corresponds roughly to 30 bits.

10 bits are required for the id, the other 20 bits can be used for the start time and the duration if you don't want any redundancy / CRC.

You just had to decide about the required time span to be covered and about the granularity of start  time and duration.

There don't seem to be that many algorithms, that are adapted to encode a 30 bit number. skip32 seems to be one if used with a tiny trick.
you encode your 30 bit numer with skip 32. If the result is not a 30 bit number but a 31 or 32 bit number then you re-encrypt again until you get a 30 bit number.
Decrypting would go the same way. if decryption yields a non 30 bit value decrypt again.

However I am not qualified enough to know whether that would be cryptographically safe.

Author

Commented:
You see right ;)
In fact i dont Think there will be more than 99 lockers.
I have also think to onetime password but it wasn’t the solution
I think i get lost my self searching for something complicated.
Your both aproaches are the solution I’am looking for.
nociSoftware Engineer
Distinguished Expert 2018

Commented:
it would be better not Not have the lockID in the  code but a hash of a secret, the lockid & times.

The lock knows it's id.  and the  shared secret.  It can receive the times & calculate the hash verify for a correct code.
or use a shared secret / clock then the clock id is implicit in the shared secret.

For half days you don't need much bits. (730 periods / year) = ~ 9.5 bits.
even/odd years might be sufficient   ~10.5 bits.
So i guess : they allow for timestamps of haf day periods  within a year.
start/stop  time. Still leave 10 bits for some kind of checksum/hash.
I slightly edited my previous post. Pls reread
You might also look at format preserving encryption algorithms if you don't find a trick with TOTPs https://en.wikipedia.org/wiki/Format-preserving_encryption

Author

Commented:
Noci your right,
The lock knows it's id.  and the  shared secret.  It can receive the times & calculate the hash verify for a correct code.
or use a shared secret / clock then the clock id is implicit in the shared secret.

yes the lock have a realtime clock and knows his serial. I have a rapid look to them code ... I'm not strong enough to understand all but the the little I saw is that the code generator seems to use a kind of 32 char token looking somehow to this "FF3818CD93CBA029F89B197179F76D04"  that is also registered in the lock. The lock have his own real time clock.
This code generated for me : 6CA7DC says : open from 29/09/2019 from 00:00 to 23:59


gelonoda : if the serial of the lock is the hash as the lock know his id, i do not need to use the 10 bits for the lock serial.
as ou say they seems to use a trick to encrypt / decrypt into 30bit.

You may wonder why I don't use them solution ?

Well in fact I do but the problem is that the locks are really bad and the keypads get often broken. The idea is to use the keypad that is used to access the site to also open the lockers. This keypad is rought enough and is rasperrypi driven.
Using  letters in the code make a bit difficult to find a code that will open the site entrance (I mean is better than 0000 :) ) ... I don't say is impossible but it will takes long time because the system will lock for some time after 10 error codes.

I've also have the java jar that works in the RPi keypad I try to decompile with jd-gui. I even found where they do the decode but there are so many classes and everything si called a, b etc. that I get rapidly lost :) but the system seem really pretty :)

Author

Commented:
Hello noci.
This question is for you.
As cryologie is not my world ... I may need a bit your help.
You said : It can receive the times & calculate the hash verify for a correct code.
or use a shared secret / clock then the clock id is implicit in the shared secret.
This is really obscure for me :)

Each lock will have his own secret key and for the time I will only use the hours since january 2019 and so ... so that time can drift a little :)

Now my really problem is how can i do B644D that mean 11 oct 2019 (based on hours since 1970)  to make it become a base 14 code that the lock can understand ?

I confess i don't know how to ... i look the web and because i don't know really how to ask what i'm looking for i can't find my answer.

Thanks for you help
nociSoftware Engineer
Distinguished Expert 2018

Commented:
What you do is  hash(secretkey, starttime, endtime) - (select part of the hash as it is a 128-512 bit binary string)
the lock needs to receive the starttime, endtime + the hash part from the keyboard.
The lock can calculate the hash(secretkey, starttime, endtime)  and select the same part of the hash string then compare it the values do match.

You would need 4 digits to represent a time in hours...
So a date for even years would be 0000 - 32B6 (offset in year) / odd years would be 32B7 - 658C   (366 days + offset in year).
a code would be: (Startperiod, EndPeriod)    or shorter (startperiod, # hours)   and a hash.
So jan 1, 00:00  = 0000
Dec 31, 23:59 = 329A   (even non leap year).  [ 2018, 2022 ]
Dec 31, 23:59 = 32B6   (even leap year).  [ 2020, 2024 ]
So jan 1, 00:00  = 32B7
Dec 31, 23:59 =  658C  (odd year).  [ 2019, 2021, 2023 ]

You calculate the days in a ( year *24 + hour ) and convert that to base 14

day=DAYOFYEAR
hr=HROFDAY
echo " obase=14 ; $(( $day  * 24 + $hr ))" | bc

Open in new window

for odd years you can add 366 to the DAYOFYEAR.
You can make the hash any size you want.

Author

Commented:
Hello,
Using PHP I set the reference date to 2019-01-01 00:00 the lock use the same date referance.
So when I create a new code like 2019-11-23 00:00 I do tOpen - tRef = tOffset in days (I get 194 in base 14)
The working time will be max 99 days in base 14 so if I want the lock to work only 1 day il will be wTime = '01'
I concatenate the wTime with tOffset that give : 19401
Then I take the shared secret and I concatenate 19401 and secret and hash with sha256
hash may look like this : 9dfe494055d7174aad1c36151584bcc3b2a8d856ed028b76d5c0f1b9d8ec14f5 ok is not binary and nor base 14 but I can convert a part

Now the problem how can I do, the max length I'd like for a password is 8 char. Is enough 3 chars from the hash in order to identify the lock ? 3 chars is enough ?

Thanks a lot for your answer
Software Engineer
Distinguished Expert 2018
Commented:
Say you take the middle 5 characters of the sha256. and convert that from hexadecimal (base16) -> base14.
You can make it slightly more flexible by dividing the hash in 14 (parts) zones and prefix the zone you need in the
#0   1   2   3   4   5   6   7   8   9   0   a    b   c   d
#9dfe494055d7174aad1c36151584bcc3b2a8d856ed028b76d5c0f1b9d8ec14f5

Open in new window


So zone 6 would be:
1584

then:   echo "obase=14; ibase=16; x=1584; print x, \"\\n\" " | bc   # (convert hex  -> base 14 gives:
2016
prefixing the zone id = 6

The Total code you issue will be:  1940162016    or 6201619401...
The lock can do the same math .... and should see the same for zone 6 ...

Author

Commented:
Thanks a lot for your help. I was great :)
Now I can go further in my project
Thanks !

Author

Commented:
Thanks a lot noci !!

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial