def testD03RSA(self): """crypto.cipher: decrypt_symmetric() v3 RSA secret key (RSA_d,p,q,u)""" rsasec_armored = read_test_file([ 'pgpfiles', 'interop', 'pgp6.5.3', 'RSA1', 'key.pgp6.5.3.RSA1.sec.asc' ]) rsanopass_armored = read_test_file([ 'pgpfiles', 'interop', 'pgp6.5.3', 'RSA1', 'key.pgp6.5.3.RSA1.sec.nopass.asc' ]) rsasec_d, rsanopass_d = list_armored( rsasec_armored)[0].data, list_armored(rsanopass_armored)[0].data pkts, nopasspkts = list_pkts(rsasec_d), list_pkts(rsanopass_d) secretkey_pkt, nopasskey_pkt = pkts[0], nopasspkts[0] secretkey, nopasskey = secretkey_pkt.body, nopasskey_pkt.body passphrase = 'test' # for the future.. if secretkey.s2k_usg in [254, 255]: # we have an s2k key = string2key(secretkey.s2k, secretkey.alg_sym, passphrase) else: import md5 key = md5.new(passphrase).digest() # Just comparing bytes, not integer values. The funky notation # 'enc_RSA_d_d', 'enc_RSA_p_d' means "the encrypted *integer* # data from the RSA d and p # MPIs, respectively. # 'len_RSA_d_d' means "the octet length of the integer portion # of the RSA d MPI." idx = 0 # RSA_d len_RSA_d_d = mpilen2int(secretkey._enc_d[idx:idx + 2]) idx = idx + 2 enc_RSA_d_d = secretkey._enc_d[idx:idx + len_RSA_d_d] idx = idx + len_RSA_d_d iv = secretkey.iv # iv provided RSA_d_d = decrypt_symmetric(secretkey.alg_sym, key, enc_RSA_d_d, iv) self.assertEqual(RSA_d_d, nopasskey.RSA_d._int_d) # RSA_p len_RSA_p_d = mpilen2int(secretkey._enc_d[idx:idx + 2]) idx = idx + 2 enc_RSA_p_d = secretkey._enc_d[idx:idx + len_RSA_p_d] idx = idx + len_RSA_p_d iv = enc_RSA_d_d[-8:] # last 8 octets from "pre-sync" instream RSA_p_d = decrypt_symmetric(secretkey.alg_sym, key, enc_RSA_p_d, iv) self.assertEqual(RSA_p_d, nopasskey.RSA_p._int_d) # RSA_q len_RSA_q_d = mpilen2int(secretkey._enc_d[idx:idx + 2]) idx = idx + 2 enc_RSA_q_d = secretkey._enc_d[idx:idx + len_RSA_q_d] idx = idx + len_RSA_q_d iv = enc_RSA_p_d[-8:] # last 8 octets from "pre-sync" instream RSA_q_d = decrypt_symmetric(secretkey.alg_sym, key, enc_RSA_q_d, iv) self.assertEqual(RSA_q_d, nopasskey.RSA_q._int_d) # RSA_u len_RSA_u_d = mpilen2int(secretkey._enc_d[idx:idx + 2]) idx = idx + 2 enc_RSA_u_d = secretkey._enc_d[idx:idx + len_RSA_u_d] idx = idx + len_RSA_u_d iv = enc_RSA_q_d[-8:] # last 8 octets from "pre-sync" instream RSA_u_d = decrypt_symmetric(secretkey.alg_sym, key, enc_RSA_u_d, iv) self.assertEqual(RSA_u_d, nopasskey.RSA_u._int_d)
def testD03RSA(self): """crypto.cipher: decrypt_symmetric() v3 RSA secret key (RSA_d,p,q,u)""" rsasec_armored = read_test_file(['pgpfiles','interop','pgp6.5.3','RSA1','key.pgp6.5.3.RSA1.sec.asc']) rsanopass_armored = read_test_file(['pgpfiles','interop','pgp6.5.3','RSA1','key.pgp6.5.3.RSA1.sec.nopass.asc']) rsasec_d, rsanopass_d = list_armored(rsasec_armored)[0].data, list_armored(rsanopass_armored)[0].data pkts, nopasspkts = list_pkts(rsasec_d), list_pkts(rsanopass_d) secretkey_pkt, nopasskey_pkt = pkts[0], nopasspkts[0] secretkey, nopasskey = secretkey_pkt.body, nopasskey_pkt.body passphrase = 'test' # for the future.. if secretkey.s2k_usg in [254, 255]: # we have an s2k key = string2key(secretkey.s2k, secretkey.alg_sym, passphrase) else: import md5 key = md5.new(passphrase).digest() # Just comparing bytes, not integer values. The funky notation # 'enc_RSA_d_d', 'enc_RSA_p_d' means "the encrypted *integer* # data from the RSA d and p # MPIs, respectively. # 'len_RSA_d_d' means "the octet length of the integer portion # of the RSA d MPI." idx = 0 # RSA_d len_RSA_d_d = mpilen2int(secretkey._enc_d[idx:idx+2]) idx = idx + 2 enc_RSA_d_d = secretkey._enc_d[idx:idx+len_RSA_d_d] idx = idx + len_RSA_d_d iv = secretkey.iv # iv provided RSA_d_d = decrypt_symmetric(secretkey.alg_sym, key, enc_RSA_d_d, iv) self.assertEqual(RSA_d_d, nopasskey.RSA_d._int_d) # RSA_p len_RSA_p_d = mpilen2int(secretkey._enc_d[idx:idx+2]) idx = idx + 2 enc_RSA_p_d = secretkey._enc_d[idx:idx+len_RSA_p_d] idx = idx + len_RSA_p_d iv = enc_RSA_d_d[-8:] # last 8 octets from "pre-sync" instream RSA_p_d = decrypt_symmetric(secretkey.alg_sym, key, enc_RSA_p_d, iv) self.assertEqual(RSA_p_d, nopasskey.RSA_p._int_d) # RSA_q len_RSA_q_d = mpilen2int(secretkey._enc_d[idx:idx+2]) idx = idx + 2 enc_RSA_q_d = secretkey._enc_d[idx:idx+len_RSA_q_d] idx = idx + len_RSA_q_d iv = enc_RSA_p_d[-8:] # last 8 octets from "pre-sync" instream RSA_q_d = decrypt_symmetric(secretkey.alg_sym, key, enc_RSA_q_d, iv) self.assertEqual(RSA_q_d, nopasskey.RSA_q._int_d) # RSA_u len_RSA_u_d = mpilen2int(secretkey._enc_d[idx:idx+2]) idx = idx + 2 enc_RSA_u_d = secretkey._enc_d[idx:idx+len_RSA_u_d] idx = idx + len_RSA_u_d iv = enc_RSA_q_d[-8:] # last 8 octets from "pre-sync" instream RSA_u_d = decrypt_symmetric(secretkey.alg_sym, key, enc_RSA_u_d, iv) self.assertEqual(RSA_u_d, nopasskey.RSA_u._int_d)
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 testD01DSASecretKey(self): """crypto.cipher: decrypt_symmetric() v4 DSA secret key (DSA_x)""" dsasec_d = read_test_file(['pgpfiles','key','DSAELG1.sec.gpg']) dsasecnopass_d = read_test_file(['pgpfiles','key','DSAELG1.sec.nopass.gpg']) pkts, nopasspkts = list_pkts(dsasec_d), list_pkts(dsasecnopass_d) secretkey_pkt, nopasskey_pkt = pkts[0], nopasspkts[0] secretkey, nopasskey = secretkey_pkt.body, nopasskey_pkt.body passphrase = 'test' key = string2key(secretkey.s2k, secretkey.alg_sym, passphrase) result = decrypt_symmetric(secretkey.alg_sym, key, secretkey._enc_d, secretkey.iv) self.assertEqual(nopasskey.DSA_x._d, result[:22])
def testC01MDCBlowfish(self): """crypto.cipher: decrypt_symmetric() Blowfish""" # Almost the same, this time with Blowfish and no compressed packet. mdc_d = read_test_file(['pgpfiles','enc','mdc.nocompress.blo.254.196.198.clrtxt.gpg']) pkts = list_pkts(mdc_d) seskey, symint = pkts[0].body, pkts[1].body passphrase = 'test' key = string2key(seskey.s2k, seskey.alg, passphrase) result = decrypt_symmetric(seskey.alg, key, symint.data) result = result[10:] # ditching the prefix + 2 literal = list_pkts(result)[0].body self.assertEqual(self.cleartext, literal.data)
def testD02RSASecretKey(self): """crypto.cipher: decrypt_symmetric() v4 RSA secret key (RSA_d,p,q,u)""" rsasec_d = read_test_file(['pgpfiles','key','RSA1.sec.gpg']) rsasecnopass_d = read_test_file(['pgpfiles','key','RSA1.sec.nopass.gpg']) pkts, nopasspkts = list_pkts(rsasec_d), list_pkts(rsasecnopass_d) secretkey_pkt, nopasskey_pkt = pkts[0], nopasspkts[0] secretkey, nopasskey = secretkey_pkt.body, nopasskey_pkt.body passphrase = 'test' key = string2key(secretkey.s2k, secretkey.alg_sym, passphrase) result = decrypt_symmetric(secretkey.alg_sym, key, secretkey._enc_d, secretkey.iv) good_mpi_d = nopasskey.RSA_d._d + nopasskey.RSA_p._d + nopasskey.RSA_q._d + nopasskey.RSA_u._d self.assertEqual(good_mpi_d, result[:328])
def testC01MDCBlowfish(self): """crypto.cipher: decrypt_symmetric() Blowfish""" # Almost the same, this time with Blowfish and no compressed packet. mdc_d = read_test_file( ['pgpfiles', 'enc', 'mdc.nocompress.blo.254.196.198.clrtxt.gpg']) pkts = list_pkts(mdc_d) seskey, symint = pkts[0].body, pkts[1].body passphrase = 'test' key = string2key(seskey.s2k, seskey.alg, passphrase) result = decrypt_symmetric(seskey.alg, key, symint.data) result = result[10:] # ditching the prefix + 2 literal = list_pkts(result)[0].body self.assertEqual(self.cleartext, literal.data)
def testD01DSASecretKey(self): """crypto.cipher: decrypt_symmetric() v4 DSA secret key (DSA_x)""" dsasec_d = read_test_file(['pgpfiles', 'key', 'DSAELG1.sec.gpg']) dsasecnopass_d = read_test_file( ['pgpfiles', 'key', 'DSAELG1.sec.nopass.gpg']) pkts, nopasspkts = list_pkts(dsasec_d), list_pkts(dsasecnopass_d) secretkey_pkt, nopasskey_pkt = pkts[0], nopasspkts[0] secretkey, nopasskey = secretkey_pkt.body, nopasskey_pkt.body passphrase = 'test' key = string2key(secretkey.s2k, secretkey.alg_sym, passphrase) result = decrypt_symmetric(secretkey.alg_sym, key, secretkey._enc_d, secretkey.iv) self.assertEqual(nopasskey.DSA_x._d, result[:22])
def testD02RSASecretKey(self): """crypto.cipher: decrypt_symmetric() v4 RSA secret key (RSA_d,p,q,u)""" rsasec_d = read_test_file(['pgpfiles', 'key', 'RSA1.sec.gpg']) rsasecnopass_d = read_test_file( ['pgpfiles', 'key', 'RSA1.sec.nopass.gpg']) pkts, nopasspkts = list_pkts(rsasec_d), list_pkts(rsasecnopass_d) secretkey_pkt, nopasskey_pkt = pkts[0], nopasspkts[0] secretkey, nopasskey = secretkey_pkt.body, nopasskey_pkt.body passphrase = 'test' key = string2key(secretkey.s2k, secretkey.alg_sym, passphrase) result = decrypt_symmetric(secretkey.alg_sym, key, secretkey._enc_d, secretkey.iv) good_mpi_d = nopasskey.RSA_d._d + nopasskey.RSA_p._d + nopasskey.RSA_q._d + nopasskey.RSA_u._d self.assertEqual(good_mpi_d, result[:328])
def testC02IntegrityProtectedCAST(self): """crypto.cipher: decrypt_symmetric() CAST5""" # Same as test above, just wrapped integrity protected packet. mdc_d = read_test_file(['pgpfiles','enc','mdc.14.212.136.clrtxt.gpg']) pkts = list_pkts(mdc_d) seskey, symint = pkts[0].body, pkts[1].body passphrase = 'test' key = string2key(seskey.s2k, seskey.alg, passphrase) result = decrypt_symmetric(seskey.alg, key, symint.data) result = result[10:] # ditching the prefix + 2 compressed = list_pkts(result)[0].body comp_d = compressed.data literal = list_pkts(comp_d)[0].body self.assertEqual(self.cleartext, literal.data)
def testC02IntegrityProtectedCAST(self): """crypto.cipher: decrypt_symmetric() CAST5""" # Same as test above, just wrapped integrity protected packet. mdc_d = read_test_file( ['pgpfiles', 'enc', 'mdc.14.212.136.clrtxt.gpg']) pkts = list_pkts(mdc_d) seskey, symint = pkts[0].body, pkts[1].body passphrase = 'test' key = string2key(seskey.s2k, seskey.alg, passphrase) result = decrypt_symmetric(seskey.alg, key, symint.data) result = result[10:] # ditching the prefix + 2 compressed = list_pkts(result)[0].body comp_d = compressed.data literal = list_pkts(comp_d)[0].body self.assertEqual(self.cleartext, literal.data)
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)