def fill(self, d): self._d = d self.version = STN.str2int(d[0:1]) self.type = STN.str2int(d[1:2]) self.alg_hash = STN.str2int(d[2:3]) self.alg_pubkey = STN.str2int(d[3:4]) self.keyid = STN.str2hex(d[4:12]) self.nest = STN.str2int(d[12:13])
def testB0BadTypesS2N(self): "strnum: str2int bad types" for b in self.bad_types: try: str2int(b) except: # make sure any old exception is raised pass else: raise
def testF01ElGamal(self): """crypto.cipher: decrypt_public() ElGamal-encrypted session key""" #encmsg_d = read_test_file(['pgpfiles','enc','pub.elg.aes256.clrtxt.gpg']) encmsg_d = read_test_file( ['pgpfiles', 'enc', 'pub.elg.cast.clrtxt.gpg']) encmsg = list_msgs(list_pkts(encmsg_d))[0] seskeypkt = encmsg.targets[0] # target = session key # get target secret key (in this case, a subkey) keymsg_d = read_test_file( ['pgpfiles', 'key', 'DSAELG1.sec.nopass.gpg']) keymsg = list_msgs(list_pkts(keymsg_d))[0] for block in keymsg._b_subkeys.list(): subkey = block.leader if seskeypkt.body.keyid == subkey.body.id: break # leave with the appropriate subkey # I know the target in question is an ElGamal key key_tuple = (subkey.body.ELGAMAL_p.value, subkey.body.ELGAMAL_x.value) cipher_tuple = (seskeypkt.body.ELGAMAL_gk_modp.value, seskeypkt.body.ELGAMAL_myk_modp.value) # retrieving the PKCS, etc., padded session key padded_message = decrypt_public(seskeypkt.body.alg_pubkey, key_tuple, cipher_tuple) # Rules from rfc 2437 9.1.2.2: # 1. Padding starts with 0x02. # 2. Padding continues with >= 8 octets non-zero gibberish. # 3. Gibberish concludes with 0x00. # 4. Remaining data is the message. if '\x02' == padded_message[0]: idx = padded_message.find('\x00') if -1 != idx and 8 <= idx: message = padded_message[idx + 1:] chksum = str2int(message[-2:]) ciphertype = str2int(message[0]) key = message[1:len(message) - 2] i = 0 for e in key: i += str2int(e) # TODO check chksum cleartext = decrypt_symmetric(ciphertype, key, encmsg.encrypted.body.data) else: errmsg = "Misplaced \\x00 in session key padding, located at index->(%s)" % idx else: errmsg = "Session key padding must start with \\x02, received->()" % hex( ord(padded_message[0])) cleartext = cleartext[10:] # ditching the prefix + 2 # result is a compressed message.. compressedmsg = list_msgs(list_pkts(cleartext))[0] newmsgs = list_msgs(list_pkts(compressedmsg.compressed.body.data)) # ..with only one literal data packet literal_data = newmsgs[0].literals[0].body.data # compare against original file clrtxt = read_test_file(['pgpfiles', 'cleartext.txt']) self.assertEqual(literal_data, clrtxt)
def testF01ElGamal(self): """crypto.cipher: decrypt_public() ElGamal-encrypted session key""" #encmsg_d = read_test_file(['pgpfiles','enc','pub.elg.aes256.clrtxt.gpg']) encmsg_d = read_test_file(['pgpfiles','enc','pub.elg.cast.clrtxt.gpg']) encmsg = list_msgs(list_pkts(encmsg_d))[0] seskeypkt = encmsg.targets[0] # target = session key # get target secret key (in this case, a subkey) keymsg_d = read_test_file(['pgpfiles','key','DSAELG1.sec.nopass.gpg']) keymsg = list_msgs(list_pkts(keymsg_d))[0] for block in keymsg._b_subkeys.list(): subkey = block.leader if seskeypkt.body.keyid == subkey.body.id: break # leave with the appropriate subkey # I know the target in question is an ElGamal key key_tuple = (subkey.body.ELGAMAL_p.value, subkey.body.ELGAMAL_x.value) cipher_tuple = (seskeypkt.body.ELGAMAL_gk_modp.value, seskeypkt.body.ELGAMAL_myk_modp.value) # retrieving the PKCS, etc., padded session key padded_message = decrypt_public(seskeypkt.body.alg_pubkey, key_tuple, cipher_tuple) # Rules from rfc 2437 9.1.2.2: # 1. Padding starts with 0x02. # 2. Padding continues with >= 8 octets non-zero gibberish. # 3. Gibberish concludes with 0x00. # 4. Remaining data is the message. if '\x02' == padded_message[0]: idx = padded_message.find('\x00') if -1 != idx and 8 <= idx: message = padded_message[idx+1:] chksum = str2int(message[-2:]) ciphertype = str2int(message[0]) key = message[1:len(message)-2] i = 0 for e in key: i += str2int(e) # TODO check chksum cleartext = decrypt_symmetric(ciphertype, key, encmsg.encrypted.body.data) else: errmsg = "Misplaced \\x00 in session key padding, located at index->(%s)" % idx else: errmsg = "Session key padding must start with \\x02, received->()" % hex(ord(padded_message[0])) cleartext = cleartext[10:] # ditching the prefix + 2 # result is a compressed message.. compressedmsg = list_msgs(list_pkts(cleartext))[0] newmsgs = list_msgs(list_pkts(compressedmsg.compressed.body.data)) # ..with only one literal data packet literal_data = newmsgs[0].literals[0].body.data # compare against original file clrtxt = read_test_file(['pgpfiles','cleartext.txt']) self.assertEqual(literal_data, clrtxt)
def fill(self, d): """oldlength.fill(d) Set the OldLength object's data, filling its attributes. Tag data (d) must be either 1, 2, or 4 octets containing the length (integer count) of the packet body (see rfc2004 4.2.1). :Parameters: - `d`: character (StringType, length == 1) :Returns: Nothing Example: >>> oldlength_octets = [0x88, 0x88] >>> oldlength_data_string = ''.join(map(chr, oldlength_octets)) >>> oldlength = OldLength() >>> oldlength.fill(oldlength_data_string) >>> oldlength.size 34952 """ if len(d) in [1, 2, 4]: self._d, self.size = d, STN.str2int(d) elif 0 == len(d): self._d, self.size = '', "UNDEFINED" else: raise PGPFormatError, "Old packet length data must come in 0, 1, 2, or 4 octets. Received->(%s octets)." % ( str(len(d)))
def fill(self, d): """oldlength.fill(d) Set the OldLength object's data, filling its attributes. Tag data (d) must be either 1, 2, or 4 octets containing the length (integer count) of the packet body (see rfc2004 4.2.1). :Parameters: - `d`: character (StringType, length == 1) :Returns: Nothing Example: >>> oldlength_octets = [0x88, 0x88] >>> oldlength_data_string = ''.join(map(chr, oldlength_octets)) >>> oldlength = OldLength() >>> oldlength.fill(oldlength_data_string) >>> oldlength.size 34952 """ if len(d) in [1, 2, 4]: self._d, self.size = d, STN.str2int(d) elif 0 == len(d): self._d, self.size = '', "UNDEFINED" else: raise PGPFormatError, "Old packet length data must come in 0, 1, 2, or 4 octets. Received->(%s octets)." % (str(len(d)))
def test01_int2str_str2int(self): "strnum: string/integer inversion (int2str/str2int)" body = self.key.body for i in [ body.DSA_p.value, body.DSA_q.value, body.DSA_g.value, body.DSA_y.value ]: self.assertEqual(i, str2int(int2str(i)))
def fill(self, d): self._d = d version_d = d[0] self.version, idx = STN.strcalc(STN.str2int, d[0], 0) if self.version in [2, 3]: hash_len, idx = STN.strcalc(STN.str2int, d[idx:idx+1], idx) self.type, idx = STN.strcalc(STN.str2int, d[idx:idx+1], idx) self.created, idx = STN.strcalc(STN.str2int, d[idx:idx+4], idx) self.hashed_data = d[2:idx] self.keyid, idx = STN.strcalc(STN.str2hex, d[idx:idx+8], idx) self.alg_pubkey, idx = STN.strcalc(STN.str2int, d[idx:idx+1], idx) self.alg_hash, idx = STN.strcalc(STN.str2int, d[idx:idx+1], idx) self.hashed_subpkts = [] # dummy settings to make searches easier self.unhashed_subpkts = [] # elif 4 == self.version: import struct _type_d, idx = STN.strcalc(None, d[idx:idx+1], idx) self.type = STN.str2int(_type_d) self.alg_pubkey, idx = STN.strcalc(STN.str2int, d[idx:idx+1], idx) self.alg_hash, idx = STN.strcalc(STN.str2int, d[idx:idx+1], idx) # hashed subpackets subpkts_len, idx = STN.strcalc(STN.str2int, d[idx:idx+2], idx) self.hashed_subpkts = self.__resolve_subpkts(d[idx:idx+subpkts_len]) # hashed data & trailer - should '>i' ever return more than 4 chars? hashed_data = d[0:idx+subpkts_len] bigend = struct.pack('>i', len(hashed_data))[-4:] self.hashed_data = ''.join([hashed_data, version_d, '\xff', bigend]) idx = idx + subpkts_len # unhashed subpackets subpkts_len, idx = STN.strcalc(STN.str2int, d[idx:idx+2], idx) self.unhashed_subpkts = self.__resolve_subpkts(d[idx:idx+subpkts_len]) idx = idx + subpkts_len # attribute convenience self.keyid = self.__set_subpkt_attr(SIGSUB_SIGNERID) or '' self.created = self.__set_subpkt_attr(SIGSUB_CREATED) or 0 else: raise PGPValueError("Unsupported signature version. Received->(%s)" % str(self.version)) self.hash_frag, idx = STN.strcalc(None, d[idx:idx+2], idx) if self.alg_pubkey in [ASYM_RSA_S, ASYM_RSA_EOS]: self.RSA, idx = MPI.strcalc_mpi(d[idx:], idx) elif ASYM_DSA == self.alg_pubkey: self.DSA_r, idx = MPI.strcalc_mpi(d[idx:], idx) self.DSA_s, idx = MPI.strcalc_mpi(d[idx:], idx) elif self.alg_pubkey in [ASYM_ELGAMAL_EOS]: self.ELGAMAL_a, idx = MPI.strcalc_mpi(d[idx:], idx) self.ELGAMAL_b, idx = MPI.strcalc_mpi(d[idx:], idx) else: raise PGPValueError("Unsupported public-key algorithm (%d)." % self.alg_pubkey)
def fill(self, d): import struct idx = 0 self._length_d, idx = STN.strcalc(None, d[idx:idx+2], idx) self.bit_length = STN.str2int(self._length_d) self.length = STN.mpilen2int(self._length_d) self._d = d[0:2+self.length] self._int_d = d[idx:idx+self.length] self.size = len(self._d) # explicitly.. i = struct.unpack('>'+str(len(self._int_d))+'s', self._int_d)[0] self.value = STN.str2int(i) if self.check(): pass else: raise self.err[0], self.err[1]
def fill(self, d): import struct idx = 0 self._length_d, idx = STN.strcalc(None, d[idx:idx + 2], idx) self.bit_length = STN.str2int(self._length_d) self.length = STN.mpilen2int(self._length_d) self._d = d[0:2 + self.length] self._int_d = d[idx:idx + self.length] self.size = len(self._d) # explicitly.. i = struct.unpack('>' + str(len(self._int_d)) + 's', self._int_d)[0] self.value = STN.str2int(i) if self.check(): pass else: raise self.err[0], self.err[1]
def fill(self, d): self._d = d self.format = d[0:1] self.fnlen = STN.str2int(d[1:2]) idx = 2 if 0 < self.fnlen: self.filename, idx = STN.strcalc(None, d[idx:idx+self.fnlen], idx) else: self.filename = None self.modified, idx = STN.strcalc(STN.str2int, d[idx:idx+4], idx) self.data = d[idx:]
def encrypt_public(algorithm, msg, key_tuple): """Encrypt data to a public key. :Parameters: - `algorithm`: integer public key algorithm constant - `key_tuple`: tuple containing a public and private integers the target key, RSA values (n, d) or ElGamal values (p, g, y) (see `RSA key tuple`_ and `ElGamal key tuple`_) :Returns: tuple ciphertext (a, b) for ElGamal and (r,) for RSA .. _RSA key tuple: RSA key tuple (n, e): - `n`: integer RSA product of primes p & q - `e`: integer RSA encryption key .. _ElGamal key tuple: ElGamal key tuple (p, g, y): - `p`: integer ElGamal prime - `g`: integer ElGamal group generator - `y`: integer ElGamal public key """ import Crypto.Util.number key_tuple = tuple([long(i) for i in key_tuple]) # fastmath dep if algorithm in [ASYM_RSA_EOS, ASYM_RSA_E]: from Crypto.PublicKey import RSA key = RSA.construct(key_tuple) k = '' elif algorithm in [ASYM_ELGAMAL_EOS, ASYM_ELGAMAL_E]: from Crypto.PublicKey import ElGamal key = ElGamal.construct(key_tuple) k = Crypto.Util.number.getPrime(128, gen_random) else: raise NotImplementedError, "Can't handle public encryption algorithm->(%s)" % algorithm enc_tup = key.encrypt(msg, k) # Crypto returns strings instead of integers. return tuple([STN.str2int(x) for x in enc_tup]) # Why?
def str2mpi(s, limit): """Convert a MPI byte-string into an integer. :Parameters: - `s`: MPI string - `limit`: *optional* maximum number of MPIs to search for :Returns: list of MPI values (integers/longs) """ import struct idx = 0 mpi_list = [] while True: if limit and limit == len(mpi_list): break mpilen_d, idx = read_slice(s, 2, idx) if 2 == len(mpilen_d): # we don't care about bit length, just the bytes containing them mpilen = mpilen2int(mpilen_d) int_d, idx = read_slice(s, mpilen, idx) len_int_d = len(int_d) if len_int_d == mpilen: i = struct.unpack('>' + str(len_int_d) + 's', int_d)[0] mpival = str2int(i) mpi_list.append(mpival) continue # if good, keep going break # otherwise quit return mpi_list, idx
def svt_int(): str2val = lambda string, limit: str2int(string[:limit]) val2str = lambda value, limit: _limit_int2str(value, limit) return str2val, val2str
def fill(self, d): self._d = d self.version = STN.str2int(d[0:1]) self.data = d[1:]
def fill(self, d): ord_d = ord(d[0]) if ord_d < 192: slice = d[0] size = ord_d elif 192 <= ord_d < 255: slice = d[:2] #size = size + STN.doubleoct2int(slice) size = STN.doubleoct2int(slice) elif 255 == ord_d: slice = d[:5] #size = size + STN.pentoct2int(slice) size = STN.pentoct2int(slice) len_slice = len(slice) self._d = d[:len_slice + size] type_d = d[len_slice:len_slice + 1] self.type = 127 & ord(type_d) self.critical = 128 & ord(type_d) value_d = d[len_slice + 1:len_slice + size] if SIGSUB_SIGNERID == self.type: self.value = STN.str2hex(value_d[:8]) elif self.type in [SIGSUB_CREATED, SIGSUB_EXPIRES, SIGSUB_KEYEXPIRES]: self.value = STN.str2int(value_d[:4]) self.value = STN.str2int(value_d) elif self.type in [ SIGSUB_EXPORTABLE, SIGSUB_REVOCABLE, SIGSUB_PRIMARYUID ]: self.value = STN.str2int(value_d[:1]) if self.value not in [0, 1]: raise SignatureSubpacketValueError, "Subpacket (# %s) value must be 0 or 1." % ( str(subtype)) elif SIGSUB_TRUST == self.type: # level, amount self.value = (STN.str2int(value_d[0]), STN.str2int(value_d[1])) elif self.type in [ SIGSUB_SYMCODE, SIGSUB_HASHCODE, SIGSUB_COMPCODE, SIGSUB_KEYSERVPREFS, SIGSUB_KEYFLAGS, SIGSUB_FEATURES ]: self.value = [ord(x) for x in value_d] elif SIGSUB_REVOKER == self.type: cls = STN.str2int(value_d[0]) alg = STN.str2int(value_d[1]) fprint = STN.str2hex(value_d[2:22]) self.value = (cls, alg, fprint) elif SIGSUB_NOTE == self.type: flags = [STN.str2int(x) for x in value_d[:4]] # first four flag octs name_len = STN.str2int(value_d[4:6]) val_len = STN.str2int(value_d[6:8]) nam = value_d[8:8 + name_len] val = value_d[8 + name_len:8 + name_len + val_len] self.value = (flags, nam, val) elif self.type in [ SIGSUB_KEYSERV, SIGSUB_POLICYURL, SIGSUB_SIGNERUID, SIGSUB_REGEX ]: self.value = value_d elif SIGSUB_REVOCREASON == self.type: # code, reason self.value = (STN.str2int(value_d[0]), value_d[1:]) elif SIGSUB_SIGTARGET == self.type: raise NotImplementedError, "SIGTARGET not supported" else: # the subpacket has an unknown type, so just pack the data in self.value = value_d
def decrypt_secret_key(keypkt, passphrase=''): """Retrieve decryption key values from a secret key packet. :Parameters: - `keypkt`: `OpenPGP.packet.SecretKey.SecretKey` instance or `OpenPGP.packet.SecretSubkey.SecretSubkey` instance - `passphrase`: optional decryption string :Returns: tuple of secret key integer values :Exceptions: - `PGPKeyDecryptionFailure`: secret key values did not encrypt properly Secret key tuples: - RSA keys: (d, p, q, u) - ElGamal keys: (x, ) - DSA keys: (x, ) :note: As far as key decryption goes, the only real check performed is the internal MPI check that the header, size, etc. make sense. Chances are slight that a failed decryption will render sensible MPIs. This is why the integrity checks are so important. """ if not hasattr(keypkt.body, 's2k_usg'): raise PGPCryptoError("Key material does not contain secret key values (missing s2k usage).") if 0 == keypkt.body.s2k_usg: if keypkt.body.alg in [ASYM_RSA_E, ASYM_RSA_EOS]: key_tuple = (keypkt.body.RSA_d.value, keypkt.body.RSA_p.value, keypkt.body.RSA_q.value, keypkt.body.RSA_u.value) elif keypkt.body.alg in [ASYM_ELGAMAL_E, ASYM_ELGAMAL_EOS]: key_tuple = keypkt.body.ELGAMAL_x.value, # coerce tuple elif keypkt.body.alg in [ASYM_DSA]: key_tuple = keypkt.body.DSA_x.value, # coerce tuple else: # ..'idx' comes into play during the integrity check if 3 >= keypkt.body.version: if keypkt.body.alg in [ASYM_RSA_E, ASYM_RSA_EOS]: alg = keypkt.body.alg_sym if keypkt.body.s2k_usg in [254, 255]: k = string2key(keypkt.body.s2k, alg, passphrase) else: k = md5.new(passphrase).digest() # extra work required since MPIs integers are encrypted w/out # their lengths # create MPIs w/ encrypted integer octets secRSA_d, idx = MPI.strcalc_mpi(keypkt.body._enc_d, 0) secRSA_p, idx = MPI.strcalc_mpi(keypkt.body._enc_d, idx) secRSA_q, idx = MPI.strcalc_mpi(keypkt.body._enc_d, idx) secRSA_u, idx = MPI.strcalc_mpi(keypkt.body._enc_d, idx) # decrypt integer octets RSA_d_int_d = decrypt_symmetric(alg, k, secRSA_d._int_d, keypkt.body.iv) RSA_p_int_d = decrypt_symmetric(alg, k, secRSA_d._int_d, keypkt.body.iv) RSA_q_int_d = decrypt_symmetric(alg, k, secRSA_d._int_d, keypkt.body.iv) RSA_u_int_d = decrypt_symmetric(alg, k, secRSA_d._int_d, keypkt.body.iv) # translate integer values RSA_d_value = STN.str2int(RSA_d_int_d) RSA_p_value = STN.str2int(RSA_p_int_d) RSA_q_value = STN.str2int(RSA_q_int_d) RSA_u_value = STN.str2int(RSA_u_int_d) key_tuple = (RSA_d_value, RSA_p_value, RSA_q_value, RSA_u_value) sec_d = ''.join([secRSA_d._d[:2], RSA_d_int_d, secRSA_p._d[:2], RSA_p_int_d, secRSA_q._d[:2], RSA_q_int_d, secRSA_q._d[:2], RSA_q_int_d]) else: raise NotImplementedError("Unsupported v3 decryption key algorithm->(%s)." % keypkt.body.alg) elif 4 == keypkt.body.version: alg = keypkt.body.alg_sym k = string2key(keypkt.body.s2k, alg, passphrase) sec_d = decrypt_symmetric(alg, k, keypkt.body._enc_d, keypkt.body.iv) if keypkt.body.alg in [ASYM_RSA_E, ASYM_RSA_EOS, ASYM_RSA_S]: RSA_d, idx = MPI.strcalc_mpi(sec_d, 0) RSA_p, idx = MPI.strcalc_mpi(sec_d[idx:], idx) RSA_q, idx = MPI.strcalc_mpi(sec_d[idx:], idx) RSA_u, idx = MPI.strcalc_mpi(sec_d[idx:], idx) key_tuple = (RSA_d.value, RSA_p.value, RSA_q.value, RSA_u.value) elif keypkt.body.alg in [ASYM_ELGAMAL_E, ASYM_ELGAMAL_EOS]: ELGAMAL_x, idx = MPI.strcalc_mpi(sec_d, 0) key_tuple = ELGAMAL_x.value, # coerce tuple elif keypkt.body.alg in [ASYM_DSA]: DSA_x, idx = MPI.strcalc_mpi(sec_d, 0) key_tuple = DSA_x.value, # coerce tuple else: raise NotImplementedError("Unsupported public key algorithm->(%s)." % keypkt.body.alg) else: raise NotImplementedError, "Unsupported key version->(%s)." % keypkt.body.version # check integrity if 254 == keypkt.body.s2k_usg: if sec_d[idx:] != sha.new(sec_d[:idx]).digest(): raise PGPCryptoError("Integrity hash check failed.") elif 255 == keypkt.body.s2k_usg: if keypkt.body.chksum != STN.checksum(sec_d): raise PGPCryptoError("Integrity checksum failed.") return key_tuple
def decrypt(encpkt, passphrase='', sespkt=None, keypkt=None): """Decrypt messages in symmetrically encrypted packets (types 9 & 18). :Parameters: - `encpkt`: packet containing encrypted data (symmetrically encrypted or integrity protected packet, types 9 & 18) - `passphrase`: string decryption passphrase (see below) - `sespkt`: optional session key packet - `keypkt`: optional public key packet :Returns: string cleartext :Exceptions: - `PGPError`: implementation error - `PGPDecryptionFailure`: decryption failed - `PGPSessionDecryptionFailure`: session decryption failed This is the all-in-one handler for "normal" decryption - that is, decrypting symmetrically encrypted (type 9) and symmetrically encrypted integrity protected (type 18) data. By consolidating everything to one function it will be easier (hopefully) to manage secure data handling in the future. Because this function focuses on decrypting information in packet types 9 and 18, decrypted data is by definition (or "will be", due to the mechanics of this function) the data used to build an OpenPGP message (not the message instance). It is up to the API layer to automate things like "if compressed, decompress" or "if signed, verify." """ result = key = algorithm = None # key & algo set to force integrity failure if sespkt: ses = sespkt.body if PKT_PUBKEYSESKEY == sespkt.tag.type: if ses.keyid == keypkt.body.id: try: seckeys = decrypt_secret_key(keypkt, passphrase) except PGPError: # catch MPI value error due to .. raise PGPCryptoError("Public key encrypted session key checksum failed.") if keypkt.body.alg in [ASYM_RSA_E, ASYM_RSA_EOS]: cipher_tuple = (ses.RSA_me_modn.value,) key_tuple = (keypkt.body.RSA_n.value, seckeys[0]) elif keypkt.body.alg in [ASYM_ELGAMAL_E, ASYM_ELGAMAL_EOS]: cipher_tuple = (ses.ELGAMAL_gk_modp.value, ses.ELGAMAL_myk_modp.value) key_tuple = (keypkt.body.ELGAMAL_p.value, seckeys[0]) else: raise NotImplementedError("Unsupported public encryption algorithm->(%s)." % keypkt.body.alg) else: # shouldn't happen, programmer error raise PGPCryptoError("The public encryption key did not match the session key target.") # should be ready to decrypt session key with key tuple padded_key = decrypt_public(ses.alg_pubkey, key_tuple, cipher_tuple) if '\x02' == padded_key[0]: # handle EME-PKCS1-v1_5 encoding idx = padded_key.find('\x00') # 0x00 used as padding separator if -1 != idx and 8 <= idx: message = padded_key[idx+1:] algorithm = STN.str2int(message[0]) # required for both.. chksum = STN.str2int(message[-2:]) key = message[1:len(message)-2] # ..symencdata and symencintdata if chksum != STN.checksum(key): raise PGPCryptoError("Public Key encrypted session key checksum failed.") else: raise PGPCryptoError("Misplaced \\x00 in session key padding, located at index->(%s)." % idx) else: raise PGPCryptoError("Session key didn't start with \\x02, received->()." % hex(ord(padded_key[0]))) elif PKT_SYMKEYSESKEY == sespkt.tag.type: # using symmetric key session key algorithm = ses.alg key = string2key(ses.s2k, algorithm, passphrase) if ses.has_key: iv = STN.prepad(_import_cipher(algorithm).block_size) padded_key = decrypt_symmetric(algorithm, key, ciphertext, iv) algorithm = padded_key[0] key = padded_key[1:] else: raise NotImplementedError("Unrecognized session key type-(%s)." % sespkt.tag.type) # 'algorithm' & 'key' should be set, it's time to decrypt the message if PKT_SYMENCINTDATA == encpkt.tag.type: bs = _import_cipher(algorithm).block_size iv = STN.prepad(bs) cleartext = decrypt_symmetric(algorithm, key, encpkt.body.data, iv) prefix = cleartext[:bs+2] clearmsg_d = cleartext[bs+2:-22] mdc_d = cleartext[-22:] mdc = mdc_d[-20:] if mdc != sha.new(''.join([prefix, clearmsg_d, '\xd3\x14'])).digest(): raise PGPCryptoError("Integrity hash check failed.") elif PKT_SYMENCDATA == encpkt.tag.type: if None == key == algorithm: # non-integrity allows default key & alg key = md5.new(passphrase).digest algorithm = SYM_IDEA clearmsg_d = decrypt_symmetric_resync(algorithm, key, encpkt.body.data) return clearmsg_d
def fill(self, d): self._d = d version_d = d[0] self.version, idx = STN.strcalc(STN.str2int, d[0], 0) if self.version in [2, 3]: hash_len, idx = STN.strcalc(STN.str2int, d[idx:idx + 1], idx) self.type, idx = STN.strcalc(STN.str2int, d[idx:idx + 1], idx) self.created, idx = STN.strcalc(STN.str2int, d[idx:idx + 4], idx) self.hashed_data = d[2:idx] self.keyid, idx = STN.strcalc(STN.str2hex, d[idx:idx + 8], idx) self.alg_pubkey, idx = STN.strcalc(STN.str2int, d[idx:idx + 1], idx) self.alg_hash, idx = STN.strcalc(STN.str2int, d[idx:idx + 1], idx) self.hashed_subpkts = [] # dummy settings to make searches easier self.unhashed_subpkts = [] # elif 4 == self.version: import struct _type_d, idx = STN.strcalc(None, d[idx:idx + 1], idx) self.type = STN.str2int(_type_d) self.alg_pubkey, idx = STN.strcalc(STN.str2int, d[idx:idx + 1], idx) self.alg_hash, idx = STN.strcalc(STN.str2int, d[idx:idx + 1], idx) # hashed subpackets subpkts_len, idx = STN.strcalc(STN.str2int, d[idx:idx + 2], idx) self.hashed_subpkts = self.__resolve_subpkts(d[idx:idx + subpkts_len]) # hashed data & trailer - should '>i' ever return more than 4 chars? hashed_data = d[0:idx + subpkts_len] bigend = struct.pack('>i', len(hashed_data))[-4:] self.hashed_data = ''.join( [hashed_data, version_d, '\xff', bigend]) idx = idx + subpkts_len # unhashed subpackets subpkts_len, idx = STN.strcalc(STN.str2int, d[idx:idx + 2], idx) self.unhashed_subpkts = self.__resolve_subpkts(d[idx:idx + subpkts_len]) idx = idx + subpkts_len # attribute convenience self.keyid = self.__set_subpkt_attr(SIGSUB_SIGNERID) or '' self.created = self.__set_subpkt_attr(SIGSUB_CREATED) or 0 else: raise PGPValueError( "Unsupported signature version. Received->(%s)" % str(self.version)) self.hash_frag, idx = STN.strcalc(None, d[idx:idx + 2], idx) if self.alg_pubkey in [ASYM_RSA_S, ASYM_RSA_EOS]: self.RSA, idx = MPI.strcalc_mpi(d[idx:], idx) elif ASYM_DSA == self.alg_pubkey: self.DSA_r, idx = MPI.strcalc_mpi(d[idx:], idx) self.DSA_s, idx = MPI.strcalc_mpi(d[idx:], idx) elif self.alg_pubkey in [ASYM_ELGAMAL_EOS]: self.ELGAMAL_a, idx = MPI.strcalc_mpi(d[idx:], idx) self.ELGAMAL_b, idx = MPI.strcalc_mpi(d[idx:], idx) else: raise PGPValueError("Unsupported public-key algorithm (%d)." % self.alg_pubkey)
def testC4Inversion(self): """strnum: number to string inversion (int2quadoct/str2int())""" for o in self.good_nums: self.assertEqual(o[0], str2int(int2quadoct(o[0])))
def testC0TranslationS2N(self): """strnum: str2int output""" for v in self.good_strings: self.assertEqual(v[1], str2int(v[0]))
def test01_int2str_str2int(self): "strnum: string/integer inversion (int2str/str2int)" body = self.key.body for i in [body.DSA_p.value, body.DSA_q.value, body.DSA_g.value, body.DSA_y.value]: self.assertEqual(i, str2int(int2str(i)))
def fill(self, d): ord_d = ord(d[0]) if ord_d < 192: slice = d[0] size = ord_d elif 192 <= ord_d < 255: slice = d[:2] #size = size + STN.doubleoct2int(slice) size = STN.doubleoct2int(slice) elif 255 == ord_d: slice = d[:5] #size = size + STN.pentoct2int(slice) size = STN.pentoct2int(slice) len_slice = len(slice) self._d = d[:len_slice+size] type_d = d[len_slice:len_slice+1] self.type = 127 & ord(type_d) self.critical = 128 & ord(type_d) value_d = d[len_slice+1:len_slice+size] if SIGSUB_SIGNERID == self.type: self.value = STN.str2hex(value_d[:8]) elif self.type in [SIGSUB_CREATED, SIGSUB_EXPIRES, SIGSUB_KEYEXPIRES]: self.value = STN.str2int(value_d[:4]) self.value = STN.str2int(value_d) elif self.type in [SIGSUB_EXPORTABLE, SIGSUB_REVOCABLE, SIGSUB_PRIMARYUID]: self.value = STN.str2int(value_d[:1]) if self.value not in [0, 1]: raise SignatureSubpacketValueError, "Subpacket (# %s) value must be 0 or 1." % (str(subtype)) elif SIGSUB_TRUST == self.type: # level, amount self.value = (STN.str2int(value_d[0]), STN.str2int(value_d[1])) elif self.type in [SIGSUB_SYMCODE, SIGSUB_HASHCODE, SIGSUB_COMPCODE, SIGSUB_KEYSERVPREFS, SIGSUB_KEYFLAGS, SIGSUB_FEATURES]: self.value = [ord(x) for x in value_d] elif SIGSUB_REVOKER == self.type: cls = STN.str2int(value_d[0]) alg = STN.str2int(value_d[1]) fprint = STN.str2hex(value_d[2:22]) self.value = (cls, alg, fprint) elif SIGSUB_NOTE == self.type: flags = [STN.str2int(x) for x in value_d[:4]] # first four flag octs name_len = STN.str2int(value_d[4:6]) val_len = STN.str2int(value_d[6:8]) nam = value_d[8:8+name_len] val = value_d[8+name_len:8+name_len+val_len] self.value = (flags, nam, val) elif self.type in [SIGSUB_KEYSERV, SIGSUB_POLICYURL, SIGSUB_SIGNERUID, SIGSUB_REGEX]: self.value = value_d elif SIGSUB_REVOCREASON == self.type: # code, reason self.value = (STN.str2int(value_d[0]), value_d[1:]) elif SIGSUB_SIGTARGET == self.type: raise NotImplementedError, "SIGTARGET not supported" else: # the subpacket has an unknown type, so just pack the data in self.value = value_d