Example #1
0
    def get_fprint(self):
        """Get a key's fingerprint as an uppercase hex string.
        """
        if 3 == self.version:
            import md5

            n_bytes = mpi2str([self.mpi[0]],
                              None)[2:]  # chop off MPI length bytes
            e_bytes = mpi2str([self.mpi[1]], None)[2:]

            return md5.new(''.join([n_bytes, e_bytes])).hexdigest().upper()

        elif 4 == self.version:
            import sha
            f_data = ''.join([
                int2str(self.version),  #self._val2str('version'),
                int2str(self.created),  #self._val2str('created'),
                int2str(self.k_asym),  #self._val2str('k_asym'),
                mpi2str(self.mpi, None)
            ])  #self._val2str('mpi')])
            len_f_data = len(f_data)
            hi = chr((0xffff & len_f_data) >> 8)  # high order packet length
            lo = chr(0xff & len_f_data)  # low order packet length

            f = ['\x99', hi, lo, f_data]
            return sha.new(''.join(f)).hexdigest().upper()
def create_SymmetricKeyEncryptedSessionKeyBody(*args, **kwords):
    """Create a SymmetricKeyEncryptedSessionKeyBody instance.

    :Parameters:
        - `args`: parameter list
        - `kwords`: keyword parameter list

    Keyword options:
        - `alg`: integer symmetric key algorithm
        - `s2k`: `OpenPGP.packet.S2K` instance
        - `version`: optional integer version number (default 4)

    :Returns: `SymmetricKeyEncryptedSessionKeyBody` instance
    """
    try:
        kwords = args[0]
    except IndexError:
        pass

    if 'version' in kwords:
        if 0 < version < 128:
            version = kwords['version']
        else:
            raise PGPValueError, "Symmetric session key version %s is out of range." % version
    else:
        version = 4

    d = []
    d.append(STN.int2str(version)[0])
    d.append(STN.int2str(kwords['alg'])[0])
    d.append(kwords['s2k']._d)
    return SymmetricKeyEncryptedSessionKeyBody(''.join(d))
Example #3
0
def mpi2str(l, limit):
    """Convert a list of MPIs to a byte-string.

    :Parameters:
        - `l`: list of MPI integers
        - `limit`: dummy parameter to follow svt_*() suit

    :Returns: MPI byte-string

    :note: This should probably return some sort of an index like `str2mpi()`
        since a limit < len(l) might be useful. But it's not useful now.
    """
    d = []

    for i in l:
        i_d = int2str(i)
        i_length = len(i_d)
        bit_count = sigbits(i_d[0]) + (8 * (i_length - 1))
        i_length_str = int2str(bit_count)

        if 2 < len(i_length_str):
            raise ValueError, "MPI integer > two octs: %s octets used>" % str(
                i_length)

        elif 1 == len(i_length_str):
            i_length_str = ''.join(['\x00', i_length_str])

        d.append(''.join([i_length_str,
                          i_d]))  # since limit checks complete mpi

        if limit == len(d):
            break

    return ''.join(d)
Example #4
0
def create_MPI(i):
    """Create an MPI out of an integer.

    :Parameters:
        - `i`: integer

    :Returns: `MPI` instance
    """
    d = []
    i_d = STN.int2str(i)
    i_length = len(i_d)
    bit_count = STN.sigbits(i_d[0]) + (8 * (i_length - 1))
    i_length_str = STN.int2str(bit_count)

    if 2 < len(i_length_str):
        raise ValueError, "int is larger than two octets can specify - int occupies %s octets" % str(
            i_length)

    elif 1 == len(i_length_str):
        i_length_str = ''.join(['\x00', i_length_str])

    d.append(i_length_str)
    d.append(i_d)

    return MPI(''.join(d))
Example #5
0
def decrypt_public(algorithm, key_tuple, cipher_tuple):
    """Decrypt public key encrypted data.

    :Parameters:
        - `algorithm`: integer public key algorithm constant
        - `key_tuple`: tuple containing a public and private integers of the
          target key, RSA values (n, d) or ElGamal values (p, x)
        - `cipher_tuple`: tuple containing the integers of the encrypted data,
          coerced RSA value (c, ) and ElGamal values (a, b)

    :Returns: string cleartext

    `decrypt_public()` works with public key encrypted information (information
    encrypted to public key values and decrypted using the corresponding secret
    key values). This function works with tuples of public key values and
    tuples of values that comprise the "ciphertext."

    **Use this function to decrypt public key encrypted session key packets.**

    RSA key tuple (n, d):
        - `n`: integer RSA product of primes p & q
        - `d`: integer RSA decryption key

    RSA cipher tuple (c, ):
        - `c`: integer m**e mod n

    ElGamal key tuple (p, x):
        - `p`: integer ElGamal prime
        - `x`: integer ElGamal private key

    ElGamal cipher tuple (a, b):
        - `a`: integer ElGamal value g**k mod p
        - `b`: integer ElGamal value m * y**k mod p

    Use this for decrypting public-key encrypted session keys.
    """
    key_tuple = tuple([long(i) for i in key_tuple]) # long(): fastmath dep

    if algorithm in [ASYM_RSA_EOS, ASYM_RSA_E]:
        from Crypto.PublicKey import RSA

        key = RSA.construct((key_tuple[0], 0L, key_tuple[1])) # L for fastmath
        a = STN.int2str(cipher_tuple[0])
        return key.decrypt((a,))

    elif algorithm in [ASYM_ELGAMAL_EOS, ASYM_ELGAMAL_E]:
        from Crypto.PublicKey import ElGamal

        key = ElGamal.construct((key_tuple[0], 0, 0, key_tuple[1]))
        a = STN.int2str(cipher_tuple[0])
        b = STN.int2str(cipher_tuple[1])
        return key.decrypt((a, b))

    else:
        raise NotImplementedError, "Unsupported asymmetric algorithm:%s" % algorithm
Example #6
0
File: S2K.py Project: Zaryob/wubi
def create_S2K(*args, **kwords):
    """Create an S2K (string-to-key specifier) instance.
    
    :Parameters:
        - `args`: parameter list
        - `kwords`: keyword parameter dictionary 

    :Keywords:
        - `alg_hash`: integer hash algorithm constant (default SHA1)
        - `salt`: string 8 octet salt **Required for types 1 & 3**
        - `type`: *optional* integer S2K type (default 3)
        - `count`: *optional* integer count code (< 128) used for type 3
          only (default 99)

    :Returns: `S2K` instance

    :note: All keyword parameters can be specified in a dictionary,
        sent as a single parameter (args[0]).
    """
    try:
        kwords = args[0]
    except IndexError:
        pass

    if 'type' in kwords:
        s2ktype = kwords['type']
    else:
        s2ktype = 3
    if 'alg_hash' in kwords:
        alg_hash = kwords['alg_hash']
    else:
        alg_hash = HASH_SHA1

    d = []
    if 0 == s2ktype:
        d.append('\x00')
        d.append(STN.int2str(alg_hash)[0])
    elif 1 == s2ktype:
        d.append('\x01')
        d.append(STN.int2str(alg_hash)[0])
        d.append(kwords['salt'][:8])
    elif 3 == s2ktype:
        d.append('\x03')
        d.append(STN.int2str(alg_hash)[0])
        d.append(kwords['salt'][:8])
        if 'count' in kwords:
            if 0 < kwords['count'] < 128:
                d.append(STN.int2str(kwords['count']))
            else:
                raise PGPValueError, "S2K count value %s out of range." % kwords['count']
        else:
            d.append('\x63') # 99
    return S2K(''.join(d))
Example #7
0
def create_OnePassSignatureBody(*args, **kwords):
    """Create a OnePassSignatureBody instance.

    :Parameters:
        - `args`: ordered parameters
        - `kwords`: parameter keywords
    
    :Returns: `OnePassSignatureBody` instance

    Parameter keywords:
        `sigtype`: integer signature type constant
        `alg_hash`: integer hash algorithm constant
        `alg_pubkey`: integer public key algorithm constant
        `keyid`: string 16-character hex signing key ID
        `nest`: integer nested status
        `version`: integer one-pass version
    """
    if 0 < len(args) and isinstance(args[0], dict):
        kwords = args[0]
    sigtype = kwords.get('sigtype')
    alg_hash = kwords.get('alg_hash')
    alg_pubkey = kwords.get('alg_pubkey')
    keyid = kwords.get('keyid')
    nest = kwords.get('nest')
    version = kwords.setdefault('version', 3)

    errmsg = None
    version_d = STN.int2str(version)
    if 1 < len(version_d):
        errmsg = "One-pass version length (%s octs) exceeded 1 octet limit." % len(version_d)
    sigtype_d = STN.int2str(sigtype)
    if 1 < len(sigtype_d):
        errmsg = "One-pass sigtype length (%s octs) exceeded 1 octet limit." % len(type_d)
    alg_hash_d = STN.int2str(alg_hash)
    if 1 < len(alg_hash_d):
        errmsg = "One-pass hash algorithm length (%s octs) exceeded 1 octet limit." % len(alg_hash_d)
    alg_pubkey_d = STN.int2str(alg_pubkey)
    if 1 < len(alg_pubkey_d):
        errmsg = "One-pass public key algorithm length (%s octs) exceeded 1 octet limit." % len(alg_pubkey_d)
    keyid_d = STN.hex2str(keyid)
    if 8 != len(keyid_d):
        errmsg = "One-pass key ID should be a 16 octet (not %s octs) hex string." % len(keyid)
    nest_d = STN.int2str(nest)
    if 1 < len(nest_d):
        errmsg = "One-pass nest length (%s octs) exceeded 1 octet limit." % len(nest_d)
    if errmsg:
        raise PGPValueError(errmsg)
    d = ''.join([version_d, sigtype_d, alg_hash_d, alg_pubkey_d, keyid_d, nest_d])
    return OnePassSignatureBody(d)
Example #8
0
def sign_DSA(msg, key_tuple, k=None):
    """Create a DSA signature.

    :Parameters:
        - `msg`: string of data signature applies to 
        - `key_tuple`: tuple of DSA integers (y, g, p, q, x)
          (see `DSA tuple`_)
        - `k`: random integer 2 < k < q (automatically generated by
          default)

    :Returns: tuple (integer, integer) DSA signature values (r, s)

    .. _DSA tuple:

    DSA tuple:

        - `y`: integer DSA public key
        - `g`: integer DSA group
        - `p`: integer DSA prime
        - `q`: integer DSA order
        - `x`: integer DSA secret value
    """
    import Crypto.PublicKey.DSA as DSA
    if k is None: # generate our own k value (2 < k < q)
        import Crypto.Util.number as NUM
        import Crypto.Util.randpool as RND
        rnd = RND.RandomPool()
        q = key_tuple[3]
        while 1:
            k = NUM.getRandomNumber(8*len(STN.int2str(q)), rnd.get_bytes)
            if 2 < k < q:
                break
    dsa = DSA.construct(key_tuple) # note change in ordering
    return dsa.sign(msg, k)
Example #9
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)))
Example #10
0
def __cat_subpkt_block(subpkts):
    subpkt_d = ''.join([x._d for x in subpkts])
    subpkt_d_len = STN.int2str(len(subpkt_d))

    if 2 >= len(subpkt_d_len):
        return STN.prepad(2, subpkt_d_len) + subpkt_d
    else:
        raise PGPValueError, "Subpacket block length (%s) is unacceptable." % len(subpkt_d_len)
Example #11
0
def create_LiteralDataBody(*args, **kwords):
    """Create a LiteralDataBody instance.

    :Parameters:
        - `args`: parameter list, will accept keyword dictionary as
          args[0]
        - `kwords`: keyword parameters

    :Keywords:
        - `data`: string of literal data
        - `modified`: integer timestamp of file modification
        - `format`: character 'b' or 't' indicating binary or text
        - `filename`: optional filename associated with data

    :Returns: `LiteralDataBody` instance

    Use the filename '_CONSOLE' to signal extra-careful handling of
    output.
    """
    try:
        if isinstance(args[0], dict):
            kwords = args[0]
    except IndexError:
        pass

    data = kwords.get('data')

    if not data:
        data = ''

    modified = kwords.setdefault('modified', 0)
    format = kwords.setdefault('format', 'b')
    filename = kwords.setdefault('filename', 'outfile')

    if format not in ['b', 't']:
        raise PGPValueError, "Literal data format must be 'b' or 't'. Received->(%s)" % str(format)

    fnlen_d = STN.int2str(len(filename))

    if 1 < len(fnlen_d):
        raise PGPValueError, "Filename length (%s) exceeded 1 octet capacity." % len(fnlen_d)

    modified_d = STN.prepad(4, STN.int2str(modified))
    d = ''.join([format, fnlen_d, filename, modified_d, data])

    return LiteralDataBody(d)
Example #12
0
def encrypt_public_session(keypkt, key, symalg):
    """Create a public-key encrypted session key.

    :Parameters:
        - `keypkt`: either an `OpenPGP.packet.PublicKey.PublicKey` (or
          subclass) instance or encryption passphrase string
        - `key`: string encryptrion algorithm used for `symalg`
        - `symalg`: integer symmetric encryption algorithm constant

    :Returns: `OpenPGP.packet.PublicKeyEncryptedSessionKey.PublicKeyEncryptedSessionKey` instance
    """
    from openpgp.sap.pkt.Packet import create_Packet
    from openpgp.sap.pkt.PublicKeyEncryptedSessionKey import create_PublicKeyEncryptedSessionKeyBody

    pubalg = keypkt.body.alg
    rnd_prefix = []

    i = 0 # fixing the "intended length" business to 127
    while i <= 63 - len(key): # seems proper, but probably inefficient
        rnd_byte = gen_random(1)

        if '\x00' != rnd_byte:
            rnd_prefix.append(rnd_byte)
            i += 1

    chksum = STN.int2str(STN.checksum(key))[:2]

    if pubalg in [ASYM_RSA_EOS, ASYM_RSA_E]:
        key_tup = (keypkt.body.RSA_n.value, keypkt.body.RSA_e.value)

    elif pubalg in [ASYM_ELGAMAL_EOS, ASYM_ELGAMAL_E]:
        key_tup = (keypkt.body.ELGAMAL_p.value, keypkt.body.ELGAMAL_g.value, keypkt.body.ELGAMAL_y.value)

    else:
        raise NotImplementedError("Unsupported public key algorithm->(%s)." % pubalg)

    padded_key = ''.join(['\x02', ''.join(rnd_prefix), '\x00',
                          STN.int2str(symalg)[0], key, chksum])

    cipher_tup = encrypt_public(pubalg, padded_key, key_tup)

    sesbody = create_PublicKeyEncryptedSessionKeyBody(
        keyid=keypkt.body.id, alg=pubalg, mpis=cipher_tup)

    return create_Packet(PKT_PUBKEYSESKEY, sesbody._d)
Example #13
0
def __cat_subpkt_block(subpkts):
    subpkt_d = ''.join([x._d for x in subpkts])
    subpkt_d_len = STN.int2str(len(subpkt_d))

    if 2 >= len(subpkt_d_len):
        return STN.prepad(2, subpkt_d_len) + subpkt_d
    else:
        raise PGPValueError, "Subpacket block length (%s) is unacceptable." % len(
            subpkt_d_len)
Example #14
0
def _limit_int2str(i, limit):
    "Ensure that int2str output has enough ('limit') bytes."
    s = int2str(i)[:limit]
    len_s = len(s)

    if len_s < limit:
        s = ((limit - len_s) * '\x00') + s

    return s
Example #15
0
def create_MPI(i):
    """Create an MPI out of an integer.

    :Parameters:
        - `i`: integer

    :Returns: `MPI` instance
    """
    d = []
    i_d = STN.int2str(i)
    i_length = len(i_d)
    bit_count = STN.sigbits(i_d[0]) + (8 * (i_length - 1))
    i_length_str = STN.int2str(bit_count)

    if 2 < len(i_length_str):
        raise ValueError, "int is larger than two octets can specify - int occupies %s octets" % str(i_length)

    elif 1 == len(i_length_str):
        i_length_str = ''.join(['\x00', i_length_str])

    d.append(i_length_str)
    d.append(i_d)

    return MPI(''.join(d))
Example #16
0
def create_Tag(pkttype):
    """Create a Tag (packet tag) instance

    :Parameters:
        - `pkttype`: integer packet type constant (see
          `OpenPGP.constant.packets`)

    :Returns: `OpenPGP.packet.Tag` instance

    :note: Only "new" version tags will be created.
    """
    if 0 <= pkttype <= 63:
        tag_d = STN.int2str(192 | pkttype) # 192 forces new version
        return Tag(tag_d)
    else:
        raise PGPFormatError("Tag type must be in the range 0<=t<=63. Received->(%s)." % pkttype)
Example #17
0
def create_Tag(pkttype):
    """Create a Tag (packet tag) instance

    :Parameters:
        - `pkttype`: integer packet type constant (see
          `OpenPGP.constant.packets`)

    :Returns: `OpenPGP.packet.Tag` instance

    :note: Only "new" version tags will be created.
    """
    if 0 <= pkttype <= 63:
        tag_d = STN.int2str(192 | pkttype)  # 192 forces new version
        return Tag(tag_d)
    else:
        raise PGPFormatError(
            "Tag type must be in the range 0<=t<=63. Received->(%s)." %
            pkttype)
def create_PublicKeyEncryptedSessionKeyBody(*args, **kwords):
    """
    """
    try:
        kwords = args[0]
    except IndexError:
        pass
    version = '\x03'
    keyid = STN.hex2str(kwords['keyid'])
    algorithm = STN.int2str(kwords['alg'])[0]
    if kwords['alg'] in [ASYM_RSA_EOS, ASYM_RSA_E, ASYM_RSA_S]:
        mpi_d = MPI.create_MPI(kwords['mpis'][0])._d
    elif ASYM_ELGAMAL_E == kwords['alg']:
        a_d = MPI.create_MPI(kwords['mpis'][0])._d
        b_d = MPI.create_MPI(kwords['mpis'][1])._d
        mpi_d = ''.join([a_d, b_d])
    else:
        raise PGPValueError, "Unsupported public key algorithm. Received alg->(%s)" % alg
    _d = ''.join([version, keyid, algorithm, mpi_d])
    return PublicKeyEncryptedSessionKeyBody(_d)
def create_PublicKeyEncryptedSessionKeyBody(*args, **kwords):
    """
    """
    try:
        kwords = args[0]
    except IndexError:
        pass
    version = '\x03'
    keyid = STN.hex2str(kwords['keyid'])
    algorithm = STN.int2str(kwords['alg'])[0]
    if kwords['alg'] in [ASYM_RSA_EOS, ASYM_RSA_E, ASYM_RSA_S]:
        mpi_d = MPI.create_MPI(kwords['mpis'][0])._d
    elif ASYM_ELGAMAL_E == kwords['alg']:
        a_d = MPI.create_MPI(kwords['mpis'][0])._d
        b_d = MPI.create_MPI(kwords['mpis'][1])._d
        mpi_d = ''.join([a_d, b_d])
    else:
        raise PGPValueError, "Unsupported public key algorithm. Received alg->(%s)" % alg
    _d = ''.join([version, keyid, algorithm, mpi_d])
    return PublicKeyEncryptedSessionKeyBody(_d)
Example #20
0
def create_SignatureSubpacket(type, value):
    """Create a SignatureSubpacket instance.

    :Parameters:
        - `type`: integer signature subpacket type constant
          (see `OpenPGP.constant.signatures`)
        - `value`: variable value depending on `type` (see
          `Subpacket types and values`_)

    :Returns: `SignatureSubpacket` instance

    .. _Subpacket types and values:

    Subpacket types and values:
 
        - ``SIGSUB_SIGNERID``: hex key ID string (16 octets)
        - ``SIGSUB_CREATED``: integer timestamp of signature
          creation(must resolve to 4 or less octets, restricting
          value to less than 4294967296)
        - ``SIGSUB_EXPIRES``, ``SIGSUB_KEYEXPIRES``: integer time past
          creation of signature or key expiration (must resolve to 4
          or less octets, restricting value to less than 4294967296)
        - ``SIGSUB_EXPORTABLE``, `SIGSUB_REVOCABLE``,
          ``SIGSUB_PRIMARYUID``: integer 1 or 0 for True or False
        - ``SIGSUB_TRUST``: tuple(integer level, integer amount)
        - ``SIGSUB_SYMCODE``, ``SIGSUB_HASHALGS``, ``SIGSUB_COMPALGS``,
          ``SIGSUB_KEYSERVPREFS``, ``SIGSUB_KEYFLAGS``,
          ``SIGSUB_FEATURES``: list of integers, see rfc2440 for
          specifics
        - ``SIGSUB_REVOKER``: tuple(integer class, integer algorithm,
          string 40 octet caps hex SHA1 fingerprint hash string
        - ``SIGSUB_NOTATION``: tuple([list of 4 flags], string name,
          string value) see rfc2440 for specifics, list of flags may
          be replaced with None for basic text notation
          [0x80, 0x0, 0x0, 0x0]
        - ``SIGSUB_KEYSERV``, ``SIGSUB_POLICYURL``,
          ``SIGSUB_SIGNERUID``, ``SIGSUB_REGEX``: string see rfc2440
          for specifics
        - ``SIGSUB_REVOCREASON``: tuple (integer code, string reason)
        - ``SIGSUB_SIGTARGET``: Not Implemented
    """
    from Packet import create_NewLength

    # set value_d
    if SIGSUB_SIGNERID == type:
        value_d = STN.hex2str(value)

        if len(value_d) != 8:
            raise SignatureSubpacketValueError("Length of subpacket key id (%s) is not 8 octets." % len(value))

    elif type in [SIGSUB_CREATED, SIGSUB_EXPIRES, SIGSUB_KEYEXPIRES]:
        value_d = STN.int2str(value)

        while len(value_d) < 4:
            value_d = '\x00' + value_d

        if len(value_d) > 4:
            raise SignatureSubpacketValueError("Length of subpacket time (%s) exceeds 4 octet limit." % len(value_d))

    elif type in [SIGSUB_EXPORTABLE, SIGSUB_REVOCABLE, SIGSUB_PRIMARYUID]:

        if value not in [0, 1]:
            raise SignatureSubpacketValueError("Subpacket (# %s) value must be 0 or 1." % (str(subtype)))
        else:
            value_d = STN.int2str(value)

    elif SIGSUB_TRUST == type: # level, amount
        value_d = STN.int2str(value[0]) + STN.int2str(value[1])

    elif type in [SIGSUB_SYMCODE, SIGSUB_HASHCODE, SIGSUB_COMPCODE,
                  SIGSUB_KEYSERVPREFS, SIGSUB_KEYFLAGS, SIGSUB_FEATURES]:
        value_d = ''.join([STN.int2str(x) for x in value])

    elif SIGSUB_REVOKER == type: #
        value_d = STN.int2str(value[0]) + STN.int2str(value[1]) + STN.hex2str(value[2])

    elif SIGSUB_NOTE == type: # [f1, f2, f3, f4], name, value
        # TODO need check for oversized flags
        if value[0]: # allow for basic text notations w/ "not value[0]"
            flag_d = ''.join([STN.int2str(x) for x in value[0]]) # first four flag octs
        else:
            flag_d = '\x80\x00\x00\x00'

        nam, val = value[1], value[2]
        namlen, vallen = STN.int2str(len(nam)), STN.int2str(len(val))

        if len(namlen) == 1:
            namlen = '\x00' + namlen
        elif len(namlen) > 2:
            raise SignatureSubpacketValueError("Length (%s) of subpacket notation 'name' exceeds 2 octet limit." % len(nam))

        if len(vallen) == 1:
            vallen = '\x00' + vallen
        elif len(vallen) > 2:
            raise SignatureSubpacketValueError("Length (%s) of subpacket notation 'value' exceeds 2 octet limit." % len(val))

        value_d = flag_d + namlen + vallen + nam + val

    elif type in [SIGSUB_KEYSERV, SIGSUB_POLICYURL, SIGSUB_SIGNERUID, SIGSUB_REGEX]:
        value_d = value

    elif SIGSUB_REVOCREASON == type: # code, reason
        value_d = STN.int2str(value[0]) + value[1]

    elif SIGSUB_SIGTARGET == type:
        raise NotImplementedError, "SIGTARGET not supported"

    else: # subpacket is an unknown type, so just pack the data in
        value_d = value

    # resolve length string
    len_d = len(value_d) + 1 # + 1 octet type
    slice = create_NewLength(len_d)._d

    # set type string (character)
    type_d = STN.int2str(type)[0]
    subpkt_d = ''.join([slice, type_d, value_d])

    return SignatureSubpacket(subpkt_d)
Example #21
0
def create_SignatureSubpacket(type, value):
    """Create a SignatureSubpacket instance.

    :Parameters:
        - `type`: integer signature subpacket type constant
          (see `OpenPGP.constant.signatures`)
        - `value`: variable value depending on `type` (see
          `Subpacket types and values`_)

    :Returns: `SignatureSubpacket` instance

    .. _Subpacket types and values:

    Subpacket types and values:
 
        - ``SIGSUB_SIGNERID``: hex key ID string (16 octets)
        - ``SIGSUB_CREATED``: integer timestamp of signature
          creation(must resolve to 4 or less octets, restricting
          value to less than 4294967296)
        - ``SIGSUB_EXPIRES``, ``SIGSUB_KEYEXPIRES``: integer time past
          creation of signature or key expiration (must resolve to 4
          or less octets, restricting value to less than 4294967296)
        - ``SIGSUB_EXPORTABLE``, `SIGSUB_REVOCABLE``,
          ``SIGSUB_PRIMARYUID``: integer 1 or 0 for True or False
        - ``SIGSUB_TRUST``: tuple(integer level, integer amount)
        - ``SIGSUB_SYMCODE``, ``SIGSUB_HASHALGS``, ``SIGSUB_COMPALGS``,
          ``SIGSUB_KEYSERVPREFS``, ``SIGSUB_KEYFLAGS``,
          ``SIGSUB_FEATURES``: list of integers, see rfc2440 for
          specifics
        - ``SIGSUB_REVOKER``: tuple(integer class, integer algorithm,
          string 40 octet caps hex SHA1 fingerprint hash string
        - ``SIGSUB_NOTATION``: tuple([list of 4 flags], string name,
          string value) see rfc2440 for specifics, list of flags may
          be replaced with None for basic text notation
          [0x80, 0x0, 0x0, 0x0]
        - ``SIGSUB_KEYSERV``, ``SIGSUB_POLICYURL``,
          ``SIGSUB_SIGNERUID``, ``SIGSUB_REGEX``: string see rfc2440
          for specifics
        - ``SIGSUB_REVOCREASON``: tuple (integer code, string reason)
        - ``SIGSUB_SIGTARGET``: Not Implemented
    """
    from Packet import create_NewLength

    # set value_d
    if SIGSUB_SIGNERID == type:
        value_d = STN.hex2str(value)

        if len(value_d) != 8:
            raise SignatureSubpacketValueError(
                "Length of subpacket key id (%s) is not 8 octets." %
                len(value))

    elif type in [SIGSUB_CREATED, SIGSUB_EXPIRES, SIGSUB_KEYEXPIRES]:
        value_d = STN.int2str(value)

        while len(value_d) < 4:
            value_d = '\x00' + value_d

        if len(value_d) > 4:
            raise SignatureSubpacketValueError(
                "Length of subpacket time (%s) exceeds 4 octet limit." %
                len(value_d))

    elif type in [SIGSUB_EXPORTABLE, SIGSUB_REVOCABLE, SIGSUB_PRIMARYUID]:

        if value not in [0, 1]:
            raise SignatureSubpacketValueError(
                "Subpacket (# %s) value must be 0 or 1." % (str(subtype)))
        else:
            value_d = STN.int2str(value)

    elif SIGSUB_TRUST == type:  # level, amount
        value_d = STN.int2str(value[0]) + STN.int2str(value[1])

    elif type in [
            SIGSUB_SYMCODE, SIGSUB_HASHCODE, SIGSUB_COMPCODE,
            SIGSUB_KEYSERVPREFS, SIGSUB_KEYFLAGS, SIGSUB_FEATURES
    ]:
        value_d = ''.join([STN.int2str(x) for x in value])

    elif SIGSUB_REVOKER == type:  #
        value_d = STN.int2str(value[0]) + STN.int2str(value[1]) + STN.hex2str(
            value[2])

    elif SIGSUB_NOTE == type:  # [f1, f2, f3, f4], name, value
        # TODO need check for oversized flags
        if value[0]:  # allow for basic text notations w/ "not value[0]"
            flag_d = ''.join([STN.int2str(x)
                              for x in value[0]])  # first four flag octs
        else:
            flag_d = '\x80\x00\x00\x00'

        nam, val = value[1], value[2]
        namlen, vallen = STN.int2str(len(nam)), STN.int2str(len(val))

        if len(namlen) == 1:
            namlen = '\x00' + namlen
        elif len(namlen) > 2:
            raise SignatureSubpacketValueError(
                "Length (%s) of subpacket notation 'name' exceeds 2 octet limit."
                % len(nam))

        if len(vallen) == 1:
            vallen = '\x00' + vallen
        elif len(vallen) > 2:
            raise SignatureSubpacketValueError(
                "Length (%s) of subpacket notation 'value' exceeds 2 octet limit."
                % len(val))

        value_d = flag_d + namlen + vallen + nam + val

    elif type in [
            SIGSUB_KEYSERV, SIGSUB_POLICYURL, SIGSUB_SIGNERUID, SIGSUB_REGEX
    ]:
        value_d = value

    elif SIGSUB_REVOCREASON == type:  # code, reason
        value_d = STN.int2str(value[0]) + value[1]

    elif SIGSUB_SIGTARGET == type:
        raise NotImplementedError, "SIGTARGET not supported"

    else:  # subpacket is an unknown type, so just pack the data in
        value_d = value

    # resolve length string
    len_d = len(value_d) + 1  # + 1 octet type
    slice = create_NewLength(len_d)._d

    # set type string (character)
    type_d = STN.int2str(type)[0]
    subpkt_d = ''.join([slice, type_d, value_d])

    return SignatureSubpacket(subpkt_d)
Example #22
0
def create_SignatureBody(*args, **kwords):
    """Assemble signature information into a SignatureBody instance.

    :Parameters:
        - `args`: parameter list
        - `kwords`: keyword parameter dictionary 
    
    :Keywords:
        - `sigtype`: integer signature type constant (see
          `OpenPGP.constant.signatures`)
        - `alg_pubkey`: integer signature algorithm (see
          `OpenPGP.constant.algorithms`)
        - `alg_hash`: integer signature algorithm (see
          `OpenPGP.constant.algorithms`)
        - `signature`: algorithm-dependent signature MPIs - DSA
          MPI tuple (``DSA_r``, ``DSA_s``), single RSA MPI ``RSA``, or
          ElGamal MPI tuple (``ELGAMAL_a``, ``ELGAMAL_b``) (see
          `DSA signature tuple`_, `RSA signature value`_, and `ElGamal
          signature tuple`_)
        - `hash_frag`: 2 octet string of signed hash fragment
        - `hashed_subpkts`: list of `SignatureSubpacket` instances
          included in the hashed (protected) portion of the signature
        - `unhashed_subpkts`: list of `SignatureSubpacket` instances
          included in the unhashed (unprotected) portion of the signature
        - `created`: integer timestamp of signature creation, **v3 only**
        - `keyid`: string ID of signing key **v3 only**

    :Returns: `SignatureBody` instance

    .. _DSA signature tuple:
    
    DSA signature tuple (``DSA_r``, ``DSA_s``):

        - `DSA_r`: `OpenPGP.packet.MPI` instance
        - `DSA_s`: `OpenPGP.packet.MPI` instance

    .. _RSA signature value:

    RSA signature value ``RSA``:

        - ``RSA``: `OpenPGP.packet.MPI` instance

    .. _ElGamal signature tuple:

    ElGamal signature tuple (``ELGAMAL_a``, ``ELGAMAL_b``):

        - ``ELGAMAL_a``: `OpenPGP.packet.MPI` instance
        - ``ELGAMAL_b``: `OpenPGP.packet.MPI` instance

    :note: This function only assembles the provided information into
        a signature packet, it does not reconcile anything - namely,
        the values of the MPIs with the signed data and hash fragment.
    
    :note: All keyword parameters can be specified in a dictionary,
        sent as a single parameter (args[0]).
    """
    try:
        kwords = args[0]
    except IndexError:
        pass

    version = kwords['version']
    sigtype = kwords['sigtype']
    alg_pubkey = kwords['alg_pubkey']
    alg_hash = kwords['alg_hash']
    signature = kwords['signature']
    hash_frag = kwords['hash_frag']
    hashed_subpkts = kwords.get('hashed_subpkts')  # optional
    unhashed_subpkts = kwords.get('unhashed_subpkts')  # optional

    _d = []
    _d.append(STN.int2str(version)[0])
    ################# version
    if 3 == version:  #################       3
        _d.append('\x05')  # hash length (required)
        _d.append(STN.int2str(sigtype)[0])  # signature type
        _d.append(STN.int2str(kwords['created'])[:4])  # creation timestamp
        _d.append(STN.hex2str(kwords['keyid'])[:8])  # signing key ID
        _d.append(STN.int2str(alg_pubkey)[0])  # public key algorithm
        _d.append(STN.int2str(alg_hash)[0])  # hash algorithm

    elif 4 == version:  #################       4
        _d.append(STN.int2str(sigtype)[0])  # signature type
        _d.append(STN.int2str(alg_pubkey)[0])  # public key algorithm
        _d.append(STN.int2str(alg_hash)[0])  # hash algorithm

        if hashed_subpkts:  # hashed subpackets
            _d.append(__cat_subpkt_block(hashed_subpkts))
        else:
            _d.append('\x00\x00')

        if unhashed_subpkts:  # unhashed subpackets
            _d.append(__cat_subpkt_block(unhashed_subpkts))
        else:
            _d.append('\x00\x00')

    _d.append(hash_frag[:2])  # hash fragment

    if alg_pubkey in [ASYM_RSA_S, ASYM_RSA_EOS]:  # RSA MPI
        _d.append(''.join([x._d for x in signature]))

    elif alg_pubkey in [ASYM_DSA, ASYM_ELGAMAL_EOS]:  # DSA MPIs
        _d.append(''.join([x._d for x in signature]))

    else:
        raise PGPValueError, "Unsupported signature algorithm %s." % algorithm

    return SignatureBody(''.join(_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)))
Example #24
0
def create_SignatureBody(*args, **kwords):
    """Assemble signature information into a SignatureBody instance.

    :Parameters:
        - `args`: parameter list
        - `kwords`: keyword parameter dictionary 
    
    :Keywords:
        - `sigtype`: integer signature type constant (see
          `OpenPGP.constant.signatures`)
        - `alg_pubkey`: integer signature algorithm (see
          `OpenPGP.constant.algorithms`)
        - `alg_hash`: integer signature algorithm (see
          `OpenPGP.constant.algorithms`)
        - `signature`: algorithm-dependent signature MPIs - DSA
          MPI tuple (``DSA_r``, ``DSA_s``), single RSA MPI ``RSA``, or
          ElGamal MPI tuple (``ELGAMAL_a``, ``ELGAMAL_b``) (see
          `DSA signature tuple`_, `RSA signature value`_, and `ElGamal
          signature tuple`_)
        - `hash_frag`: 2 octet string of signed hash fragment
        - `hashed_subpkts`: list of `SignatureSubpacket` instances
          included in the hashed (protected) portion of the signature
        - `unhashed_subpkts`: list of `SignatureSubpacket` instances
          included in the unhashed (unprotected) portion of the signature
        - `created`: integer timestamp of signature creation, **v3 only**
        - `keyid`: string ID of signing key **v3 only**

    :Returns: `SignatureBody` instance

    .. _DSA signature tuple:
    
    DSA signature tuple (``DSA_r``, ``DSA_s``):

        - `DSA_r`: `OpenPGP.packet.MPI` instance
        - `DSA_s`: `OpenPGP.packet.MPI` instance

    .. _RSA signature value:

    RSA signature value ``RSA``:

        - ``RSA``: `OpenPGP.packet.MPI` instance

    .. _ElGamal signature tuple:

    ElGamal signature tuple (``ELGAMAL_a``, ``ELGAMAL_b``):

        - ``ELGAMAL_a``: `OpenPGP.packet.MPI` instance
        - ``ELGAMAL_b``: `OpenPGP.packet.MPI` instance

    :note: This function only assembles the provided information into
        a signature packet, it does not reconcile anything - namely,
        the values of the MPIs with the signed data and hash fragment.
    
    :note: All keyword parameters can be specified in a dictionary,
        sent as a single parameter (args[0]).
    """
    try:
        kwords = args[0]
    except IndexError:
        pass

    version = kwords['version']
    sigtype = kwords['sigtype']
    alg_pubkey = kwords['alg_pubkey']
    alg_hash = kwords['alg_hash']
    signature = kwords['signature']
    hash_frag = kwords['hash_frag']
    hashed_subpkts = kwords.get('hashed_subpkts') # optional
    unhashed_subpkts = kwords.get('unhashed_subpkts') # optional

    _d = []
    _d.append(STN.int2str(version)[0])
                                                      ################# version
    if 3 == version:                                  #################       3
        _d.append('\x05')                             # hash length (required)
        _d.append(STN.int2str(sigtype)[0])            # signature type
        _d.append(STN.int2str(kwords['created'])[:4]) # creation timestamp
        _d.append(STN.hex2str(kwords['keyid'])[:8])   # signing key ID
        _d.append(STN.int2str(alg_pubkey)[0])         # public key algorithm
        _d.append(STN.int2str(alg_hash)[0])           # hash algorithm

    elif 4 == version:                                #################       4
        _d.append(STN.int2str(sigtype)[0])            # signature type
        _d.append(STN.int2str(alg_pubkey)[0])         # public key algorithm
        _d.append(STN.int2str(alg_hash)[0])           # hash algorithm

        if hashed_subpkts:                            # hashed subpackets
            _d.append(__cat_subpkt_block(hashed_subpkts))
        else:
            _d.append('\x00\x00')

        if unhashed_subpkts:                          # unhashed subpackets
            _d.append(__cat_subpkt_block(unhashed_subpkts))
        else:
            _d.append('\x00\x00')

    _d.append(hash_frag[:2])                          # hash fragment

    if alg_pubkey in [ASYM_RSA_S, ASYM_RSA_EOS]:      # RSA MPI
        _d.append(''.join([x._d for x in signature]))

    elif alg_pubkey in [ASYM_DSA, ASYM_ELGAMAL_EOS]:  # DSA MPIs
        _d.append(''.join([x._d for x in signature]))

    else:
        raise PGPValueError, "Unsupported signature algorithm %s." % algorithm

    return SignatureBody(''.join(_d))
Example #25
-1
def sign_ElGamal(msg, key_tuple, k=None):
    """Create an ElGamal signature.

    :Parameters:
        - `msg`: string of data signature applies to 
        - `key_tuple`: tuple ElGamal key integers (p, g, x)
          (see `ElGamal key tuple`_)
        - `k`: integer (must be relatively prime to p-1)

    :Returns: tuple (integer, integer) ElGamal signature values (a, b)
    
    .. _ElGamal key tuple:

    ElGamal key tuple:
            
        - `p`: integer ElGamal prime
        - `g`: integer ElGamal random "g" value
        - `x`: integer ElGamal private key
    """
    import Crypto.PublicKey.ElGamal as ELG
    if k is None: # generate our own prime k value (k relatively prime to p-1)
        import Crypto.Util.number as NUM
        import Crypto.Util.randpool as RND
        rnd = RND.RandomPool()
        q = key_tuple[0] # no restrictions on bit length for k, good enough?
        k = NUM.getPrime(8*len(STN.int2str(q)), rnd.get_bytes)
    elg = ELG.construct((key_tuple[0], key_tuple[1], 0, key_tuple[2]))
    return elg.sign(msg, k)