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)
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())
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
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())
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())
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]), ), )
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
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)
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')
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
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())
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
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 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())
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, ), ), )
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
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
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_)
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')