def _convert_rsa_private_key(keypair):
    backend = Backend()

    def _trim_bn_to_int(s):
        binary = s.lstrip(b'\x00')
        bn_ptr = backend._lib.BN_bin2bn(binary, len(binary), backend._ffi.NULL)
        try:
            return backend._bn_to_int(bn_ptr)
        finally:
            backend._lib.OPENSSL_free(bn_ptr)

    (n, e, d, iqmp, p, q) = [
        _trim_bn_to_int(value)
        for value in _read_KEY_RSA(io.BytesIO(keypair.private_key))
    ]

    numbers = RSAPrivateNumbers(
        d=d,
        p=p,
        q=q,
        dmp1=rsa_crt_dmp1(d, p),
        dmq1=rsa_crt_dmq1(d, q),
        iqmp=rsa_crt_iqmp(p, q),
        public_numbers=RSAPublicNumbers(e=e, n=n),
    )

    return numbers.private_key(backend)
Exemple #2
0
    def load_private_key(self):
        obj = self._dict_data

        if 'oth' in obj:  # pragma: no cover
            # https://tools.ietf.org/html/rfc7518#section-6.3.2.7
            raise ValueError('"oth" is not supported yet')

        public_numbers = RSAPublicNumbers(base64_to_int(obj['e']),
                                          base64_to_int(obj['n']))

        if has_all_prime_factors(obj):
            numbers = RSAPrivateNumbers(d=base64_to_int(obj['d']),
                                        p=base64_to_int(obj['p']),
                                        q=base64_to_int(obj['q']),
                                        dmp1=base64_to_int(obj['dp']),
                                        dmq1=base64_to_int(obj['dq']),
                                        iqmp=base64_to_int(obj['qi']),
                                        public_numbers=public_numbers)
        else:
            d = base64_to_int(obj['d'])
            p, q = rsa_recover_prime_factors(public_numbers.n, d,
                                             public_numbers.e)
            numbers = RSAPrivateNumbers(d=d,
                                        p=p,
                                        q=q,
                                        dmp1=rsa_crt_dmp1(d, p),
                                        dmq1=rsa_crt_dmq1(d, q),
                                        iqmp=rsa_crt_iqmp(p, q),
                                        public_numbers=public_numbers)

        return numbers.private_key(default_backend())
Exemple #3
0
    def from_jwk(jwk):
        if not isinstance(jwk, JsonWebKey):
            raise TypeError('The specified jwk must be a JsonWebKey')

        if jwk.kty != 'RSA' and jwk.kty != 'RSA-HSM':
            raise ValueError(
                'The specified jwk must have a key type of "RSA" or "RSA-HSM"')

        if not jwk.n or not jwk.e:
            raise ValueError(
                'Invalid RSA jwk, both n and e must be have values')

        rsa_key = _RsaKey()
        rsa_key.kid = jwk.kid
        rsa_key.kty = jwk.kty
        rsa_key.key_ops = jwk.key_ops

        pub = RSAPublicNumbers(n=_bytes_to_int(jwk.n), e=_bytes_to_int(jwk.e))

        # if the private key values are specified construct a private key
        # only the secret primes and private exponent are needed as other fields can be calculated
        if jwk.p and jwk.q and jwk.d:
            # convert the values of p, q, and d from bytes to int
            p = _bytes_to_int(jwk.p)
            q = _bytes_to_int(jwk.q)
            d = _bytes_to_int(jwk.d)

            # convert or compute the remaining private key numbers
            dmp1 = _bytes_to_int(jwk.dp) if jwk.dp else rsa_crt_dmp1(
                private_exponent=d, p=p)
            dmq1 = _bytes_to_int(jwk.dq) if jwk.dq else rsa_crt_dmq1(
                private_exponent=d, q=q)
            iqmp = _bytes_to_int(jwk.qi) if jwk.qi else rsa_crt_iqmp(p=p, q=q)

            # create the private key from the jwk key values
            priv = RSAPrivateNumbers(p=p,
                                     q=q,
                                     d=d,
                                     dmp1=dmp1,
                                     dmq1=dmq1,
                                     iqmp=iqmp,
                                     public_numbers=pub)
            key_impl = priv.private_key(
                cryptography.hazmat.backends.default_backend())

        # if the necessary private key values are not specified create the public key
        else:
            key_impl = pub.public_key(
                cryptography.hazmat.backends.default_backend())

        rsa_key._rsa_impl = key_impl

        return rsa_key
Exemple #4
0
    def __init__(self, n, e, d, p, q):
        self.n = n
        self.e = e
        self.d = d
        self.p = p
        self.q = q

        dmp1 = rsa_crt_dmp1(d, p)
        dmq1 = rsa_crt_dmq1(d, q)
        iqmp = rsa_crt_iqmp(p, q)

        pub = RSAPublicNumbers(e, n)
        priv = RSAPrivateNumbers(p, q, d, dmp1, dmq1, iqmp, pub)
        self._key = priv.private_key(default_backend())
Exemple #5
0
    def __init__(self, n, e, d, p, q):
        self.n = n
        self.e = e
        self.d = d
        self.p = p
        self.q = q

        dmp1 = rsa_crt_dmp1(d, p)
        dmq1 = rsa_crt_dmq1(d, q)
        iqmp = rsa_crt_iqmp(p, q)

        pub = RSAPublicNumbers(e, n)
        priv = RSAPrivateNumbers(p, q, d, dmp1, dmq1, iqmp, pub)
        self._key = priv.private_key(default_backend())
Exemple #6
0
 def private_numbers(self) -> RSAPrivateNumbers:
     n = self._backend._ffi.new("BIGNUM **")
     e = self._backend._ffi.new("BIGNUM **")
     d = self._backend._ffi.new("BIGNUM **")
     p = self._backend._ffi.new("BIGNUM **")
     q = self._backend._ffi.new("BIGNUM **")
     dmp1 = self._backend._ffi.new("BIGNUM **")
     dmq1 = self._backend._ffi.new("BIGNUM **")
     iqmp = self._backend._ffi.new("BIGNUM **")
     self._backend._lib.RSA_get0_key(self._rsa_cdata, n, e, d)
     self._backend.openssl_assert(n[0] != self._backend._ffi.NULL)
     self._backend.openssl_assert(e[0] != self._backend._ffi.NULL)
     self._backend.openssl_assert(d[0] != self._backend._ffi.NULL)
     self._backend._lib.RSA_get0_factors(self._rsa_cdata, p, q)
     self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
     self._backend.openssl_assert(q[0] != self._backend._ffi.NULL)
     self._backend._lib.RSA_get0_crt_params(self._rsa_cdata, dmp1, dmq1,
                                            iqmp)
     self._backend.openssl_assert(dmp1[0] != self._backend._ffi.NULL)
     self._backend.openssl_assert(dmq1[0] != self._backend._ffi.NULL)
     self._backend.openssl_assert(iqmp[0] != self._backend._ffi.NULL)
     return RSAPrivateNumbers(
         p=self._backend._bn_to_int(p[0]),
         q=self._backend._bn_to_int(q[0]),
         d=self._backend._bn_to_int(d[0]),
         dmp1=self._backend._bn_to_int(dmp1[0]),
         dmq1=self._backend._bn_to_int(dmq1[0]),
         iqmp=self._backend._bn_to_int(iqmp[0]),
         public_numbers=RSAPublicNumbers(
             e=self._backend._bn_to_int(e[0]),
             n=self._backend._bn_to_int(n[0]),
         ),
     )
Exemple #7
0
    def from_jwk(cls, jwk):
        if jwk.kty != "RSA" and jwk.kty != "RSA-HSM":
            raise ValueError(
                'The specified jwk must have a key type of "RSA" or "RSA-HSM"')

        if not jwk.n or not jwk.e:
            raise ValueError(
                "Invalid RSA jwk, both n and e must be have values")

        rsa_key = cls(kid=jwk.kid)
        rsa_key.kty = jwk.kty
        rsa_key.key_ops = jwk.key_ops

        pub = RSAPublicNumbers(n=_bytes_to_int(jwk.n), e=_bytes_to_int(jwk.e))

        # if the private key values are specified construct a private key
        # only the secret primes and private exponent are needed as other fields can be calculated
        if jwk.p and jwk.q and jwk.d:
            # convert the values of p, q, and d from bytes to int
            p = _bytes_to_int(jwk.p)
            q = _bytes_to_int(jwk.q)
            d = _bytes_to_int(jwk.d)

            # convert or compute the remaining private key numbers
            dmp1 = _bytes_to_int(jwk.dp) if jwk.dp else rsa_crt_dmp1(
                private_exponent=d, p=p)
            dmq1 = _bytes_to_int(jwk.dq) if jwk.dq else rsa_crt_dmq1(
                private_exponent=d, q=q)
            iqmp = _bytes_to_int(jwk.qi) if jwk.qi else rsa_crt_iqmp(p=p, q=q)

            # create the private key from the jwk key values
            priv = RSAPrivateNumbers(p=p,
                                     q=q,
                                     d=d,
                                     dmp1=dmp1,
                                     dmq1=dmq1,
                                     iqmp=iqmp,
                                     public_numbers=pub)
            key_impl = priv.private_key(default_backend())

        # if the necessary private key values are not specified create the public key
        else:
            key_impl = pub.public_key(default_backend())

        rsa_key._rsa_impl = key_impl  # pylint:disable=protected-access

        return rsa_key
Exemple #8
0
    def from_dict(cls, dct):
        if 'oth' in dct:
            raise UnsupportedKeyTypeError(
                'RSA keys with multiples primes are not supported')

        try:
            e = uint_b64decode(dct['e'])
            n = uint_b64decode(dct['n'])
        except KeyError as why:
            raise MalformedJWKError('e and n are required') from why
        pub_numbers = RSAPublicNumbers(e, n)
        if 'd' not in dct:
            return cls(
                pub_numbers.public_key(backend=default_backend()), **dct)
        d = uint_b64decode(dct['d'])

        privparams = {'p', 'q', 'dp', 'dq', 'qi'}
        product = set(dct.keys()) & privparams
        if len(product) == 0:
            p, q = rsa_recover_prime_factors(n, e, d)
            priv_numbers = RSAPrivateNumbers(
                d=d,
                p=p,
                q=q,
                dmp1=rsa_crt_dmp1(d, p),
                dmq1=rsa_crt_dmq1(d, q),
                iqmp=rsa_crt_iqmp(p, q),
                public_numbers=pub_numbers)
        elif product == privparams:
            priv_numbers = RSAPrivateNumbers(
                d=d,
                p=uint_b64decode(dct['p']),
                q=uint_b64decode(dct['q']),
                dmp1=uint_b64decode(dct['dp']),
                dmq1=uint_b64decode(dct['dq']),
                iqmp=uint_b64decode(dct['qi']),
                public_numbers=pub_numbers)
        else:
            # If the producer includes any of the other private key parameters,
            # then all of the others MUST be present, with the exception of
            # "oth", which MUST only be present when more than two prime
            # factors were used.
            raise MalformedJWKError(
                'p, q, dp, dq, qi MUST be present or'
                'all of them MUST be absent')
        return cls(priv_numbers.private_key(backend=default_backend()), **dct)
Exemple #9
0
    def from_dict(cls, dct):
        if 'oth' in dct:
            raise UnsupportedKeyTypeError(
                'RSA keys with multiples primes are not supported')

        try:
            e = uint_b64decode(dct['e'])
            n = uint_b64decode(dct['n'])
        except KeyError as why:
            raise MalformedJWKError('e and n are required')
        pub_numbers = RSAPublicNumbers(e, n)
        if 'd' not in dct:
            return cls(
                pub_numbers.public_key(backend=default_backend()), **dct)
        d = uint_b64decode(dct['d'])

        privparams = {'p', 'q', 'dp', 'dq', 'qi'}
        product = set(dct.keys()) & privparams
        if len(product) == 0:
            p, q = rsa_recover_prime_factors(n, e, d)
            priv_numbers = RSAPrivateNumbers(
                d=d,
                p=p,
                q=q,
                dmp1=rsa_crt_dmp1(d, p),
                dmq1=rsa_crt_dmq1(d, q),
                iqmp=rsa_crt_iqmp(p, q),
                public_numbers=pub_numbers)
        elif product == privparams:
            priv_numbers = RSAPrivateNumbers(
                d=d,
                p=uint_b64decode(dct['p']),
                q=uint_b64decode(dct['q']),
                dmp1=uint_b64decode(dct['dp']),
                dmq1=uint_b64decode(dct['dq']),
                iqmp=uint_b64decode(dct['qi']),
                public_numbers=pub_numbers)
        else:
            # If the producer includes any of the other private key parameters,
            # then all of the others MUST be present, with the exception of
            # "oth", which MUST only be present when more than two prime
            # factors were used.
            raise MalformedJWKError(
                'p, q, dp, dq, qi MUST be present or'
                'all of them MUST be absent')
        return cls(priv_numbers.private_key(backend=default_backend()), **dct)
        def from_jwk(jwk):
            try:
                obj = json.loads(jwk)
            except ValueError:
                raise InvalidKeyError('Key is not valid JSON')

            if obj.get != 'RSA':
                raise InvalidKeyError('Not an RSA key')

            if 'd' in obj and 'e' in obj and 'n' in obj:
                # Private key
                if 'oth' in obj:
                    raise InvalidKeyError(
                        'Unsupported RSA private key: > 2 primes not supported'
                    )

                other_props = ['p', 'q', 'dp', 'dq', 'qi']
                props_found = [prop in obj for prop in other_props]
                any_props_found = any(props_found)

                if any_props_found and not all(props_found):
                    raise InvalidKeyError(
                        'RSA key must include all parameters if any are present besides d'
                    )

                public_numbers = RSAPublicNumbers(
                    from_base64url_uint(obj['e']),
                    from_base64url_uint(obj['n']))

                if any_props_found:
                    numbers = RSAPrivateNumbers(
                        d=from_base64url_uint(obj['d']),
                        p=from_base64url_uint(obj['p']),
                        q=from_base64url_uint(obj['q']),
                        dmp1=from_base64url_uint(obj['dp']),
                        dmq1=from_base64url_uint(obj['dq']),
                        iqmp=from_base64url_uint(obj['qi']),
                        public_numbers=public_numbers)
                else:
                    d = from_base64url_uint(obj['d'])
                    p, q = rsa_recover_prime_factors(public_numbers.n, d,
                                                     public_numbers.e)

                    numbers = RSAPrivateNumbers(d=d,
                                                p=p,
                                                q=q,
                                                dmp1=rsa_crt_dmp1(d, p),
                                                dmq1=rsa_crt_dmq1(d, q),
                                                iqmp=rsa_crt_iqmp(p, q),
                                                public_numbers=public_numbers)

                return numbers.private_key(default_backend())
            elif 'n' in obj and 'e' in obj:
                # Public key
                numbers = RSAPublicNumbers(from_base64url_uint(obj['e']),
                                           from_base64url_uint(obj['n']))

                return numbers.public_key(default_backend())
            else:
                raise InvalidKeyError('Not a public or private key')
Exemple #11
0
 def test_load_p12(self):
     cert = PinkSign(p12_data=base64.b64decode(TEST_CERT['pfx']),
                     prikey_password=TEST_CERT['signPw'])
     expected_public_numbers = RSAPublicNumbers(e=65537, n=TEST_CERT['n'])
     self.assertEqual(cert.pubkey.public_numbers(), expected_public_numbers)
     expected = RSAPrivateNumbers(p=TEST_CERT['p'], q=TEST_CERT['q'], d=TEST_CERT['d'], dmp1=TEST_CERT['dmp1'],
                                  dmq1=TEST_CERT['dmq1'], iqmp=TEST_CERT['iqmp'],
                                  public_numbers=expected_public_numbers)
     self.assertEqual(expected, cert.prikey.private_numbers())
def privKeyToRSA(key):
    #get available RSA components from private key
    eLength = 3
    pLength = 65
    qLength = 65
    components = [None,None,None,None,None,None,None,None]
    if (len(key) > eLength + pLength + qLength):
        abyte2 = key[0:4]
        privExponentLength = ((abyte2[0]&0xFF)<<24)|((abyte2[1]&0xFF)<<16)|((abyte2[2]&0xFF)<<8)|((abyte2[3]&0xFF)<<0)
        components[1] = key[4:4 + privExponentLength]
        components[2] = key[4 + privExponentLength:4 + privExponentLength + eLength]
        components[3] = key[4 + privExponentLength + eLength:4 + privExponentLength + eLength + pLength]
        components[4] = key[4 + privExponentLength + eLength + pLength:4 + privExponentLength + eLength + pLength + qLength]
    else:
        components[2] = key[0:eLength]
        components[3] = key[eLength:eLength + pLength]
        components[4] = key[eLength + pLength:eLength + pLength + qLength]

	#compute missing RSA components
    bigints = [None,None,None,None,None,None,None,None]
    for x,component in enumerate(components, start=0):
        if component is not None:
            bigints[x] = ((int.from_bytes(component,byteorder='big')))

    if (bigints[3]<bigints[4]):
        bigint = bigints[3]
        bigints[3] = bigints[4]
        bigints[4] = bigint
        bigint = bigints[5]
        bigints[5] = bigints[6]
        bigints[6] = bigint
        bigints[7] = None
    
    if (bigints[7] is None):
        bigints[7] = modinv(bigints[4],(bigints[3]))
    if (bigints[0] is None):
        bigints[0] = bigints[3]*bigints[4]
    if (bigints[1] is None):
        bigints[1] = modinv(bigints[2],((bigints[3]-1)*(bigints[4]-1)))
    if (bigints[5] is None):
        bigints[5] = bigints[1]%(bigints[3]-1)
    if (bigints[6] is None):
        bigints[6] = bigints[1]%(bigints[4]-1)

    #construct the RSA object
    #n:		modulus		    bigints[0]
    #d:		private exponent    bigints[1]
    #e:		public exponent	    bigints[2]	
    #p:		prime1 		    bigints[3]
    #q:		prime2		    bigints[4]
    #dmp1: 	exponent1	    bigints[5]
    #dmq1: 	exponent2	    bigints[6]
    #coeff:	coefficient	    bigints[7]
    rsa=RSAPrivateNumbers(bigints[3],bigints[4], bigints[1], bigints[5], bigints[6], bigints[7], RSAPublicNumbers(bigints[2],bigints[0])).private_key(backend = default_backend())
    return rsa
Exemple #13
0
    def loads_private_key(self, obj):
        if 'oth' in obj:
            # https://tools.ietf.org/html/rfc7518#section-6.3.2.7
            return self.loads_other_primes_info(obj)

        props = ['p', 'q', 'dp', 'dq', 'qi']
        props_found = [prop in obj for prop in props]
        any_props_found = any(props_found)

        if any_props_found and not all(props_found):
            raise ValueError('RSA key must include all parameters if any are present besides d')

        public_numbers = RSAPublicNumbers(
            base64_to_int(obj['e']), base64_to_int(obj['n'])
        )

        if any_props_found:
            numbers = RSAPrivateNumbers(
                d=base64_to_int(obj['d']),
                p=base64_to_int(obj['p']),
                q=base64_to_int(obj['q']),
                dmp1=base64_to_int(obj['dp']),
                dmq1=base64_to_int(obj['dq']),
                iqmp=base64_to_int(obj['qi']),
                public_numbers=public_numbers
            )
        else:
            d = base64_to_int(obj['d'])
            p, q = rsa_recover_prime_factors(
                public_numbers.n, d, public_numbers.e
            )
            numbers = RSAPrivateNumbers(
                d=d,
                p=p,
                q=q,
                dmp1=rsa_crt_dmp1(d, p),
                dmq1=rsa_crt_dmq1(d, q),
                iqmp=rsa_crt_iqmp(p, q),
                public_numbers=public_numbers
            )

        return numbers.private_key(default_backend())
Exemple #14
0
    def _load_prikey_with_decrypted_data(self, decrypted_prikey_data):
        der_pri = der_decoder.decode(decrypted_prikey_data)
        der_pri2 = der_decoder.decode(der_pri[0][2])

        # (n, e, d, p, q)
        (n, e, d, p, q) = (der_pri2[0][1], der_pri2[0][2], der_pri2[0][3],
                           der_pri2[0][4], der_pri2[0][5])
        (n, e, d, p, q) = (int(n), int(e), int(d), int(p), int(q))
        iqmp = rsa_crt_iqmp(p, q)
        dmp1 = rsa_crt_dmp1(e, p)
        dmq1 = rsa_crt_dmq1(e, q)
        pn = RSAPublicNumbers(n=n, e=e)

        self.prikey = RSAPrivateNumbers(
            p=p, q=q, d=d, dmp1=dmp1, dmq1=dmq1, iqmp=iqmp,
            public_numbers=pn).private_key(backend=default_backend())
        if len(der_pri[0]) > 3:
            # sometimes, r value is not exist -  (i don't know why..)
            self._rand_num = der_pri[0][3][1][0]  # so raw data, can't be eaten
        return
    def from_jwk(jwk):
        if not isinstance(jwk, JsonWebKey):
            raise TypeError('The specified jwk must be a JsonWebKey')

        if jwk.kty != 'RSA' and jwk.kty != 'RSA-HSM':
            raise ValueError('The specified jwk must have a key type of "RSA" or "RSA-HSM"')

        if not jwk.n or not jwk.e:
            raise ValueError('Invalid RSA jwk, both n and e must be have values')

        rsa_key = _RsaKey()
        rsa_key.kid = jwk.kid
        rsa_key.kty = jwk.kty
        rsa_key.key_ops = jwk.key_ops

        pub = RSAPublicNumbers(n=_bytes_to_int(jwk.n), e=_bytes_to_int(jwk.e))

        # if the private key values are specified construct a private key
        # only the secret primes and private exponent are needed as other fields can be calculated
        if jwk.p and jwk.q and jwk.d:
            # convert the values of p, q, and d from bytes to int
            p = _bytes_to_int(jwk.p)
            q = _bytes_to_int(jwk.q)
            d = _bytes_to_int(jwk.d)

            # convert or compute the remaining private key numbers
            dmp1 = _bytes_to_int(jwk.dp) if jwk.dp else rsa_crt_dmp1(private_exponent=d, p=p)
            dmq1 = _bytes_to_int(jwk.dq) if jwk.dq else rsa_crt_dmq1(private_exponent=d, q=q)
            iqmp = _bytes_to_int(jwk.qi) if jwk.qi else rsa_crt_iqmp(p=p, q=q)

            # create the private key from the jwk key values
            priv = RSAPrivateNumbers(p=p, q=q, d=d, dmp1=dmp1, dmq1=dmq1, iqmp=iqmp, public_numbers=pub)
            key_impl = priv.private_key(cryptography.hazmat.backends.default_backend())

        # if the necessary private key values are not specified create the public key
        else:
            key_impl = pub.public_key(cryptography.hazmat.backends.default_backend())

        rsa_key._rsa_impl = key_impl

        return rsa_key
Exemple #16
0
    def _load_prikey_with_decrypted_data(self, decrypted_prikey_data):
        der_pri = der_decoder.decode(decrypted_prikey_data)
        der_pri2 = der_decoder.decode(der_pri[0][2])

        # (n, e, d, p, q)
        (n, e, d, p, q) = (der_pri2[0][1], der_pri2[0][2], der_pri2[0][3], der_pri2[0][4], der_pri2[0][5])
        (n, e, d, p, q) = (int(n), int(e), int(d), int(p), int(q))
        iqmp = rsa_crt_iqmp(p, q)
        dmp1 = rsa_crt_dmp1(e, p)
        dmq1 = rsa_crt_dmq1(e, q)
        pn = RSAPublicNumbers(n=n, e=e)

        self.prikey = RSAPrivateNumbers(p=p, q=q, d=d, dmp1=dmp1, dmq1=dmq1, iqmp=iqmp,
                                        public_numbers=pn).private_key(backend=default_backend())
        if len(der_pri[0]) > 3:
            # sometimes, r value is not exist -  (i don't know why..)
            self._rand_num = der_pri[0][3][1][0]  # so raw data, can't be eaten
        return
Exemple #17
0
def new_fixed_rsa_key(p, q):
    """
    new_fixed_rsa_key creates a new Cryptography-lib-compatible RSA private key
    using p and q as factors of N.
    :param p: first prime
    :param q: second prime
    :return: RSA private key
    """
    # We calculate n
    n = p * q
    # phi is phi(n) = (p - 1) * (q - 1)
    phi = (p - 1) * (q - 1)
    # e is usually used as pow(2,16) + 1 = 65537
    e = 65537
    # d is the inverse of e mod phi
    d = mod_inv(e, phi)
    # some useful precalculations required by Cryptography library (here is not what you are looking for)
    iqmp = rsa_crt_iqmp(p, q)
    dmp1 = rsa_crt_dmp1(d, p)
    dmq1 = rsa_crt_dmq1(d, q)
    public_numbers = RSAPublicNumbers(e, n)
    return RSAPrivateNumbers(p, q, d, dmp1, dmq1, iqmp,
                             public_numbers).private_key(default_backend())
Exemple #18
0
        def from_jwk(jwk):
            try:
                obj = json.loads(jwk)
            except ValueError:
                raise InvalidKeyError("Key is not valid JSON")

            if obj.get("kty") != "RSA":
                raise InvalidKeyError("Not an RSA key")

            if "d" in obj and "e" in obj and "n" in obj:
                # Private key
                if "oth" in obj:
                    raise InvalidKeyError(
                        "Unsupported RSA private key: > 2 primes not supported"
                    )

                other_props = ["p", "q", "dp", "dq", "qi"]
                props_found = [prop in obj for prop in other_props]
                any_props_found = any(props_found)

                if any_props_found and not all(props_found):
                    raise InvalidKeyError(
                        "RSA key must include all parameters if any are present besides d"
                    )

                public_numbers = RSAPublicNumbers(
                    from_base64url_uint(obj["e"]),
                    from_base64url_uint(obj["n"]),
                )

                if any_props_found:
                    numbers = RSAPrivateNumbers(
                        d=from_base64url_uint(obj["d"]),
                        p=from_base64url_uint(obj["p"]),
                        q=from_base64url_uint(obj["q"]),
                        dmp1=from_base64url_uint(obj["dp"]),
                        dmq1=from_base64url_uint(obj["dq"]),
                        iqmp=from_base64url_uint(obj["qi"]),
                        public_numbers=public_numbers,
                    )
                else:
                    d = from_base64url_uint(obj["d"])
                    p, q = rsa_recover_prime_factors(public_numbers.n, d,
                                                     public_numbers.e)

                    numbers = RSAPrivateNumbers(
                        d=d,
                        p=p,
                        q=q,
                        dmp1=rsa_crt_dmp1(d, p),
                        dmq1=rsa_crt_dmq1(d, q),
                        iqmp=rsa_crt_iqmp(p, q),
                        public_numbers=public_numbers,
                    )

                return numbers.private_key(default_backend())
            elif "n" in obj and "e" in obj:
                # Public key
                numbers = RSAPublicNumbers(
                    from_base64url_uint(obj["e"]),
                    from_base64url_uint(obj["n"]),
                )

                return numbers.public_key(default_backend())
            else:
                raise InvalidKeyError("Not a public or private key")
RSA_KEY_512 = RSAPrivateNumbers(
    p=int(
        "d57846898d5c0de249c08467586cb458fa9bc417cdf297f73cfc52281b787cd9", 16
    ),
    q=int(
        "d10f71229e87e010eb363db6a85fd07df72d985b73c42786191f2ce9134afb2d", 16
    ),
    d=int(
        "272869352cacf9c866c4e107acc95d4c608ca91460a93d28588d51cfccc07f449"
        "18bbe7660f9f16adc2b4ed36ca310ef3d63b79bd447456e3505736a45a6ed21",
        16,
    ),
    dmp1=int(
        "addff2ec7564c6b64bc670d250b6f24b0b8db6b2810099813b7e7658cecf5c39", 16
    ),
    dmq1=int(
        "463ae9c6b77aedcac1397781e50e4afc060d4b216dc2778494ebe42a6850c81", 16
    ),
    iqmp=int(
        "54deef8548f65cad1d411527a32dcb8e712d3e128e4e0ff118663fae82a758f4", 16
    ),
    public_numbers=RSAPublicNumbers(
        e=65537,
        n=int(
            "ae5411f963c50e3267fafcf76381c8b1e5f7b741fdb2a544bcf48bd607b10c991"
            "90caeb8011dc22cf83d921da55ec32bd05cac3ee02ca5e1dbef93952850b525",
            16,
        ),
    ),
)
Exemple #20
0
    def __init__(self, params: Dict[int, Any]):
        super().__init__(params)

        self._key: Any = None
        self._hash: Any = None
        self._padding: Any = None
        salt_len: Any = padding.PSS.MAX_LENGTH

        # Validate kty.
        if params[1] != 3:
            raise ValueError("kty(1) should be RSA(3).")

        # Validate alg.
        if 3 not in params:
            raise ValueError("alg(3) not found.")
        if params[3] not in COSE_ALGORITHMS_RSA.values():
            raise ValueError(
                f"Unsupported or unknown alg(3) for RSA: {params[3]}.")
        if params[3] == -259 or params[3] == -39:
            self._hash = hashes.SHA512
            salt_len = 64
        elif params[3] == -258 or params[3] == -38:
            self._hash = hashes.SHA384
            salt_len = 48
        elif params[3] == -257 or params[3] == -37:
            self._hash = hashes.SHA256
            salt_len = 32
        else:
            raise ValueError(
                f"Unsupported or unknown alg(3) for RSA: {params[3]}.")
        if params[3] in [-37, -38, -39]:
            self._padding = padding.PSS(mgf=padding.MGF1(self._hash()),
                                        salt_length=salt_len)
        else:
            self._padding = padding.PKCS1v15()

        # Validate key_ops.
        if -3 not in params:  # the RSA private exponent d.
            if not self._key_ops:
                self._key_ops = RSAKey._ACCEPTABLE_PUBLIC_KEY_OPS
            else:
                prohibited = [
                    ops for ops in self._key_ops
                    if ops not in RSAKey._ACCEPTABLE_PUBLIC_KEY_OPS
                ]
                if prohibited:
                    raise ValueError(
                        f"Unknown or not permissible key_ops(4) for RSAKey: {prohibited[0]}."
                    )
        else:
            if not self._key_ops:
                self._key_ops = RSAKey._ACCEPTABLE_PRIVATE_KEY_OPS
            else:
                prohibited = [
                    ops for ops in self._key_ops
                    if ops not in RSAKey._ACCEPTABLE_PRIVATE_KEY_OPS
                ]
                if prohibited:
                    raise ValueError(
                        f"Unknown or not permissible key_ops(4) for RSAKey: {prohibited[0]}."
                    )

        # Validate RSA specific parameters.
        if -1 not in params or not isinstance(params[-1], bytes):
            raise ValueError("n(-1) should be set as bytes.")
        if -2 not in params or not isinstance(params[-2], bytes):
            raise ValueError("e(-2) should be set as bytes.")

        public_numbers = RSAPublicNumbers(
            n=int.from_bytes(params[-1], "big"),
            e=int.from_bytes(params[-2], "big"),
        )
        self._dict = params
        if -3 not in params:  # the RSA private exponent d.
            private_props = [
                p for p in params.keys() if p in [-4, -5, -6, -7, -8]
            ]
            if private_props:
                raise ValueError(
                    f"RSA public key should not have private parameter: {private_props[0]}."
                )
            self._key = public_numbers.public_key()
            return

        if -3 not in params or not isinstance(params[-3], bytes):
            raise ValueError("d(-3) should be set as bytes.")
        if -4 not in params or not isinstance(params[-4], bytes):
            raise ValueError("p(-4) should be set as bytes.")
        if -5 not in params or not isinstance(params[-5], bytes):
            raise ValueError("q(-5) should be set as bytes.")
        if -6 not in params or not isinstance(params[-6], bytes):
            raise ValueError("dP(-6) should be set as bytes.")
        if -7 not in params or not isinstance(params[-7], bytes):
            raise ValueError("dQ(-7) should be set as bytes.")
        if -8 not in params or not isinstance(params[-8], bytes):
            raise ValueError("qInv(-8) should be set as bytes.")

        private_numbers = RSAPrivateNumbers(
            d=int.from_bytes(params[-3], "big"),
            p=int.from_bytes(params[-4], "big"),
            q=int.from_bytes(params[-5], "big"),
            dmp1=int.from_bytes(params[-6], "big"),
            dmq1=int.from_bytes(params[-7], "big"),
            iqmp=int.from_bytes(params[-8], "big"),
            public_numbers=public_numbers,
        )
        self._key = private_numbers.private_key()
        return
Exemple #21
0
class PinkSign:
    """Main class for PinkSign"""
    def __init__(self,
                 pubkey_path: str = None,
                 pubkey_data: bytes = None,
                 prikey_path: str = None,
                 prikey_data: bytes = None,
                 prikey_password: bytes = None,
                 p12_path: str = None,
                 p12_data: bytes = None):
        """
        Initialize
        :param pubkey_path: path for public key file (e.g "/some/path/signCert.der")
        :param pubkey_data(bytes): raw payload for public key file (e.g "0\x82...")
        :param prikey_path: path for private key file (e.g "/some/path/signPri.key")
        :param prikey_data(bytes): raw payload for private key file (e.g "0\x82...")
        :param prikey_password: passworkd for NPKI (e.g b"h@ppy-chr1stm@s")
        :param p12_path: path for p12/pfx file (e.g "/some/path/p12file.pfx")
        :param p12_data: raw payload for p12/pfx (e.g b"0\x82..."

        You can init like
        p = PinkSign()
        p = PinkSign(pubkey_path="/some/path/signCert.der")
        p = PinkSign(pubkey_path="/some/path/signCert.der", prikey_path="/some/path/signPri.key", prikey_password="******")
        p = PinkSign(pubkey_data=b"0\x82...")
        p = PinkSign(p12_path='/some/path/p12file.pfx', prikey_password="******")
        You can get help with choose_cert() function.

        Priority of parameter
        1) P12 path
        2) P12 data
        3)
            A) Public Key path
            B) Public Key data

            A) Private Key path
            B) Private Key data
        """
        self.pubkey_path = pubkey_path
        self.prikey_path = prikey_path
        self.prikey_data = prikey_data
        if prikey_password:
            if isinstance(prikey_password, str):
                logging.warning(f"Please use bytes for passphrase")
                prikey_password = str.encode(prikey_password)
        self.prikey_password = prikey_password
        self.p12_path = p12_path
        self.p12_data = p12_data
        self.pub_cert = None
        self.prikey: RSAPrivateKey = None
        self.pub_data: bytes = None
        self.pubkey: RSAPublicKey = None
        self.rand_num = None
        if p12_path is not None:
            self.load_p12()
        elif p12_data is not None:
            self.load_p12(p12_data=p12_data)
        else:
            if pubkey_path is not None:
                self.load_pubkey()
            elif pubkey_data is not None:
                self.load_pubkey(pubkey_data=pubkey_data)
            if prikey_path is not None and prikey_password is not None:
                self.load_prikey()
        return

    def load_pubkey(self,
                    pubkey_path: str = None,
                    pubkey_data: bytes = None) -> None:
        """Load public key file
        :param pubkey_path: (str) path for public key file
        :param pubkey_data: (bytes) raw data from public key file

        p = PinkSign()
        p.load_pubkey('/my/cert/signCert.der')
        p.load_pubkey(pubkey_data=b"0\x82...")

        """
        if not any([self.pubkey_path, pubkey_path, pubkey_data]):
            raise ValueError("Neither pubkey_path nor pubkey_data is exist.")

        if pubkey_data is not None:
            self.pub_data = pubkey_data
        else:
            if pubkey_path is not None:
                self.pubkey_path = pubkey_path
            self.pub_data = open(self.pubkey_path, 'rb').read()
        self.pub_cert = x509.load_der_x509_certificate(
            self.pub_data, default_backend())  # Certificate
        self.pubkey = self.pub_cert.public_key(
        )  # cryptography.hazmat.backends.openssl.rsa._RSAPublicKey
        return

    def load_prikey(self,
                    prikey_path: str = None,
                    prikey_data: bytes = None,
                    prikey_password: str = None) -> None:
        """Load public key file

        p = PinkSign(pubkey_path='/my/cert/signCert.der')
        p.load_prikey('/my/cert/signPri.key', prikey_password='******')

        """
        if self.pubkey is None:
            raise ValueError(
                "public key file should be loaded before load private key.")
        if not any(
            [self.prikey_path, prikey_path, self.prikey_data, prikey_data]):
            raise ValueError("prikey_path(prikey_data) is not defined.")
        if not any([self.prikey_password, prikey_password]):
            raise ValueError("prikey_password is not defined.")

        if prikey_path is not None:
            self.prikey_path = prikey_path
        if prikey_data is not None:
            self.prikey_data = prikey_data
        if prikey_password is not None:
            self.prikey_password = prikey_password

        if self.prikey_path is not None:
            d = open(self.prikey_path, 'rb').read()
        else:
            d = self.prikey_data
        der = der_decoder.decode(d)[0]

        # check if correct K-PKI prikey file
        algorithm_type = der[0][0].asTuple()

        private_key_decryption_key_functions = {
            ID_SEED_CBC_WITH_SHA1:
            self.get_private_key_decryption_key_for_seed_cbc_with_sha1,
            ID_SEED_CBC: self.get_private_key_decryption_key_for_seed_cbc,
            ID_PBES2: self.get_private_key_decryption_key_for_pbes2,
        }

        if algorithm_type not in private_key_decryption_key_functions.keys():
            raise ValueError("prikey is not correct K-PKI private key file")

        k, iv = private_key_decryption_key_functions[algorithm_type](der)
        cipher_key = der[1].asOctets()  # encrypted private key

        prikey_data = seed_cbc_128_decrypt(k, cipher_key, iv)
        self._load_prikey_with_decrypted_data(
            decrypted_prikey_data=prikey_data)
        return

    def _load_prikey_with_decrypted_data(self,
                                         decrypted_prikey_data: bytes) -> None:
        der_pri = der_decoder.decode(decrypted_prikey_data)
        der_pri2 = der_decoder.decode(der_pri[0][2])

        # (n, e, d, p, q)
        (n, e, d, p, q) = (der_pri2[0][1], der_pri2[0][2], der_pri2[0][3],
                           der_pri2[0][4], der_pri2[0][5])
        (n, e, d, p, q) = (int(n), int(e), int(d), int(p), int(q))
        iqmp = rsa_crt_iqmp(p, q)
        dmp1 = rsa_crt_dmp1(e, p)
        dmq1 = rsa_crt_dmq1(e, q)
        pn = RSAPublicNumbers(n=n, e=e)

        self.prikey = RSAPrivateNumbers(
            p=p, q=q, d=d, dmp1=dmp1, dmq1=dmq1, iqmp=iqmp,
            public_numbers=pn).private_key(backend=default_backend())
        if len(der_pri[0]) > 3:
            # sometimes, r value is not exist -  (i don't know why..)
            self._rand_num = der_pri[0][3][1][0]  # so raw data, can't be eaten
        return

    def load_p12(self, p12_data: bytes = None) -> None:
        """Load key information from P12(PKCS12, Usually pfx)"""
        if p12_data is None:
            p12_data = open(self.p12_path, 'rb').read()

        pubkey_data, prikey_data = separate_p12_into_npki(
            p12_data, self.prikey_password)
        self.load_pubkey(pubkey_data=pubkey_data)
        self._load_prikey_with_decrypted_data(
            decrypted_prikey_data=prikey_data)
        return

    def cn(self) -> str:
        """Get cn value

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        print p.cn()  # "홍길순()0010023400506789012345"
        """
        if self.pub_cert is None:
            raise ValueError("Public key should be loaded before fetching DN.")
        for dn in self.pub_cert.subject.rdns:
            if dn.rfc4514_string().startswith('CN='):
                return dn.rfc4514_string()[3:]
        return ''

    def issuer(self) -> str:
        """Get issuer value

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        print p.issuer()  # "yessign"
        """
        if self.pub_cert is None:
            raise ValueError(
                "Public key should be loaded before fetching issuer.")
        for dn in self.pub_cert.issuer.rdns:
            if dn.rfc4514_string().startswith('O='):
                return dn.rfc4514_string()[2:]

    def cert_class(self) -> str:
        """Get cert class

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        print p.cert_class()  # "yessignCA Class 2"
        """
        if self.pub_cert is None:
            raise ValueError(
                "Public key should be loaded before fetching cert class.")
        for dn in self.pub_cert.issuer.rdns:
            if dn.rfc4514_string().startswith('CN='):
                return dn.rfc4514_string()[3:]

    def cert_type_oid(self) -> str:
        """Get cert type
        TODO: bad way to find value following oid. exception may occurred with certain certificate

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        print p.cert_type_oid()  # "1.2.410.200005.1.1.4"
        """
        if self.pub_cert is None:
            raise ValueError(
                "Public key should be loaded before fetching cert type.")
        for ext in self.pub_cert.extensions:
            if ext.oid.dotted_string == '2.5.29.32':  #
                return ext.value[0].policy_identifier.dotted_string

    def valid_date(self) -> (datetime, datetime):
        """Get valid date range

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        print p.valid_date()  # datetime.datetime(2019, 6, 11, 14, 59, 59), datetime.datetime(2018, 6, 5, 7, 22)
        """
        if self.pub_cert is None:
            raise ValueError(
                "Public key should be loaded before fetching valid date.")
        return self.pub_cert.not_valid_before, self.pub_cert.not_valid_after

    def serialnum(self) -> int:
        """Get serial number value

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        print p.serialnum()  # 123456789
        print hex(p.serialnum())  # 0x1a2b3c4d
        """
        if self.pub_cert is None:
            raise ValueError(
                "Public key should be loaded before fetching serial number.")
        return self.pub_cert.serial_number

    def sign(self, msg: bytes, algorithm=hashes.SHA256(), padding_=PKCS1v15()):
        """Signing with private key - pkcs1 encode and decrypt

        p = PinkSign(pubkey_path="/path/signCert.der", prikey_path="/path/signPri.key", prikey_password="******")
        s = p.sign(b'my message')  # '\x00\x01\x02...'
        """
        if self.prikey is None:
            raise ValueError("Private key is required for signing.")
        return self.prikey.sign(data=msg,
                                padding=padding_,
                                algorithm=algorithm)

    def verify(
        self,
        signature: bytes,
        msg: bytes,
        algorithm=hashes.SHA256(),
        padding_=PKCS1v15()) -> bool:
        """Verify with public key - encrypt and decode pkcs1 with hashed msg

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        s = p.sign(b'my message')  # b'\x00\x01\x02...'
        v = p.verify(s, b'my message')  # True
        """
        if self.pubkey is None:
            raise ValueError("Public key is required for verification.")
        try:
            self.pubkey.verify(data=msg,
                               signature=signature,
                               padding=padding_,
                               algorithm=algorithm)
            return True
        except InvalidSignature:
            return False
        except Exception as e:
            raise e

    def decrypt(self, msg, padding_=PKCS1v15()):
        """Decrypt with private key - also used when signing.

        p = PinkSign(pubkey_path="/path/signCert.der", prikey_path="/path/signPri.key", prikey_password="******")
        msg = p.decrypt('\x0a\x0b\x0c...')  # 'my message'
        """
        if self.prikey is None:
            raise ValueError("Private key is required for decryption.")
        return self.prikey.decrypt(ciphertext=msg, padding=padding_)

    def encrypt(self, msg, padding_=PKCS1v15()):
        """Encrypt with public key - also used when verify sign

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        encrypted = p.encrypt('my message')  # '\x0a\x0b\x0c...'
        """
        if self.pubkey is None:
            raise ValueError("Public key is required for encryption.")
        return self.pubkey.encrypt(msg, padding=padding_)

    def pkcs7_signed_msg(self, msg: bytes):
        """PKCS#7 signed with certificate
        Sign and encapsulate message
        """
        signed = self.sign(msg)

        owner_cert_pub = der_decoder.decode(self.pub_data)[0]

        # signedData (PKCS #7)
        oi_pkcs7_signed = ObjectIdentifier((1, 2, 840, 113549, 1, 7, 2))
        oi_pkcs7_data = ObjectIdentifier((1, 2, 840, 113549, 1, 7, 1))
        oi_sha256 = ObjectIdentifier((2, 16, 840, 1, 101, 3, 4, 2, 1))
        oi_pkcs7_rsa_enc = ObjectIdentifier((1, 2, 840, 113549, 1, 1, 1))

        der = Sequence().setComponentByPosition(0, oi_pkcs7_signed)

        data = Sequence()
        data = data.setComponentByPosition(0, Integer(1))
        data = data.setComponentByPosition(
            1,
            Set().setComponentByPosition(
                0,
                Sequence().setComponentByPosition(
                    0, oi_sha256).setComponentByPosition(1, Null(''))))
        data = data.setComponentByPosition(
            2,
            Sequence().setComponentByPosition(
                0, oi_pkcs7_data).setComponentByPosition(
                    1,
                    Sequence().subtype(implicitTag=tag.Tag(
                        tag.tagClassContext, tag.tagFormatSimple,
                        0)).setComponentByPosition(
                            0, OctetString(hexValue=msg.hex()))))
        data = data.setComponentByPosition(
            3,
            Sequence().subtype(
                implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple,
                                    0)).setComponentByPosition(
                                        0, owner_cert_pub))

        data4001 = Sequence().setComponentByPosition(0, owner_cert_pub[0][3])
        data4001 = data4001.setComponentByPosition(1, owner_cert_pub[0][1])
        data4002 = Sequence().setComponentByPosition(
            0, oi_sha256).setComponentByPosition(1, Null(''))
        data4003 = Sequence().setComponentByPosition(
            0, oi_pkcs7_rsa_enc).setComponentByPosition(1, Null(''))
        data4004 = OctetString(hexValue=signed.hex())

        data = data.setComponentByPosition(
            4,
            Set().setComponentByPosition(
                0,
                Sequence().setComponentByPosition(
                    0, Integer(1)).setComponentByPosition(
                        1, data4001).setComponentByPosition(
                            2, data4002).setComponentByPosition(
                                3,
                                data4003).setComponentByPosition(4, data4004)))

        der = der.setComponentByPosition(
            1,
            Sequence().subtype(
                implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple,
                                    0)).setComponentByPosition(0, data))

        return der_encoder.encode(der)

    # def pkcs7_enveloped_msg(self, msg, data, iv=b"0123456789012345"):
    #     """WIP: PKCS#7 envelop msg, data with cert"""
    #     oi_pkcs7_rsa_enc = ObjectIdentifier((1, 2, 840, 113549, 1, 1, 1))
    #     oi_pkcs7_data = ObjectIdentifier((1, 2, 840, 113549, 1, 7, 1))
    #     oi_seed_cbc = ObjectIdentifier(id_seed_cbc)
    #
    #     der = Sequence().setComponentByPosition(0, ObjectIdentifier(id_pkcs7_enveloped_data))
    #
    #     data_set = Sequence().setComponentByPosition(0, Integer(0))
    #     data_set = data_set.setComponentByPosition(1, Sequence().setComponentByPosition(0, self.pub_cert[0][3]).setComponentByPosition(1, self.pub_cert[0][1]))
    #     data_set = data_set.setComponentByPosition(2, Sequence().setComponentByPosition(0, oi_pkcs7_rsa_enc).setComponentByPosition(1, Null('')))
    #     data_set = data_set.setComponentByPosition(3, OctetString(hexValue=msg.hex()))
    #
    #     data_seq = Sequence().setComponentByPosition(0, oi_pkcs7_data)
    #     data_seq = data_seq.setComponentByPosition(1, Sequence().setComponentByPosition(0, oi_seed_cbc).setComponentByPosition(1, OctetString(hexValue=iv.hex())))
    #     data_seq = data_seq.setComponentByPosition(2, OctetString(hexValue=data.hex()).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
    #
    #     data = Sequence().setComponentByPosition(0, Integer(0))
    #     data = data.setComponentByPosition(1, Set().setComponentByPosition(0, data_set))
    #     data = data.setComponentByPosition(2, data_seq)
    #
    #     der = der.setComponentByPosition(1, Sequence().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)).setComponentByPosition(0, data))
    #     return der_encoder.encode(der)

    def get_private_key_decryption_key_for_seed_cbc_with_sha1(
            self, der: Sequence) -> (bytes, bytes):
        """
        (PBKDF1) get key, iv for decrypt private key encrypted with PBES1
        :param der: encrypted private key der
        :return: tuple for key, iv
        """
        salt = der[0][1][0].asOctets()  # salt for pbkdf#5
        iter_cnt = int(der[0][1][1])  # usually 2048
        dk = pbkdf1(self.prikey_password, salt, iter_cnt, 20)
        k = dk[:16]
        div = hashlib.sha1(dk[16:20]).digest()
        iv = div[:16]
        return k, iv

    def get_private_key_decryption_key_for_seed_cbc(
            self, der: Sequence) -> (bytes, bytes):
        """
        (PBKDF1) get key, iv for decrypt private key encrypted with PBES1 (old style)
        :param der: encrypted private key der
        :return: tuple for key, iv
        """
        salt = der[0][1][0].asOctets()  # salt for pbkdf#5
        iter_cnt = int(der[0][1][1])  # usually 2048
        dk = pbkdf1(self.prikey_password, salt, iter_cnt, 20)
        k = dk[:16]
        iv = b"0123456789012345"
        return k, iv

    def get_private_key_decryption_key_for_pbes2(
            self, der: Sequence) -> (bytes, bytes):
        """
        (PBKDF2) get key, iv for decrypt private key encrypted with PBES2
        :param der: encrypted private key der
        :return: tuple for key, iv
        """
        # https://github.com/bandoche/PyPinkSign/issues/7
        salt = der[0][1][0][1][0].asOctets()  # salt for pkcs#5
        iter_cnt = int(der[0][1][0][1][1])  # usually 2048
        kdf = PBKDF2HMAC(
            algorithm=hashes.SHA1(),
            length=16,
            salt=salt,
            iterations=iter_cnt,
            backend=default_backend(),
        )
        k = kdf.derive(self.prikey_password)
        iv = der[0][1][1][1].asOctets()
        return k, iv
Exemple #22
0
class PinkSign:
    """Main class for PinkSign

    If the class has public attributes, they may be documented here
    in an ``Attributes`` section and follow the same formatting as a
    function's ``Args`` section. Alternatively, attributes may be documented
    inline with the attribute's declaration (see __init__ method below).

    Properties created with the ``@property`` decorator should be documented
    in the property's getter method.

    """

    def __init__(self, pubkey_path=None, pubkey_data=None, prikey_path=None, prikey_data=None, prikey_password=None,
                 p12_path=None, p12_data=None):
        """
        Initialize
        :param pubkey_path: path for public key file (e.g "/some/path/signCert.der")
        :param pubkey_data(bytes): raw payload for public key file (e.g "0\x82...")
        :param prikey_path: path for private key file (e.g "/some/path/signPri.key")
        :param prikey_data(bytes): raw payload for private key file (e.g "0\x82...")
        :param prikey_password: passworkd for NPKI (e.g "h@ppy-chr1stm@s")
        :param p12_path: path for p12/pfx file (e.g "/some/path/p12file.pfx")
        :param p12_data: raw payload for p12/pfx (e.g "0\x82..."

        You can init like
        p = PinkSign()
        p = PinkSign(pubkey_path="/some/path/signCert.der")
        p = PinkSign(pubkey_path="/some/path/signCert.der", prikey_path="/some/path/signPri.key", prikey_password="******")
        p = PinkSign(pubkey_data="0\x82...")
        p = PinkSign(p12_path='/some/path/p12file.pfx', prikey_password="******")
        You can get help with choose_cert() function.

        Order of parameter
        1) P12 oath
        2) P12 data
            A) Public Key path
            B) Public Key data

            A) Private Key path
            B) Private Key data
        """
        self.pubkey_path = pubkey_path
        self.prikey_path = prikey_path
        self.prikey_data = prikey_data
        self.prikey_password = prikey_password
        self.p12_path = p12_path
        self.p12_data = p12_data
        self.pub_cert = None
        self.prikey = None
        self.pubkey = None
        self.rand_num = None
        if p12_path is not None:
            self.load_p12()
        elif p12_data is not None:
            self.load_p12(p12_data=p12_data)
        else:
            if pubkey_path is not None:
                self.load_pubkey()
            elif pubkey_data is not None:
                self.load_pubkey(pubkey_data=pubkey_data)
            if prikey_path is not None and prikey_password is not None:
                self.load_prikey()
        return

    def load_pubkey(self, pubkey_path=None, pubkey_data=None):
        """Load public key file
        :param pubkey_path: (str) path for public key file
        :param pubkey_data: (bytes) raw data from public key file

        p = PinkSign()
        p.load_pubkey('/my/cert/signCert.der')
        p.load_pubkey(pubkey_data="0\x82...")

        """
        if not any([self.pubkey_path, pubkey_path, pubkey_data]):
            raise ValueError("Neither pubkey_path nor pubkey_data is exist.")

        if pubkey_data is not None:
            d = pubkey_data
        else:
            if pubkey_path is not None:
                self.pubkey_path = pubkey_path
            d = open(self.pubkey_path, 'rb').read()
        self.pub_cert = x509.load_der_x509_certificate(d, default_backend())  # Certificate
        self.pubkey = self.pub_cert.public_key()  # cryptography.hazmat.backends.openssl.rsa._RSAPublicKey
        return

    def load_prikey(self, prikey_path=None, prikey_data=None, prikey_password=None):
        """Load public key file

        p = PinkSign(pubkey_path='/my/cert/signCert.der')
        p.load_prikey('/my/cert/signPri.key', prikey_password='******')

        """
        if self.pubkey is None:
            raise ValueError("pubkey should be loaded first.")
        if not any([self.prikey_path, prikey_path, self.prikey_data, prikey_data]):
            raise ValueError("prikey_path(prikey_data) is not defined.")
        if not any([self.prikey_password, prikey_password]):
            raise ValueError("prikey_password is not defined.")

        if prikey_path is not None:
            self.prikey_path = prikey_path
        if prikey_data is not None:
            self.prikey_data = prikey_data
        if prikey_password is not None:
            self.prikey_password = prikey_password

        if self.prikey_path is not None:
            d = open(self.prikey_path, 'rb').read()
        else:
            d = self.prikey_data
        der = der_decoder.decode(d)[0]

        # check if correct K-PKI prikey file
        algorithm_type = der[0][0].asTuple()

        if algorithm_type not in (id_seed_cbc_with_sha1, id_seed_cbc):
            raise ValueError("prikey is not correct K-PKI private key file")

        salt = der[0][1][0].asOctets()  # salt for pbkdf#5
        iter_cnt = int(der[0][1][1])  # usually 2048
        cipher_key = der[1].asOctets()  # encryped private key
        dk = pbkdf1(self.prikey_password, salt, iter_cnt, 20)
        k = dk[:16]
        div = hashlib.sha1(dk[16:20]).digest()

        # IV for SEED-CBC has dependency on Algorithm type (Old-style K-PKI or Renewal)
        if algorithm_type == id_seed_cbc_with_sha1:
            iv = div[:16]
        else:
            iv = "123456789012345"

        prikey_data = seed_cbc_128_decrypt(k, cipher_key, iv)
        self._load_prikey_with_decrypted_data(decrypted_prikey_data=prikey_data)
        return

    def _load_prikey_with_decrypted_data(self, decrypted_prikey_data):
        der_pri = der_decoder.decode(decrypted_prikey_data)
        der_pri2 = der_decoder.decode(der_pri[0][2])

        # (n, e, d, p, q)
        (n, e, d, p, q) = (der_pri2[0][1], der_pri2[0][2], der_pri2[0][3], der_pri2[0][4], der_pri2[0][5])
        (n, e, d, p, q) = (int(n), int(e), int(d), int(p), int(q))
        iqmp = rsa_crt_iqmp(p, q)
        dmp1 = rsa_crt_dmp1(e, p)
        dmq1 = rsa_crt_dmq1(e, q)
        pn = RSAPublicNumbers(n=n, e=e)

        self.prikey = RSAPrivateNumbers(p=p, q=q, d=d, dmp1=dmp1, dmq1=dmq1, iqmp=iqmp,
                                        public_numbers=pn).private_key(backend=default_backend())
        if len(der_pri[0]) > 3:
            # sometimes, r value is not exist -  (i don't know why..)
            self._rand_num = der_pri[0][3][1][0]  # so raw data, can't be eaten
        return

    def load_p12(self, p12_data=None):
        """Load key information from P12(PKCS12, Usually pfx)"""
        if p12_data is None:
            p12_data = open(self.p12_path, 'rb').read()

        p12 = crypto.load_pkcs12(p12_data, self.prikey_password)
        prikey_data = crypto.dump_privatekey(crypto.FILETYPE_PEM, p12.get_privatekey())
        prikey_data = prikey_data.replace(b'-----BEGIN PRIVATE KEY-----\n', b'').replace(b'\n-----END PRIVATE KEY-----',
                                                                                         b'')
        prikey_data = base64.b64decode(prikey_data)
        pubkey_data = crypto.dump_certificate(crypto.FILETYPE_PEM, p12.get_certificate())
        pubkey_data = pubkey_data.replace(b'-----BEGIN CERTIFICATE-----\n', b'').replace(b'\n-----END CERTIFICATE-----',
                                                                                         b'')
        pubkey_data = base64.b64decode(pubkey_data)
        self.load_pubkey(pubkey_data=pubkey_data)
        self._load_prikey_with_decrypted_data(decrypted_prikey_data=prikey_data)
        return

    def cn(self):
        """Get cn value

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        print p.cn()  # "홍길순()0010023400506789012345"
        """
        if self.pub_cert is None:
            raise ValueError("Public key should be loaded for fetch DN.")
        for dn in self.pub_cert.subject.rdns:
            if dn.rfc4514_string().startswith('CN='):
                return dn.rfc4514_string()[3:]
        return ''

    def issuer(self):
        """Get issuer value

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        print p.issuer()  # "yessign"
        """
        if self.pub_cert is None:
            raise ValueError("Public key should be loaded for fetch issuer.")
        for dn in self.pub_cert.issuer.rdns:
            if dn.rfc4514_string().startswith('O='):
                return dn.rfc4514_string()[2:]

    def cert_class(self):
        """Get cert class

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        print p.cert_class()  # "yessignCA Class 2"
        """
        if self.pub_cert is None:
            raise ValueError("Public key should be loaded for fetch cert class.")
        for dn in self.pub_cert.issuer.rdns:
            if dn.rfc4514_string().startswith('CN='):
                return dn.rfc4514_string()[3:]

    def cert_type_oid(self):
        """Get cert type

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        print p.cert_type_oid()  # "1.2.410.200005.1.1.4"
        """
        if self.pub_cert is None:
            raise ValueError("Public key should be loaded for fetch cert type.")
        try:
            for ext in self.pub_cert.extensions:
                if ext.oid.dotted_string == '2.5.29.32':  #
                    return ext.value[0].policy_identifier.dotted_string
            pass
        except Exception:
            return ''

    def valid_date(self) -> (datetime, datetime):
        """Get valid date range

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        print p.valid_date()  # datetime.datetime(2019, 6, 11, 14, 59, 59), datetime.datetime(2018, 6, 5, 7, 22)
        """
        if self.pub_cert is None:
            raise ValueError("Public key should be loaded for fetch valid date.")
        return self.pub_cert.not_valid_before, self.pub_cert.not_valid_after

    def serialnum(self):
        """Get serial number value

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        print p.serialnum()  # 123456789
        print hex(p.serialnum())  # 0x1a2b3c4d
        """
        if self.pub_cert is None:
            raise ValueError("Public key should be loaded for fetch serial number.")
        return self.pub_cert.serial_number

    def sign(self, msg, algorithm=hashes.SHA256(), padding_=PKCS1v15()):
        """Signing with private key - pkcs1 encode and decrypt

        p = PinkSign(pubkey_path="/some/path/signCert.der", prikey_path="/some/path/signPri.key", prikey_password="******")
        s = p.sign('my message')  # '\x00\x01\x02...'
        """
        if self.prikey is None:
            raise ValueError("Private key is required for signing.")
        return self.prikey.sign(data=msg, padding=padding_, algorithm=algorithm)

    def verify(self, signature, msg, algorithm=hashes.SHA256(), padding_=PKCS1v15()):
        """Verify with public key - encrypt and decode pkcs1 with hashed msg

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        s = p.sign('my message')  # '\x00\x01\x02...'
        v = p.verify(s, 'my message')  # True
        """
        if self.pubkey is None:
            raise ValueError("Public key is required for verification.")
        try:
            self.pubkey.verify(data=msg, signature=signature, padding=padding_, algorithm=algorithm)
            return True
        except InvalidSignature:
            return False
        except Exception as e:
            raise e

    def decrypt(self, msg, padding_=PKCS1v15()):
        """Decrypt with private key - also used when signing.

        p = PinkSign(pubkey_path="/some/path/signCert.der", prikey_path="/some/path/signPri.key", prikey_password="******")
        msg = p.decrypt('\x0a\x0b\x0c...')  # 'my message'
        """
        if self.prikey is None:
            raise ValueError("Private key is required for decryption.")
        return self.prikey.decrypt(ciphertext=msg, padding=padding_)

    def encrypt(self, msg, padding_=PKCS1v15()):
        """Encrypt with public key - also used when verify sign

        p = PinkSign(pubkey_path="/some/path/signCert.der")
        encrypted = p.encrypt('my message')  # '\x0a\x0b\x0c...'
        """
        if self.pubkey is None:
            raise ValueError("Public key is required for encryption.")
        return self.pubkey.encrypt(msg, padding=padding_)
Exemple #23
0
        def from_jwk(jwk):
            try:
                obj = json.loads(jwk)
            except ValueError:
                raise InvalidKeyError('Key is not valid JSON')

            if obj.get('kty') != 'RSA':
                raise InvalidKeyError('Not an RSA key')

            if 'd' in obj and 'e' in obj and 'n' in obj:
                # Private key
                if 'oth' in obj:
                    raise InvalidKeyError('Unsupported RSA private key: > 2 primes not supported')

                other_props = ['p', 'q', 'dp', 'dq', 'qi']
                props_found = [prop in obj for prop in other_props]
                any_props_found = any(props_found)

                if any_props_found and not all(props_found):
                    raise InvalidKeyError('RSA key must include all parameters if any are present besides d')

                public_numbers = RSAPublicNumbers(
                    from_base64url_uint(obj['e']), from_base64url_uint(obj['n'])
                )

                if any_props_found:
                    numbers = RSAPrivateNumbers(
                        d=from_base64url_uint(obj['d']),
                        p=from_base64url_uint(obj['p']),
                        q=from_base64url_uint(obj['q']),
                        dmp1=from_base64url_uint(obj['dp']),
                        dmq1=from_base64url_uint(obj['dq']),
                        iqmp=from_base64url_uint(obj['qi']),
                        public_numbers=public_numbers
                    )
                else:
                    d = from_base64url_uint(obj['d'])
                    p, q = rsa_recover_prime_factors(
                        public_numbers.n, d, public_numbers.e
                    )

                    numbers = RSAPrivateNumbers(
                        d=d,
                        p=p,
                        q=q,
                        dmp1=rsa_crt_dmp1(d, p),
                        dmq1=rsa_crt_dmq1(d, q),
                        iqmp=rsa_crt_iqmp(p, q),
                        public_numbers=public_numbers
                    )

                return numbers.private_key(default_backend())
            elif 'n' in obj and 'e' in obj:
                # Public key
                numbers = RSAPublicNumbers(
                    from_base64url_uint(obj['e']), from_base64url_uint(obj['n'])
                )

                return numbers.public_key(default_backend())
            else:
                raise InvalidKeyError('Not a public or private key')