コード例 #1
0
    def generate_public_key_pair(self, p1, p2, data):
        """
        The GENERATE PUBLIC-KEY PAIR command either initiates the generation 
        and storing of a key pair, i.e., a public key and a private key, in the
        card, or accesses a key pair previously generated in the card.
        
        :param p1: should be 0x00 (generate new key)
        :param p2: '00' (no information provided) or reference of the key to be generated
        :param data: One or more CRTs associated to the key generation if P1-P2 different from '0000'
        """

        from Crypto.PublicKey import RSA, DSA
        from Crypto.Util.randpool import RandomPool
        rnd = RandomPool()

        cipher = self.ct.algorithm

        c_class = locals().get(cipher, None)
        if c_class is None:
            raise SwError(SW["ERR_CONDITIONNOTSATISFIED"])

        if p1 & 0x01 == 0x00:  #Generate key
            PublicKey = c_class.generate(self.dst.keylength, rnd.get_bytes)
            self.dst.key = PublicKey
        else:
            pass  #Read key

        #Encode keys
        if cipher == "RSA":
            #Public key
            n = str(PublicKey.__getstate__()['n'])
            e = str(PublicKey.__getstate__()['e'])
            pk = ((0x81, len(n), n), (0x82, len(e), e))
            result = bertlv_pack(pk)
            #Private key
            d = PublicKey.__getstate__()['d']
        elif cipher == "DSA":
            #DSAParams
            p = str(PublicKey.__getstate__()['p'])
            q = str(PublicKey.__getstate__()['q'])
            g = str(PublicKey.__getstate__()['g'])
            #Public key
            y = str(PublicKey.__getstate__()['y'])
            pk = ((0x81, len(p), p), (0x82, len(q), q), (0x83, len(g), g),
                  (0x84, len(y), y))
            #Private key
            x = str(PublicKey.__getstate__()['x'])
        #Add more algorithms here
        #elif cipher = "ECDSA":
        else:
            raise SwError(SW["ERR_CONDITIONNOTSATISFIED"])

        result = bertlv_pack([[0x7F49, len(pk), pk]])
        #TODO: Internally store key pair

        if p1 & 0x02 == 0x02:
            #We do not support extended header lists yet
            raise SwError["ERR_NOTSUPPORTED"]
        else:
            return SW["NORMAL"], result
コード例 #2
0
ファイル: nPA.py プロジェクト: NabilNoaman/vsmartcard
    def parse_SE_config(self, config):
        r = 0x9000
        try:
            ControlReferenceTemplate.parse_SE_config(self, config)
        except SwError as e:
            structure = unpack(config)
            for tlv in structure:
                tag, length, value = tlv
                if tag == 0x7f4c:
                    self.chat = CHAT(bertlv_pack([[tag, length, value]]))
                    print(self.chat)
                elif tag == 0x67:
                    self.auxiliary_data = bertlv_pack([[tag, length, value]])
                elif tag == 0x80 or tag == 0x84 or tag == 0x83 or tag == 0x91:
                    # handled by ControlReferenceTemplate.parse_SE_config
                    pass
                else:
                    raise SwError(SW["ERR_REFNOTUSABLE"])

        structure = unpack(config)

        pin_ref_str = '%c'% self.PACE_PIN
        for tlv in structure:
            if [0x83, len(pin_ref_str), pin_ref_str] == tlv:
                if self.sam.counter <= 0:
                    r = 0x63c0
                elif self.sam.counter == 1:
                    r = 0x63c1
                elif self.sam.counter == 2:
                    r = 0x63c2

        return r, ""
コード例 #3
0
ファイル: SEutils.py プロジェクト: 12019/vsmartcard
    def generate_public_key_pair(self, p1, p2, data):
        """
        The GENERATE PUBLIC-KEY PAIR command either initiates the generation 
        and storing of a key pair, i.e., a public key and a private key, in the
        card, or accesses a key pair previously generated in the card.
        
        :param p1: should be 0x00 (generate new key)
        :param p2: '00' (no information provided) or reference of the key to be generated
        :param data: One or more CRTs associated to the key generation if P1-P2 different from '0000'
        """
        
        from Crypto.PublicKey import RSA, DSA
        from Crypto.Util.randpool import RandomPool
        rnd = RandomPool()

        cipher = self.ct.algorithm

        c_class = locals().get(cipher, None)
        if c_class is None: 
            raise SwError(SW["ERR_CONDITIONNOTSATISFIED"])

        if p1 & 0x01 == 0x00: #Generate key
            PublicKey = c_class.generate(self.dst.keylength, rnd.get_bytes)
            self.dst.key = PublicKey
        else:
            pass #Read key

        #Encode keys
        if cipher == "RSA":
            #Public key
            n = str(PublicKey.__getstate__()['n'])
            e = str(PublicKey.__getstate__()['e'])
            pk = ((0x81, len(n), n), (0x82, len(e), e))
            result = bertlv_pack(pk)
            #Private key
            d = PublicKey.__getstate__()['d']
        elif cipher == "DSA":
            #DSAParams
            p = str(PublicKey.__getstate__()['p'])
            q = str(PublicKey.__getstate__()['q'])
            g = str(PublicKey.__getstate__()['g'])
            #Public key
            y = str(PublicKey.__getstate__()['y'])
            pk = ((0x81, len(p), p), (0x82, len(q), q), (0x83, len(g), g), 
                  (0x84, len(y), y))
            #Private key
            x = str(PublicKey.__getstate__()['x'])
        #Add more algorithms here
        #elif cipher = "ECDSA":
        else:
            raise SwError(SW["ERR_CONDITIONNOTSATISFIED"])

        result = bertlv_pack([[0x7F49, len(pk), pk]])
        #TODO: Internally store key pair

        if p1 & 0x02 == 0x02:
            #We do not support extended header lists yet
            raise SwError["ERR_NOTSUPPORTED"]
        else:
            return SW["NORMAL"], result
コード例 #4
0
ファイル: nPA.py プロジェクト: junaid124/vsmartcard
    def parse_SE_config(self, config):
        r = 0x9000
        try:
            ControlReferenceTemplate.parse_SE_config(self, config)
        except SwError as e:
            structure = unpack(config)
            for tlv in structure:
                tag, length, value = tlv
                if tag == 0x7f4c:
                    self.chat = CHAT(bertlv_pack([[tag, length, value]]))
                    print(self.chat)
                elif tag == 0x67:
                    self.auxiliary_data = bertlv_pack([[tag, length, value]])
                elif tag == 0x80 or tag == 0x84 or tag == 0x83 or tag == 0x91:
                    # handled by ControlReferenceTemplate.parse_SE_config
                    pass
                else:
                    raise SwError(SW["ERR_REFNOTUSABLE"])

        return r, ""
コード例 #5
0
ファイル: nPA.py プロジェクト: 12019/vsmartcard
    def parse_SE_config(self, config):
        r = 0x9000
        try:
            ControlReferenceTemplate.parse_SE_config(self, config)
        except SwError as e:
            structure = unpack(config)
            for tlv in structure:
                tag, length, value = tlv
                if tag == 0x7f4c:
                    self.chat = CHAT(bertlv_pack([[tag, length, value]]))
                    print(self.chat)
                elif tag == 0x67:
                    self.auxiliary_data = bertlv_pack([[tag, length, value]])
                elif tag == 0x80 or tag == 0x84 or tag == 0x83 or tag == 0x91:
                    # handled by ControlReferenceTemplate.parse_SE_config
                    pass
                else:
                    raise SwError(SW["ERR_REFNOTUSABLE"])

        return r, ""
コード例 #6
0
ファイル: nPA.py プロジェクト: Jdi99y515/vsmartcard
    def protect_response(self, sw, result):
        """
        This method protects a response APDU using secure messaging mechanisms
        
        :returns: the protected data and the SW bytes
        """

        return_data = ""

        if result != "":
            # Encrypt the data included in the RAPDU
            encrypted = self.encipher(0x82, 0x80, result)
            encrypted = "\x01" + encrypted
            encrypted_tlv = bertlv_pack([(
                                SM_Class["CRYPTOGRAM_PADDING_INDICATOR_ODD"],
                                len(encrypted),
                                encrypted)])
            return_data += encrypted_tlv 

        sw_str = inttostring(sw)
        length = len(sw_str) 
        tag = SM_Class["PLAIN_PROCESSING_STATUS"]
        tlv_sw = bertlv_pack([(tag, length, sw_str)])
        return_data += tlv_sw
        
        if self.cct.algorithm == None:
            raise SwError(SW["CONDITIONSNOTSATISFIED"])
        elif self.cct.algorithm == "CC":
            tag = SM_Class["CHECKSUM"]
            padded = vsCrypto.append_padding(self.cct.blocklength, return_data)
            auth = self.compute_cryptographic_checksum(0x8E, 0x80, padded)
            length = len(auth)
            return_data += bertlv_pack([(tag, length, auth)])
        elif self.cct.algorithm == "SIGNATURE":
            tag = SM_Class["DIGITAL_SIGNATURE"]
            hash = self.hash(0x90, 0x80, return_data)
            auth = self.compute_digital_signature(0x9E, 0x9A, hash)
            length = len(auth)
            return_data += bertlv_pack([(tag, length, auth)])
        
        return sw, return_data
コード例 #7
0
    def protect_response(self, sw, result):
        """
        This method protects a response APDU using secure messaging mechanisms

        :returns: the protected data and the SW bytes
        """

        return_data = b""

        if result:
            # Encrypt the data included in the RAPDU
            encrypted = self.encipher(0x82, 0x80, result)
            encrypted = b"\x01" + encrypted
            encrypted_tlv = bertlv_pack([
                (SM_Class["CRYPTOGRAM_PADDING_INDICATOR_ODD"], len(encrypted),
                 encrypted)
            ])
            return_data += encrypted_tlv

        sw_str = inttostring(sw)
        length = len(sw_str)
        tag = SM_Class["PLAIN_PROCESSING_STATUS"]
        tlv_sw = bertlv_pack([(tag, length, sw_str)])
        return_data += tlv_sw

        if self.cct.algorithm is None:
            raise SwError(SW["CONDITIONSNOTSATISFIED"])
        elif self.cct.algorithm == "CC":
            tag = SM_Class["CHECKSUM"]
            padded = vsCrypto.append_padding(self.cct.blocklength, return_data)
            auth = self.compute_cryptographic_checksum(0x8E, 0x80, padded)
            length = len(auth)
            return_data += bertlv_pack([(tag, length, auth)])
        elif self.cct.algorithm == "SIGNATURE":
            tag = SM_Class["DIGITAL_SIGNATURE"]
            hash = self.hash(0x90, 0x80, return_data)
            auth = self.compute_digital_signature(0x9E, 0x9A, hash)
            length = len(auth)
            return_data += bertlv_pack([(tag, length, auth)])

        return sw, return_data
コード例 #8
0
ファイル: nPA.py プロジェクト: Jdi99y515/vsmartcard
    def verify_certificate(self, p1, p2, data):
        if (p1, p2) != (0x00, 0xbe):
            raise SwError(SW["ERR_INCORRECTPARAMETERS"])

        cert = bertlv_pack([[0x7f21, len(data), data]])
        if 1 != eac.TA_STEP2_import_certificate(self.eac_ctx, cert):
            eac.print_ossl_err()
            raise SwError(SW["ERR_NOINFO69"]) 

        print "Imported Certificate"

        return ""
コード例 #9
0
    def verify_certificate(self, p1, p2, data):
        if (p1, p2) != (0x00, 0xbe):
            raise SwError(SW["ERR_INCORRECTPARAMETERS"])

        cert = bertlv_pack([[0x7f21, len(data), data]])
        if 1 != eac.TA_STEP2_import_certificate(self.eac_ctx, cert):
            eac.print_ossl_err()
            raise SwError(SW["ERR_NOINFO69"])

        print("Imported Certificate")

        return b""
コード例 #10
0
    def parse_SE_config(self, config):
        r = 0x9000
        try:
            ControlReferenceTemplate.parse_SE_config(self, config)
        except SwError as e:
            structure = unpack(config)
            for tlv in structure:
                tag, length, value = tlv
                if tag == 0x7f4c:
                    self.chat = CHAT(bertlv_pack([[tag, length, value]]))
                elif tag == 0x67:
                    self.auxiliary_data = bertlv_pack([[tag, length, value]])
                    # extract reference values for verifying
                    # DateOfBirth, DateOfExpiry and CommunityID
                    for ddo in decodeDiscretionaryDataObjects(value):
                        try:
                            oidvalue = ddo[0][2]
                            reference = ddo[1][2]
                            mapped_algo = ALGO_MAPPING[oidvalue]
                            if mapped_algo == "DateOfBirth":
                                self.DateOfBirth = int(reference)
                                logging.info("Found reference DateOfBirth: " +
                                             str(self.DateOfBirth))
                            elif mapped_algo == "DateOfExpiry":
                                self.DateOfExpiry = int(reference)
                                logging.info("Found reference DateOfExpiry: " +
                                             str(self.DateOfExpiry))
                            elif mapped_algo == "CommunityID":
                                self.CommunityID = binascii.hexlify(reference)
                                logging.info("Found reference CommunityID: " +
                                             str(self.CommunityID))
                        except:
                            pass
                elif tag == 0x80 or tag == 0x84 or tag == 0x83 or tag == 0x91:
                    # handled by ControlReferenceTemplate.parse_SE_config
                    pass
                else:
                    raise SwError(SW["ERR_REFNOTUSABLE"])

        return r, b""
コード例 #11
0
ファイル: nPA.py プロジェクト: Snyper4277/vsmartcard
    def parse_SE_config(self, config):
        r = 0x9000
        try:
            ControlReferenceTemplate.parse_SE_config(self, config)
        except SwError as e:
            structure = unpack(config)
            for tlv in structure:
                tag, length, value = tlv
                if tag == 0x7f4c:
                    self.chat = CHAT(bertlv_pack([[tag, length, value]]))
                elif tag == 0x67:
                    self.auxiliary_data = bertlv_pack([[tag, length, value]])
                    # extract reference values for verifying
                    # DateOfBirth, DateOfExpiry and CommunityID
                    for ddo in decodeDiscretionaryDataObjects(value):
                        try:
                            oidvalue = ddo[0][2]
                            reference = ddo[1][2]
                            mapped_algo = ALGO_MAPPING[oidvalue]
                            if mapped_algo == "DateOfBirth":
                                self.DateOfBirth = int(reference)
                                logging.info("Found reference DateOfBirth: " +
                                             str(self.DateOfBirth))
                            elif mapped_algo == "DateOfExpiry":
                                self.DateOfExpiry = int(reference)
                                logging.info("Found reference DateOfExpiry: " +
                                             str(self.DateOfExpiry))
                            elif mapped_algo == "CommunityID":
                                self.CommunityID = binascii.hexlify(reference)
                                logging.info("Found reference CommunityID: " +
                                             str(self.CommunityID))
                        except:
                            pass
                elif tag == 0x80 or tag == 0x84 or tag == 0x83 or tag == 0x91:
                    # handled by ControlReferenceTemplate.parse_SE_config
                    pass
                else:
                    raise SwError(SW["ERR_REFNOTUSABLE"])

        return r, ""
コード例 #12
0
ファイル: nPA.py プロジェクト: Jdi99y515/vsmartcard
 def __pack_general_authenticate(data):
     tlv_data = bertlv_pack(data)
     return bertlv_pack([[0x7c, len(tlv_data), tlv_data]])
コード例 #13
0
    def parse_SM_CAPDU(self, CAPDU, authenticate_header):
        """
        This methods parses a data field including Secure Messaging objects.
        SM_header indicates whether or not the header of the message shall be 
        authenticated. It returns an unprotected command APDU
        
        :param CAPDU: The protected CAPDU to be parsed
        :param authenticate_header: Whether or not the header should be
            included in authentication mechanisms 
        :returns: Unprotected command APDU
        """

        structure = unpack(CAPDU.data)
        return_data = [
            "",
        ]

        cla = None
        ins = None
        p1 = None
        p2 = None
        le = None

        if authenticate_header:
            to_authenticate = inttostring(CAPDU.cla) + inttostring(CAPDU.ins)+\
                              inttostring(CAPDU.p1) + inttostring(CAPDU.p2)
            to_authenticate = vsCrypto.append_padding(self.cct.blocklength,
                                                      to_authenticate)
        else:
            to_authenticate = ""

        for tlv in structure:
            tag, length, value = tlv

            if tag % 2 == 1:  #Include object in checksum calculation
                to_authenticate += bertlv_pack([[tag, length, value]])

            #SM data objects for encapsulating plain values
            if tag in (SM_Class["PLAIN_VALUE_NO_TLV"],
                       SM_Class["PLAIN_VALUE_NO_TLV_ODD"]):
                return_data.append(value)  #FIXME: Need TLV coding?
            #Encapsulated SM objects. Parse them
            #FIXME: Need to pack value into a dummy CAPDU
            elif tag in (SM_Class["PLAIN_VALUE_TLV_INCULDING_SM"],
                         SM_Class["PLAIN_VALUE_TLV_INCULDING_SM_ODD"]):
                return_data.append(
                    self.parse_SM_CAPDU(value, authenticate_header))
            #Encapsulated plaintext BER-TLV objects
            elif tag in (SM_Class["PLAIN_VALUE_TLV_NO_SM"],
                         SM_Class["PLAIN_VALUE_TLV_NO_SM_ODD"]):
                return_data.append(value)
            elif tag in (SM_Class["Ne"], SM_Class["Ne_ODD"]):
                le = value
            elif tag == SM_Class["PLAIN_COMMAND_HEADER"]:
                if len(value) != 8:
                    raise SwError(SW["ERR_SECMESSOBJECTSINCORRECT"])
                else:
                    cla = value[:2]
                    ins = value[2:4]
                    p1 = value[4:6]
                    p2 = value[6:8]

            #SM data objects for confidentiality
            if tag in (SM_Class["CRYPTOGRAM_PLAIN_TLV_INCLUDING_SM"],
                       SM_Class["CRYPTOGRAM_PLAIN_TLV_INCLUDING_SM_ODD"]):
                #The cryptogram includes SM objects.
                #We decrypt them and parse the objects.
                plain = self.decipher(tag, 0x80, value)
                #TODO: Need Le = length
                return_data.append(
                    self.parse_SM_CAPDU(plain, authenticate_header))
            elif tag in (SM_Class["CRYPTOGRAM_PLAIN_TLV_NO_SM"],
                         SM_Class["CRYPTOGRAM_PLAIN_TLV_NO_SM_ODD"]):
                #The cryptogram includes BER-TLV encoded plaintext.
                #We decrypt them and return the objects.
                plain = self.decipher(tag, 0x80, value)
                return_data.append(plain)
            elif tag in (SM_Class["CRYPTOGRAM_PADDING_INDICATOR"],
                         SM_Class["CRYPTOGRAM_PADDING_INDICATOR_ODD"]):
                #The first byte of the data field indicates the padding to use:
                """
                Value        Meaning
                '00'     No further indication
                '01'     Padding as specified in 6.2.3.1
                '02'     No padding
                '1X'     One to four secret keys for enciphering information,
                         not keys ('X' is a bitmap with any value from '0' to 'F')
                '11'     indicates the first key (e.g., an "even" control word
                         in a pay TV system)
                '12'     indicates the second key (e.g., an "odd" control word
                         in a pay TV system)
                '13'     indicates the first key followed by the second key
                         (e.g., a pair of control words in a pay TV system)
                '2X'     Secret key for enciphering keys, not information
                         ('X' is a reference with any value from '0' to 'F')
                         (e.g., in a pay TV system, either an operational key
                         for enciphering control words, or a management key for
                         enciphering operational keys)
                '3X'     Private key of an asymmetric key pair ('X' is a
                         reference with any value from '0' to 'F')
                '4X'     Password ('X' is a reference with any value from '0' to
                         'F')
            '80' to '8E' Proprietary
                """
                padding_indicator = stringtoint(value[0])
                plain = self.decipher(tag, 0x80, value[1:])
                plain = vsCrypto.strip_padding(self.ct.blocklength, plain,
                                               padding_indicator)
                return_data.append(plain)

            #SM data objects for authentication
            if tag == SM_Class["CHECKSUM"]:
                auth = vsCrypto.append_padding(self.cct.blocklength,
                                               to_authenticate)
                checksum = self.compute_cryptographic_checksum(
                    0x8E, 0x80, auth)
                if checksum != value:
                    raise SwError(SW["ERR_SECMESSOBJECTSINCORRECT"])
            elif tag == SM_Class["DIGITAL_SIGNATURE"]:
                auth = to_authenticate  #FIXME: Need padding?
                signature = self.compute_digital_signature(0x9E, 0x9A, auth)
                if signature != value:
                    raise SwError(SW["ERR_SECMESSOBJECTSINCORRECT"])
            elif tag in (SM_Class["HASH_CODE"], SM_Class["HASH_CODE_ODD"]):
                hash = self.hash(p1, p2, to_authenticate)
                if hash != value:
                    raise SwError(SW["ERR_SECMESSOBJECTSINCORRECT"])

        #Form unprotected CAPDU
        if cla == None:
            cla = CAPDU.cla
        if ins == None:
            ins = CAPDU.ins
        if p1 == None:
            p1 = CAPDU.p1
        if p2 == None:
            p2 = CAPDU.p2
        # FIXME
        #if expected != "":
        #raise SwError(SW["ERR_SECMESSOBJECTSMISSING"])

        if isinstance(le, str):
            # FIXME C_APDU only handles le with strings of length 1. Better patch utils.py to support extended length apdus
            le_int = stringtoint(le)
            if le_int == 0 and len(le) > 1:
                le_int = MAX_EXTENDED_LE
            le = le_int

        c = C_APDU(cla=cla,
                   ins=ins,
                   p1=p1,
                   p2=p2,
                   le=le,
                   data="".join(return_data))
        return c
コード例 #14
0
 def __pack_general_authenticate(data):
     tlv_data = bertlv_pack(data)
     return bertlv_pack([[0x7c, len(tlv_data), tlv_data]])
コード例 #15
0
ファイル: SEutils.py プロジェクト: 12019/vsmartcard
    def parse_SM_CAPDU(self, CAPDU, authenticate_header):
        """
        This methods parses a data field including Secure Messaging objects.
        SM_header indicates whether or not the header of the message shall be 
        authenticated. It returns an unprotected command APDU
        
        :param CAPDU: The protected CAPDU to be parsed
        :param authenticate_header: Whether or not the header should be
            included in authentication mechanisms 
        :returns: Unprotected command APDU
        """
            
        structure = unpack(CAPDU.data)
        return_data = ["",]
        
        cla = None
        ins = None
        p1 = None
        p2 = None
        le = None
        
        if authenticate_header:
            to_authenticate = inttostring(CAPDU.cla) + inttostring(CAPDU.ins)+\
                              inttostring(CAPDU.p1) + inttostring(CAPDU.p2)
            to_authenticate = vsCrypto.append_padding(self.cct.blocklength, to_authenticate)
        else:
            to_authenticate = ""

        for tlv in structure:
            tag, length, value = tlv
            
            if tag % 2 == 1: #Include object in checksum calculation
                to_authenticate += bertlv_pack([[tag, length, value]])
            
            #SM data objects for encapsulating plain values
            if tag in (SM_Class["PLAIN_VALUE_NO_TLV"],
                       SM_Class["PLAIN_VALUE_NO_TLV_ODD"]):
                return_data.append(value) #FIXME: Need TLV coding?
            #Encapsulated SM objects. Parse them
            #FIXME: Need to pack value into a dummy CAPDU
            elif tag in (SM_Class["PLAIN_VALUE_TLV_INCULDING_SM"],
                         SM_Class["PLAIN_VALUE_TLV_INCULDING_SM_ODD"]):
                return_data.append(self.parse_SM_CAPDU(value, authenticate_header)) 
            #Encapsulated plaintext BER-TLV objects
            elif tag in (SM_Class["PLAIN_VALUE_TLV_NO_SM"],
                         SM_Class["PLAIN_VALUE_TLV_NO_SM_ODD"]):
                return_data.append(value)
            elif tag in (SM_Class["Ne"], SM_Class["Ne_ODD"]):
                le = value
            elif tag == SM_Class["PLAIN_COMMAND_HEADER"]:
                if len(value) != 8:
                    raise SwError(SW["ERR_SECMESSOBJECTSINCORRECT"])
                else:
                    cla = value[:2]
                    ins = value[2:4]
                    p1 = value[4:6]
                    p2 = value[6:8]

            #SM data objects for confidentiality
            if tag in (SM_Class["CRYPTOGRAM_PLAIN_TLV_INCLUDING_SM"],
                       SM_Class["CRYPTOGRAM_PLAIN_TLV_INCLUDING_SM_ODD"]):
                #The cryptogram includes SM objects. 
                #We decrypt them and parse the objects.
                plain = self.decipher(tag, 0x80, value)
                #TODO: Need Le = length
                return_data.append(self.parse_SM_CAPDU(plain, authenticate_header))
            elif tag in (SM_Class["CRYPTOGRAM_PLAIN_TLV_NO_SM"],
                         SM_Class["CRYPTOGRAM_PLAIN_TLV_NO_SM_ODD"]):
                #The cryptogram includes BER-TLV encoded plaintext. 
                #We decrypt them and return the objects.
                plain = self.decipher(tag, 0x80, value)
                return_data.append(plain)
            elif tag in (SM_Class["CRYPTOGRAM_PADDING_INDICATOR"],
                         SM_Class["CRYPTOGRAM_PADDING_INDICATOR_ODD"]):
                #The first byte of the data field indicates the padding to use:
                """
                Value        Meaning
                '00'     No further indication
                '01'     Padding as specified in 6.2.3.1
                '02'     No padding
                '1X'     One to four secret keys for enciphering information,
                         not keys ('X' is a bitmap with any value from '0' to 'F')
                '11'     indicates the first key (e.g., an "even" control word
                         in a pay TV system)
                '12'     indicates the second key (e.g., an "odd" control word
                         in a pay TV system)
                '13'     indicates the first key followed by the second key
                         (e.g., a pair of control words in a pay TV system)
                '2X'     Secret key for enciphering keys, not information
                         ('X' is a reference with any value from '0' to 'F')
                         (e.g., in a pay TV system, either an operational key
                         for enciphering control words, or a management key for
                         enciphering operational keys)
                '3X'     Private key of an asymmetric key pair ('X' is a
                         reference with any value from '0' to 'F')
                '4X'     Password ('X' is a reference with any value from '0' to
                         'F')
            '80' to '8E' Proprietary
                """
                padding_indicator = stringtoint(value[0])
                plain = self.decipher(tag, 0x80, value[1:])
                plain = vsCrypto.strip_padding(self.ct.blocklength, plain,
                                               padding_indicator)
                return_data.append(plain)

            #SM data objects for authentication 
            if tag == SM_Class["CHECKSUM"]:
                auth = vsCrypto.append_padding(self.cct.blocklength, to_authenticate)
                checksum = self.compute_cryptographic_checksum(0x8E,
                                                                   0x80,
                                                                   auth)
                if checksum != value:
                    raise SwError(SW["ERR_SECMESSOBJECTSINCORRECT"])
            elif tag == SM_Class["DIGITAL_SIGNATURE"]:
                auth = to_authenticate #FIXME: Need padding?
                signature = self.compute_digital_signature(0x9E, 0x9A, auth)
                if signature != value:
                    raise SwError(SW["ERR_SECMESSOBJECTSINCORRECT"])
            elif tag in (SM_Class["HASH_CODE"], SM_Class["HASH_CODE_ODD"]):
                hash = self.hash(p1, p2, to_authenticate)
                if hash != value:
                    raise SwError(SW["ERR_SECMESSOBJECTSINCORRECT"])
                
        #Form unprotected CAPDU
        if cla == None:
            cla = CAPDU.cla
        if ins == None:
            ins = CAPDU.ins
        if p1 == None:
            p1 = CAPDU.p1
        if p2 == None:
            p2 = CAPDU.p2
        if le == None:
            le = CAPDU.le
        # FIXME
        #if expected != "":
            #raise SwError(SW["ERR_SECMESSOBJECTSMISSING"])

        if isinstance(le, str):
            # FIXME C_APDU only handles le with strings of length 1. Better patch utils.py to support extended length apdus
            le_int = stringtoint(le)
            if le_int == 0 and len(le) > 1:
                le_int = MAX_EXTENDED_LE
            le = le_int
        
        c = C_APDU(cla=cla, ins=ins, p1=p1, p2=p2, le=le, data="".join(return_data))
        return c