Source code for linotp.lib.feitian

#
#    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")