Ejemplo n.º 1
0
    def _get_keydata(self, data):
        results = []
        try:
            if "-----BEGIN" in data:
                ak = pgpdump.AsciiData(data)
            else:
                ak = pgpdump.BinaryData(data)
        except TypeError:
            return []

        now = time.time()
        for m in ak.packets():
            if isinstance(m, pgpdump.packet.PublicKeyPacket):
                results.append({
                    "fingerprint":
                    m.fingerprint,
                    "created":
                    m.datetime,
                    "validity":
                    ('e' if (0 < (int(m.expiration_time or 0)) < now) else ''),
                    "keytype_name": (m.pub_algorithm or '').split()[0],
                    "keysize":
                    str(int(1.024 * round(len('%x' % m.modulus) / 0.256))),
                    "uids": [],
                })
            if isinstance(m, pgpdump.packet.UserIDPacket):
                results[-1]["uids"].append({
                    "name": m.user_name,
                    "email": m.user_email
                })

        return results
Ejemplo n.º 2
0
def read_gpg_key(data,base64decode=True):
	if base64decode==True:
		binary = base64.b64decode(data)
	else:
		binary = data	
	info = pgpdump.BinaryData(binary)
	info_key = {}
	info_key_id = {}
	info_keys_tmp = []
	info_keys_out = []

	packets = list(info.packets())
	for packet in packets:
		#print(packet)
		if isinstance(packet, PublicSubkeyPacket) or isinstance(packet, PublicKeyPacket):
			info_key['key_id'] = packet.key_id
			info_key['raw_pub_algorithm'] = packet.raw_pub_algorithm
			info_key['modulus_bitlen'] = packet.modulus_bitlen
			info_key['exponent'] = packet.exponent
			info_key['modulus'] = packet.modulus
			info_keys_tmp.append(info_key) 
		elif isinstance(packet, UserIDPacket):
			info_key_id['user_name'] = packet.user_name
			info_key_id['user_email'] = packet.user_email
	for info_key in info_keys_tmp:
		info_key['user_name'] =  info_key_id['user_name']
		info_key['user_email'] = info_key_id['user_email']
		info_keys_out.append(info_key)
	return info_keys_out
Ejemplo n.º 3
0
    def _get_keydata(self, data):
        results = {}
        try:
            if "-----BEGIN" in data:
                ak = pgpdump.AsciiData(data)
            else:
                ak = pgpdump.BinaryData(data)
        except TypeError:
            return []

        curfp = None
        for m in ak.packets():
            if isinstance(m, pgpdump.packet.PublicKeyPacket):
                curfp = m.fingerprint
                results[curfp] = {
                    "fingerprint": m.fingerprint,
                    "expires": m.expiration_time,
                    "created": m.datetime,
                    "uids": [],
                }
            if isinstance(m, pgpdump.packet.UserIDPacket):
                results[curfp]["uids"].append({"name": m.user_name, 
                    "email": m.user_email})

        return results
Ejemplo n.º 4
0
 def render(self, value, request):
     if not value:
         return super(PGPKeyField, self).render(_('No public key.\nPaste your ASCII-armored pubkey here.'), request)
     data = pgpdump.BinaryData(value)
     packets = list(data.packets())
     if packets:
         value = 'Imported Key:\n0x'+(packets[0].key_id.decode('utf-8'))
     else:
         value = ''
     return super(PGPKeyField, self).render(value, request)
Ejemplo n.º 5
0
    def parse(settingsdir=None):
        if settingsdir == None:
            settingsdir = GnuPGProperties.path

        secring_file = os.path.join(settingsdir, GnuPGProperties.secring)
        if not os.path.exists(secring_file):
            return dict()
        rawdata = GnuPGProperties.load_data(secring_file)
        try:
            data = pgpdump.BinaryData(rawdata)
        except pgpdump.utils.PgpdumpException, e:
            print("gnupg: %s" % (e))
            return dict()
Ejemplo n.º 6
0
def get_modulus_from_gpg(cert):
    import pgpdump, types
    try:
        data = pgpdump.BinaryData(cert)
    except pgpdump.utils.PgpdumpException:
        data = pgpdump.AsciiData(cert)

    public_gpg_keys = [
        packet for packet in data.packets()
        if type(packet) == pgpdump.packet.PublicKeyPacket
    ]
    if len(public_gpg_keys) != 1:
        raise (Exception(
            "Found {} gpg public keys, require exactly 1, aborting.".format(
                len(public_gpg_keys))))

    return public_gpg_keys[0].modulus
Ejemplo n.º 7
0
def change_passphrase(keydata,
                      old_pass,
                      new_pass='',
                      fast=False,
                      decoding_charset='utf-8'):
    """
    Accepts a PGP key (armored or binary) and attempt to change the
    passphrase of any secret keys within.

    If new_pass is false (blank or None), the output will be an
    unprotected key. If fast is True, the new passphrase is assumed to
    already have high entropy and we use a minimal number of iterations
    when deriving the actual encryption key.

    Returns the new key in binary form, raises an exception on error.
    """
    keydata = bytes(keydata)
    if b'-----BEGIN PGP' in keydata:
        packet_iter = pgpdump.AsciiData(keydata).packets()
    else:
        packet_iter = pgpdump.BinaryData(keydata).packets()

    try:
        # Ensure correct encoding on Python 2
        if not isinstance(old_pass, unicode):
            old_pass = old_pass.decode('utf-8')
        if not isinstance(new_pass, unicode):
            new_pass = new_pass.decode('utf-8')
    except NameError:
        pass

    output = []
    for packet in packet_iter:
        if packet.raw in (5, 7):
            packet = _unlock_secret_key(packet, old_pass, decoding_charset)
            if new_pass:
                packet = _lock_secret_key(packet, new_pass, fast)
        if packet is not None:
            output.append(packet)

    newkey = b''
    for p in output:
        newkey += _pgp_header(p.raw, len(p.data)) + p.data

    return newkey
Ejemplo n.º 8
0
def _get_keydata(data):
    results = []
    try:
        if "-----BEGIN" in data:
            ak = pgpdump.AsciiData(data)
        else:
            ak = pgpdump.BinaryData(data)
        packets = list(ak.packets())
    except (TypeError, IndexError, PgpdumpException):
        return []

    now = time.time()
    for m in packets:
        try:
            if isinstance(m, pgpdump.packet.PublicKeyPacket):
                size = str(
                    int(1.024 * round(len('%x' % (m.modulus or 0)) / 0.256)))
                validity = ('e' if
                            (0 < (int(m.expiration_time or 0)) < now) else '')
                results.append({
                    "fingerprint":
                    m.fingerprint,
                    "created":
                    _get_creation_time(m),
                    "validity":
                    validity,
                    "keytype_name": (m.pub_algorithm or '').split()[0],
                    "keysize":
                    size,
                    "uids": [],
                })
            if isinstance(m, pgpdump.packet.UserIDPacket) and results:
                # FIXME: This used to happen with results=[], does that imply
                #        UIDs sometimes come before the PublicKeyPacket?
                results[-1]["uids"].append({
                    "name": m.user_name,
                    "email": m.user_email
                })
        except (TypeError, AttributeError, KeyError, IndexError, NameError):
            import traceback
            traceback.print_exc()

    # This will only return keys that have UIDs
    return [k for k in results if k['uids']]
Ejemplo n.º 9
0
    def _get_keydata(self, data):
        results = []
        try:
            if "-----BEGIN" in data:
                ak = pgpdump.AsciiData(data)
            else:
                ak = pgpdump.BinaryData(data)
        except TypeError:
            return []

        now = time.time()
        for m in ak.packets():
            try:
                if isinstance(m, pgpdump.packet.PublicKeyPacket):
                    # FIXME m.datetime throws nasty error fails hard
                    # Issue 1115
                    size = str(
                        int(1.024 * round(len('%x' % m.modulus) / 0.256)))
                    validity = ('e' if
                                (0 <
                                 (int(m.expiration_time or 0)) < now) else '')
                    results.append({
                        "fingerprint":
                        m.fingerprint,
                        "created":
                        "1970-01-01 00:00:00",
                        "validity":
                        validity,
                        "keytype_name": (m.pub_algorithm or '').split()[0],
                        "keysize":
                        size,
                        "uids": [],
                    })
                if isinstance(m, pgpdump.packet.UserIDPacket):
                    results[-1]["uids"].append({
                        "name": m.user_name,
                        "email": m.user_email
                    })
            except (AttributeError, KeyError, IndexError, NameError):
                import traceback
                traceback.print_exc()

        return results
Ejemplo n.º 10
0
def minimal_key(keydata, user_id=None, subkey_id=None, binary_out=False):
    """
    Accepts a PGP key (armored or binary) and returns a minimal PGP key
    containing exactly five packets (base64 or binary) defining a
    primary key, a single user id with one self-signature, and a 
    single encryption subkey with one self-signature. Such a five packet
    key MUST be used in Autocrypt headers (Level 1 Spec section 2.1.1). 
    The unrevoked user id with newest unexpired self-signature and the
    unrevoked encryption-capable subkey with newest unexpired
    self-signature are selected from the input key.
    If user_id is provided, a user id containing that string will be 
    selected if there is one, otherwise any user id will be accepted.
    If subkey_id is specified, only a subkey with that id will be selected.
    
    Along with the new key, the selected user id and subkey id are returned.
    Returns None if there is a failure.
    
    """
    def _get_int4(data, offset):
        '''Pull four bytes from data at offset and return as an integer.'''
        return ((data[offset] << 24) + (data[offset + 1] << 16) +
                (data[offset + 2] << 8) + data[offset + 3])

    def _exp_time(creation_time, exp_time_subpacket_data):

        life_s = _get_int4(exp_time_subpacket_data, 0)
        if not life_s:
            return 0
        return packet.creation_time + datetime.timedelta(seconds=life_s)

    def _pgp_header(type, body_length):

        if body_length < 192:
            return bytearray([type + 0xC0, body_length])
        elif body_length < 8384:
            return bytearray([
                type + 0xC0, (body_length - 192) // 256 + 192,
                (body_length - 192) % 256
            ])
        else:
            return bytearray([
                type + 0xC0, 255, body_length // (1 << 24),
                body_length // (1 << 16) % 256, body_length // 1 << 8 % 256,
                body_length % 256
            ])

    pri_key = None
    u_id = None
    u_id_sig = None
    u_id_match = False
    s_key = None
    s_key_sig = None
    now = datetime.datetime.utcfromtimestamp(time.time())

    if '-----BEGIN PGP PUBLIC KEY BLOCK-----' in keydata:
        packet_iter = pgpdump.AsciiData(keydata).packets()
    else:
        packet_iter = pgpdump.BinaryData(keydata).packets()

    try:
        packet = next(packet_iter)
    except:
        packet = None

    while packet:

        if packet.raw == 6 and pri_key:  # Primary key must be the first
            break  # and only the first packet.
        elif packet.raw != 6 and not pri_key:
            break

        elif packet.raw == 6:  # Primary Public-Key Packet
            pri_key = packet

        elif packet.raw == 13:  # User ID Packet
            u_id_try = packet
            u_id_sig_try = None
            u_id_try_match = not user_id or user_id in u_id_try.user
            #**FIXME Autocrypt spec 5.1 requires E-mail address canonicalization

            # Accept a nonmatching u_id IFF no other u_id matches.
            if u_id_match and not u_id_try_match:
                u_id_try = None

            for packet in packet_iter:
                if packet.raw != 2:  # Signature Packet
                    break
                elif not u_id_try:
                    continue
                    # User ID certification
                elif packet.raw_sig_type in (0x10, 0x11, 0x12, 0x13, 0x1F):
                    if (packet.key_id in pri_key.fingerprint
                            and (not packet.expiration_time
                                 or packet.expiration_time > now) and
                        (not u_id_sig_try or
                         u_id_sig_try.creation_time < packet.creation_time)):
                        u_id_sig_try = packet
                        # Certification revocation
                elif packet.raw_sig_type == 0x30:
                    if packet.key_id in pri_key.fingerprint:
                        u_id_try = None
                        u_id_sig_try = None

            # Select unrevoked user id with newest unexpired self-signature
            if u_id_try and u_id_sig_try and (
                    not u_id or not u_id_sig
                    or u_id_try_match and not u_id_match
                    or u_id_sig_try.creation_time >= u_id_sig.creation_time):
                u_id = u_id_try
                u_id_sig = u_id_sig_try
                u_id_match = u_id_try_match
            continue  # Skip next(packet_iter) - for has done it.

        elif packet.raw == 14:  # Public-Subkey Packet
            s_key_try = packet
            s_key_sig_try = None

            # Honour a request for specific subkey and check for expiry.
            if (subkey_id and not subkey_id in s_key_try.fingerprint
                    or s_key_try.expiration_time
                    and s_key_try.expiration_time < now):
                s_key_try = None

            for packet in packet_iter:
                if packet.raw != 2:  # Signature Packet
                    break
                elif not s_key_try:
                    continue
                    # Subkey Binding Signature
                elif packet.raw_sig_type == 0x18:
                    packet.key_expire_time = None
                    if (packet.key_id in pri_key.fingerprint
                            and not packet.expiration_time
                            or packet.expiration_time >= now):
                        can_encrypt = True  # Assume encrypt if no flags.
                        for subpacket in packet.subpackets:
                            if subpacket.subtype == 9:  # Key expiration
                                # pgpdump should provide this!!
                                packet.key_expire_time = _exp_time(
                                    packet.creation_time, subpacket.data)
                            elif subpacket.subtype == 27:  # Key flags
                                can_encrypt |= subpacket.data[0] & 0x0C
                        if can_encrypt and (not packet.key_expire_time
                                            or packet.key_expire_time >= now):
                            s_key_sig_try = packet
                            # Subkey revocation signature
                elif packet.raw_sig_type == 0x28:
                    if packet.key_id in pri_key.fingerprint:
                        s_key_try = None
                        s_key_sig_try = None

            # Select unrevoked encryption-capable subkey with newest
            # unexpired self-signature (ignores newness of key itself).
            if s_key_try and s_key_sig_try and (
                    not s_key_sig
                    or s_key_sig_try.creation_time >= s_key_sig.creation_time):
                s_key = s_key_try
                s_key_sig = s_key_sig_try
            continue  # Skip next(packet_iter) - for has done it.

        try:
            packet = next(packet_iter)
        except:
            packet = None

    if not (pri_key and u_id and u_id_sig and s_key and s_key_sig):
        return '', None, None

    newkey = (_pgp_header(pri_key.raw, len(pri_key.data)) + pri_key.data +
              _pgp_header(u_id.raw, len(u_id.data)) + u_id.data +
              _pgp_header(u_id_sig.raw, len(u_id_sig.data)) + u_id_sig.data +
              _pgp_header(s_key.raw, len(s_key.data)) + s_key.data +
              _pgp_header(s_key_sig.raw, len(s_key_sig.data)) + s_key_sig.data)

    if not binary_out:
        newkey = base64.b64encode(newkey)

    return newkey, u_id.user, s_key.key_id
Ejemplo n.º 11
0
    def post_save(self, sender, instance, created, **kwargs):
        if created:
            data = instance.file.read()
            pgp = None
            try:
                pgp = pgpdump.AsciiData(data)
            except PgpdumpException:
                pgp = pgpdump.BinaryData(data)
            instance.file.save(instance.file.name, ContentFile(pgp.data))
            crc = crc24(pgp.data)
            crc_bin = crc.to_bytes(3, "big")
            instance.crc24 = base64.b64encode(crc_bin).decode("utf-8")
            instance.save()

            # parse packets
            index = 0
            last_pubkey = None
            last_userid = None
            for packet in pgp.packets():
                index += 1
                if (not isinstance(packet, PublicKeyPacket)
                        and not isinstance(packet, UserIDPacket)
                        and not isinstance(packet, SignaturePacket)):
                    continue
                if isinstance(packet, PublicKeyPacket):
                    is_sub = isinstance(packet, PublicSubkeyPacket)
                    creation_time = make_aware(packet.creation_time, utc)
                    expir = None
                    if packet.expiration_time is not None:
                        expir = make_aware(packet.expiration_time, utc)
                    algo = packet.raw_pub_algorithm
                    bits = 0
                    if algo in (1, 2, 3):
                        bits = len(bin(packet.modulus)[2:])
                    elif algo == 17:
                        bits = len(bin(packet.prime)[2:])
                    elif algo in (16, 20):
                        bits = len(bin(packet.prime)[2:])
                    fingerprint = packet.fingerprint.lower().decode('utf-8')
                    keyid = packet.key_id.lower().decode('utf-8')
                    last_pubkey = PGPPublicKeyModel.objects.create(
                        index=index,
                        key=instance,
                        is_sub=is_sub,
                        creation_time=creation_time,
                        expiration_time=expir,
                        algorithm=algo,
                        bits=bits,
                        fingerprint=fingerprint,
                        keyid=keyid)
                elif isinstance(packet, UserIDPacket):
                    userid = packet.data.decode("utf-8")
                    last_userid = PGPUserIDModel.objects.create(index=index,
                                                                key=instance,
                                                                userid=userid)
                elif isinstance(packet, SignaturePacket) and last_userid:
                    creation_time = make_aware(packet.creation_time, utc)
                    expir = None
                    if packet.expiration_time is not None:
                        expir = make_aware(packet.expiration_time, utc)
                    keyid = packet.key_id.lower().decode('utf-8')
                    PGPSignatureModel.objects.create(
                        index=index,
                        key=instance,
                        pkey=last_pubkey,
                        userid=last_userid,
                        type=packet.raw_sig_type,
                        pka=packet.raw_pub_algorithm,
                        hash=packet.raw_hash_algorithm,
                        creation_time=creation_time,
                        expiration_time=expir,
                        keyid=keyid)
Ejemplo n.º 12
0
def get_keyinfo(data, autocrypt_header=None,
                key_info_class=KeyInfo, key_uid_class=KeyUID,
                key_source=None):
    """
    This method will parse a stream of OpenPGP packets into a list of KeyInfo
    objects.

    Note: Signatures are not validated, this code only parses the data.
    """
    try:
        if "-----BEGIN" in data:
            ak = pgpdump.AsciiData(data)
        else:
            ak = pgpdump.BinaryData(data)
        packets = list(ak.packets())
    except (TypeError, IndexError, PgpdumpException):
        traceback.print_exc()
        return []

    def _unixtime(packet, seconds=0, days=0):
        return (packet.raw_creation_time
                + (days or 0) * 24 * 3600
                + (seconds or 0))

    results = []
    last_uid = key_uid_class()  # Dummy
    last_key = key_info_class()  # Dummy
    last_pubkeypacket = None
    main_key_id = None
    for m in packets:
        try:
            if isinstance(m, pgpdump.packet.PublicKeyPacket):
                size = str(int(1.024 *
                               round(len('%x' % (m.modulus or 0)) / 0.256)))
                last_pubkeypacket = m
                last_key = key_info_class(
                    key_source=key_source,
                    fingerprint=m.fingerprint,
                    keytype_name=m.pub_algorithm or '',
                    keytype_code=m.raw_pub_algorithm,
                    keysize=size)
                if isinstance(m, pgpdump.packet.PublicSubkeyPacket):
                    last_key.is_subkey = True
                    results[-1].subkeys.append(last_key)
                else:
                    main_key_id = m.key_id
                    results.append(last_key)

                # Older pgpdumps may fail here and cause traceback noise, but
                # the loop will limp onwards.
                last_key.created = _unixtime(m)
                if m.raw_days_valid > 0:
                    last_key.expires = _unixtime(m, days=m.raw_days_valid)
                    if last_key.expires == last_key.created:
                        last_key.expires = 0

            elif isinstance(m, pgpdump.packet.UserIDPacket) and results:
                last_uid = key_uid_class(name=m.user_name, email=m.user_email)
                last_key.uids.append(last_uid)

            elif isinstance(m, pgpdump.packet.SignaturePacket) and results:
                # Note: We don't actually check the signature; we trust
                #       GnuPG will if we decide to use this key.
                if m.key_id == main_key_id:
                    for s in m.subpackets:
                        if s.subtype == 9:
                            exp = _unixtime(last_pubkeypacket, seconds=get_int4(s.data, 0))
                            last_key.expires = max(last_key.expires, exp)
                        elif s.subtype == 27:
                            caps = set(c for c in last_key.capabilities)
                            for flag, c in ((0x01, 'c'), (0x02, 's'),
                                            (0x0C, 'e'), (0x20, 'a')):
                                if s.data[0] & flag:
                                    caps.add(c)
                            last_key.capabilities = ''.join(caps)

        except (TypeError, AttributeError, KeyError, IndexError, NameError):
            traceback.print_exc()

    autocrypt_uid = None
    if autocrypt_header:
        # The autocrypt spec tells us that the visible addr= attribute
        # overrides whatever is on the key itself, so we synthesize a
        # fake UID here so the info is correct in an Autocrypt context.
        autocrypt_uid = key_uid_class(
            email=autocrypt_header['addr'],
            comment='Autocrypt')

    now = time.time()
    for keyinfo in results:
        keyinfo.synthesize_validity(now=now)
        keyinfo.add_subkey_capabilities(now=now)
        keyinfo.recalculate_expiration(now=now)
        if autocrypt_uid is not None:
            keyinfo.ensure_autocrypt_uid(autocrypt_uid)

    return results
Ejemplo n.º 13
0
def get_keydata(data, include_subkeys=False, autocrypt_header=None):
    results = []
    try:
        if "-----BEGIN" in data:
            ak = pgpdump.AsciiData(data)
        else:
            ak = pgpdump.BinaryData(data)
        packets = list(ak.packets())
    except (TypeError, IndexError, PgpdumpException):
        return []

    if autocrypt_header:
        # The autocrypt spec tells us that the visible addr= attribute
        # overrides whatever is on the key itself, so we synthesize a
        # fake UID here so strict e-mail matches don't break Autocrypt.
        ac_uid = {'comment': 'Autocrypt', 'email': autocrypt_header['addr']}
    else:
        ac_uid = None

    now = time.time()
    for m in packets:
        try:
            if isinstance(m, pgpdump.packet.PublicKeyPacket):
                size = str(
                    int(1.024 * round(len('%x' % (m.modulus or 0)) / 0.256)))
                validity = ('e' if
                            (0 < (int(m.expiration_time or 0)) < now) else '')
                results.append({
                    "fingerprint":
                    m.fingerprint,
                    "created":
                    _get_creation_time(m),
                    "validity":
                    validity,
                    "keytype_name": (m.pub_algorithm or '').split()[0],
                    "keysize":
                    size,
                    "uids": []
                })
            if isinstance(m, pgpdump.packet.UserIDPacket) and results:
                # FIXME: This used to happen with results=[], does that imply
                #        UIDs sometimes come before the PublicKeyPacket?
                results[-1]["uids"].append({
                    "name": m.user_name,
                    "email": m.user_email
                })
        except (TypeError, AttributeError, KeyError, IndexError, NameError):
            import traceback
            traceback.print_exc()

    if not include_subkeys:
        # This will only return keys that have UIDs
        results = [k for k in results if k['uids']]

    # Ensure that all the keys we're returning have the Autocrypt UID,
    # if they have UIDs at all.
    if ac_uid is not None:
        for k in results:
            found = 0
            for u in k['uids']:
                if u['email'] == ac_uid['email']:
                    u['comment'] = u.get('comment', '') + '(Autocrypt)'
                    found += 1
            if k['uids'] and not found:
                k['uids'] += [ac_uid]

    return results