#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the
# GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
# E-mail: linotp@lsexperts.de
# Contact: www.linotp.org
# Support: www.lsexperts.de
#
'''
This module can be used to create the optical challenge image for Feitian
c601 token.
c601:
Either you can create a single challenge that will display the OTP response
calculate_optical_data(value="12345678")
or you can split the challenge into ACCOUNT and AMOUNT.
calculate_optical_data(value="12345", type=ACCOUNT)
calculate_optical_data(value="67890", type=AMOUNT)
The challenge then will be AMOUNT+ACCOUNT (6789012345)
'''
CHALLENGE = [0, 1]
ACCOUNT = [1, 1]
AMOUNT = [1, 0]
DELAY_BLACK = 5
DELAY_WHITE = 5
DELAY_GRAY = 5
def _calculate_sum(value):
sum = 0;
alternate = True;
for c in value:
n = ord(c) & 0x0f
if alternate:
v = n * 2
if v > 9:
sum += 1 + (v % 10)
else:
sum += v
alternate = False
else:
sum += n
alternate = True
return (10 - (sum % 10)) % 10
def _modify_optical(optical):
'''
Takes the optical array and modifies it to the three
black = 0
gray = 1
white = 2
values
'''
ret_optical = []
t = 0
ret_optical.append(t)
for o in optical[:-1]:
if o == 1:
t = t + 1
if t > 2:
t = 0
else:
t = t - 1
if t < 0:
t = 2
ret_optical.append(t)
return ret_optical
[docs]def calculate_optical_data(value="", type=CHALLENGE):
''' create an array, representing black and white (1 and 0)
type
0,1 : Default challenge
1,1 : Account
1,0 : Amount
value
Input challenge Data: A numerical string
'''
# sanity checks
if len(type) != 2:
raise Exception("The type is limited to a length of 2.")
value_int = int(value)
if type == CHALLENGE:
if len(value) > 59:
raise Exception("The length of the challenge value is limited to 59.")
if len(value) < 8:
raise Exception("The length of the challenge value must be a minimum of 8.")
if type == ACCOUNT or type == AMOUNT:
if len(value) > 6:
raise Exception("You should not use amount or account longer than 6, as it will not be displayerd.")
optical = []
# header
optical.append(1)
optical.append(1)
optical.append(1)
optical.append(1)
optical.append(1)
optical.append(0)
# type
optical.append(type[0])
optical.append(type[1])
# Length
L = "%02d" % len(value)
# convert a "9" to a binary 1001
# Lenght
for c in L:
optical.append(ord(c) >> 3 & 0x01)
optical.append(ord(c) >> 2 & 0x01)
optical.append(ord(c) >> 1 & 0x01)
optical.append(ord(c) & 0x01)
# data
for v in value:
optical.append(ord(v) >> 3 & 0x01)
optical.append(ord(v) >> 2 & 0x01)
optical.append(ord(v) >> 1 & 0x01)
optical.append(ord(v) & 0x01)
# checksum
# sum 0011 - 3 0010 - 2 0001 - 1
bin = int("%d%d" % (type[0], type[1]))
bin_str = "%d" % bin
# type + len + value
sum_data = bin_str + L + value
sum = _calculate_sum(sum_data)
optical.append(sum >> 3 & 0x01)
optical.append(sum >> 2 & 0x01)
optical.append(sum >> 1 & 0x01)
optical.append(sum & 0x01)
optical = _modify_optical(optical)
return optical
def _create_image(optical, outfile="challenge.gif", delay=(DELAY_WHITE, DELAY_GRAY, DELAY_BLACK)):
'''
Creates an animated GIF for the given data array
which is the output of calculate optical data
'''
input_files = ""
for o in optical:
if o == 2:
input_files += " -delay %d white.gif " % delay[0]
elif o == 1:
input_files += " -delay %d gray.gif " % delay[1]
elif o == 0:
input_files += " -delay %d black.gif " % delay[2]
command = "convert %s -loop 0 %s" % (input_files, outfile)
os.system(command)
if __name__ == '__main__':
import os
# data for challenge 12345678
demo_data_challenge = [ 0, 1, 2, 0, 1, 2, 1, 0, 1, 0, 2, 1, 0, 1, 0, 2, 1, 0, 2, 1, 2, 1, 0, 1, 0, 2, 1, 2, 0, 2, 0, 2, 1, 0, 1, 0, 1, 0, 1, 2, 1, 0, 1, 2, 0, 1, 0, 2, 1, 0, 2, 0]
optical = calculate_optical_data(value="12345678")
print "-" * 70
print "Cha D: %s" % demo_data_challenge
print "Cha O: %s " % optical
_create_image(optical)
# data for account 12345
demo_data_account = [0, 1, 2, 0, 1, 2, 1, 2, 0, 2, 1, 0, 2, 1, 2, 1, 2, 1, 0, 2, 0, 2, 1, 2, 1, 0, 2, 0, 1, 0, 1, 0, 2, 1, 2, 1, 2, 1, 2, 0]
optical = calculate_optical_data(value="12345", type=ACCOUNT)
print "-" * 70
print "Acc D: %s" % demo_data_account
print "Acc O: %s " % optical
_create_image(optical, outfile="account.gif")
# data for amount
demo_data_amount = [0, 1, 2, 0, 1, 2, 1, 2, 1, 0, 2, 1, 0, 2, 0, 2, 0, 2, 0, 1, 0, 2, 0, 1, 2, 0, 2, 1, 0, 1, 0, 2, 0, 2, 1, 0, 2, 1, 2, 0]
optical = calculate_optical_data(value="67890", type=AMOUNT)
print "-" * 70
print "Amo D: %s" % demo_data_amount
print "Amo O: %s " % optical
_create_image(optical, outfile="amount.gif")