def der2rsa(der): # Extract subjectPublicKeyInfo field from X.509 certificate (see RFC3280) cert = DerSequence() cert.decode(der) tbs_certificate = DerSequence() tbs_certificate.decode(cert[0]) subject_public_key_info = tbs_certificate[6] # Initialize RSA key return RSA.importKey(subject_public_key_info)
def _create_subject_public_key_info(algo_oid, secret_key, params=None): if params is None: params = DerNull() spki = DerSequence([ DerSequence([DerObjectId(algo_oid), params]), DerBitString(secret_key) ]) return spki.encode()
def decrypt(data, passphrase): """Decrypt a piece of data using a passphrase and *PBES1*. The algorithm to use is automatically detected. :Parameters: data : byte string The piece of data to decrypt. passphrase : byte string The passphrase to use for decrypting the data. :Returns: The decrypted data, as a binary string. """ enc_private_key_info = DerSequence().decode(data) encrypted_algorithm = DerSequence().decode(enc_private_key_info[0]) encrypted_data = DerOctetString().decode( enc_private_key_info[1]).payload pbe_oid = DerObjectId().decode(encrypted_algorithm[0]).value cipher_params = {} if pbe_oid == _OID_PBE_WITH_MD5_AND_DES_CBC: # PBE_MD5_DES_CBC hashmod = MD5 ciphermod = DES elif pbe_oid == _OID_PBE_WITH_MD5_AND_RC2_CBC: # PBE_MD5_RC2_CBC hashmod = MD5 ciphermod = ARC2 cipher_params['effective_keylen'] = 64 elif pbe_oid == _OID_PBE_WITH_SHA1_AND_DES_CBC: # PBE_SHA1_DES_CBC hashmod = SHA1 ciphermod = DES elif pbe_oid == _OID_PBE_WITH_SHA1_AND_RC2_CBC: # PBE_SHA1_RC2_CBC hashmod = SHA1 ciphermod = ARC2 cipher_params['effective_keylen'] = 64 else: raise PbesError("Unknown OID for PBES1") pbe_params = DerSequence().decode(encrypted_algorithm[1], nr_elements=2) salt = DerOctetString().decode(pbe_params[0]).payload iterations = pbe_params[1] key_iv = PBKDF1(passphrase, salt, 16, iterations, hashmod) key, iv = key_iv[:8], key_iv[8:] cipher = ciphermod.new(key, ciphermod.MODE_CBC, iv, **cipher_params) pt = cipher.decrypt(encrypted_data) return unpad(pt, cipher.block_size)
def test_expected_nr_elements(self): der_bin = DerSequence([1, 2, 3]).encode() DerSequence().decode(der_bin, nr_elements=3) DerSequence().decode(der_bin, nr_elements=(2, 3)) self.assertRaises(ValueError, DerSequence().decode, der_bin, nr_elements=1) self.assertRaises(ValueError, DerSequence().decode, der_bin, nr_elements=(4, 5))
def generate_rsa_key_pair(): rsa_key = RSA.generate(2048) private_key = DerSequence([ 0, rsa_key.n, rsa_key.e, rsa_key.d, rsa_key.p, rsa_key.q, rsa_key.d % (rsa_key.p - 1), rsa_key.d % (rsa_key.q - 1), Integer(rsa_key.q).inverse(rsa_key.p) ]).encode() pub_key = rsa_key.publickey() public_key = DerSequence([pub_key.n, pub_key.e]).encode() return private_key, public_key
def rsa_public_from_der_certificate(certificate): # Extract subject_public_key_info field from X.509 certificate (see RFC3280) try: # try to extract pubkey from scapy.layers.x509 X509Cert type in case # der_certificate is of type X509Cert # Note: der_certificate may not be of type X509Cert if it wasn't # received completely, in that case, we'll try to extract it anyway # using the old method. # TODO: get rid of the old method and always expect X509Cert obj ? """ Rebuild ASN1 SubjectPublicKeyInfo since X509Cert does not provide the full struct ASN1F_SEQUENCE( ASN1F_SEQUENCE(ASN1F_OID("pubkey_algo","1.2.840.113549.1.1.1"), ASN1F_field("pk_value",ASN1_NULL(0))), ASN1F_BIT_STRING("pubkey","") ), """ subject_public_key_info = ASN1_SEQUENCE([ ASN1_SEQUENCE([certificate.pubkey_algo, certificate.pk_value]), certificate.pubkey ]) return RSA.importKey(str(subject_public_key_info)) except AttributeError: pass # Fallback method, may pot. allow to extract pubkey from incomplete der streams cert = DerSequence() cert.decode(certificate) tbs_certificate = DerSequence() tbs_certificate.decode(cert[0]) # first DER SEQUENCE # search for pubkey OID: rsaEncryption: "1.2.840.113549.1.1.1" # hex: 06 09 2A 86 48 86 F7 0D 01 01 01 subject_public_key_info = None for seq in tbs_certificate: if not isinstance(seq, basestring): continue # skip numerics and non sequence stuff if "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01" in seq: subject_public_key_info = seq if subject_public_key_info is None: raise ValueError( "could not find OID rsaEncryption 1.2.840.113549.1.1.1 in certificate" ) # Initialize RSA key return RSA.importKey(subject_public_key_info)
def get_public_key_from_file(file_name): with open(file_name) as f: pem = f.read() lines = pem.replace(" ", '').split() der = a2b_base64(''.join(lines[1:-1])) # Extract subjectPublicKeyInfo field from X.509 certificate (see RFC3280) cert = DerSequence() cert.decode(der) tbsCertificate = DerSequence() tbsCertificate.decode(cert[0]) subjectPublicKeyInfo = tbsCertificate[6] # Initialize RSA key publicKey = RSA.importKey(subjectPublicKeyInfo) return publicKey.publickey()
def write_signature_value(self, wire, contents) -> int: cng = Cng() hash_val, cb_hash = self._hash_contents(contents) cb_signature = c.c_ulong() status = cng.ncrypt.NCryptSignHash(self.h_key, 0, hash_val, cb_hash, 0, 0, c.pointer(cb_signature), 0) if not cng.nt_success(status): raise OSError(f'Error {status} returned by NCryptSignHash') signature = (c.c_ubyte * cb_signature.value)() status = cng.ncrypt.NCryptSignHash(self.h_key, 0, hash_val, cb_hash, signature, cb_signature, c.pointer(cb_signature), 0) if not cng.nt_success(status): raise OSError(f'Error {status} returned by NCryptSignHash') if self.key_type == SignatureType.SHA256_WITH_ECDSA: der = DerSequence( (int.from_bytes(signature[:cb_signature.value // 2], 'big'), int.from_bytes(signature[cb_signature.value // 2:], 'big'))).encode() else: der = bytes(signature) real_len = len(der) wire[:real_len] = der return real_len
def testEncode7(self): # One integer and another type (already encoded) der = DerSequence() der.append(0x180) der.append(b('0\x03\x02\x01\x05')) self.assertEquals(der.encode(), b('0\x09\x02\x02\x01\x800\x03\x02\x01\x05')) self.failIf(der.hasOnlyInts())
def _export_private_der(self, include_ec_params=True): assert self.has_private() # ECPrivateKey ::= SEQUENCE { # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), # privateKey OCTET STRING, # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, # publicKey [1] BIT STRING OPTIONAL # } # Public key - uncompressed form order_bytes = _curve.order.size_in_bytes() public_key = (b'\x04' + self.pointQ.x.to_bytes(order_bytes) + self.pointQ.y.to_bytes(order_bytes)) seq = [ 1, DerOctetString(self.d.to_bytes(order_bytes)), DerObjectId(_curve.oid, explicit=0), DerBitString(public_key, explicit=1) ] if not include_ec_params: del seq[2] return DerSequence(seq).encode()
def testEncode4(self): # One very long integer der = DerSequence() der.append(2**2048) self.assertEquals( der.encode(), b('0\x82\x01\x05') + b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00'))
def testDecode6(self): # Two integers der = DerSequence() der.decode(b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff')) self.assertEquals(len(der), 2) self.assertEquals(der[0], 0x180) self.assertEquals(der[1], 0xFF)
def _import_pkcs1_public(encoded, *kwargs): # RSAPublicKey ::= SEQUENCE { # modulus INTEGER, -- n # publicExponent INTEGER -- e # } der = DerSequence().decode(encoded, nr_elements=2, only_ints_expected=True) return construct(der)
def testDecode4(self): # One very long integer der = DerSequence() der.decode( b('0\x82\x01\x05') + b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00')) self.assertEquals(len(der), 1) self.assertEquals(der[0], 2**2048)
def _import_openssl_private(encoded, passphrase, params): if params: raise ValueError("DSA private key already comes with parameters") der = DerSequence().decode(encoded, nr_elements=6, only_ints_expected=True) if der[0] != 0: raise ValueError("No version found") tup = [der[comp] for comp in (4, 3, 1, 2, 5)] return construct(tup)
def testDecode7(self): # One integer and 2 other types der = DerSequence() der.decode(b('0\x0A\x02\x02\x01\x80\x24\x02\xb6\x63\x12\x00')) self.assertEquals(len(der), 3) self.assertEquals(der[0], 0x180) self.assertEquals(der[1], b('\x24\x02\xb6\x63')) self.assertEquals(der[2], b('\x12\x00'))
def testErrDecode3(self): # Wrong length format der = DerSequence() # Missing length in sub-item self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x01\x01\x00')) # Valid BER, but invalid DER length self.assertRaises(ValueError, der.decode, b('\x30\x81\x03\x02\x01\x01')) self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x81\x01\x01'))
def import_key(extern_key, salt=None): der, marker, _ = PEM.decode(extern_key) ints = DerSequence().decode(der) if not marker.startswith('myDSA'): raise ValueError('Invalid format') key_dict = dict(zip(('p', 'q', 'g', 'y', 'x'), map(Integer, ints))) return myDSA(key_dict, salt)
def _extract_subject_public_key_info(x509_certificate): """Extract subjectPublicKeyInfo from a DER X.509 certificate.""" certificate = DerSequence().decode(x509_certificate, nr_elements=3) tbs_certificate = DerSequence().decode(certificate[0], nr_elements=list(range(6, 11))) index = 5 try: tbs_certificate[0] + 1 # Version not present version = 1 except TypeError: version = DerInteger(explicit=0).decode(tbs_certificate[0]).value if version not in (2, 3): raise ValueError("Incorrect X.509 certificate version") index = 6 return tbs_certificate[index]
def _import_pkcs8(encoded, passphrase, params): if params: raise ValueError("PKCS#8 already includes parameters") k = PKCS8.unwrap(encoded, passphrase) if k[0] != oid: raise ValueError("No PKCS#8 encoded DSA key") x = DerInteger().decode(k[1]).value p, q, g = list(DerSequence().decode(k[2])) tup = (pow(g, x, p), g, p, q, x) return construct(tup)
def test_expected_only_integers(self): der_bin1 = DerSequence([1, 2, 3]).encode() der_bin2 = DerSequence([1, 2, DerSequence([3, 4])]).encode() DerSequence().decode(der_bin1, only_ints_expected=True) DerSequence().decode(der_bin1, only_ints_expected=False) DerSequence().decode(der_bin2, only_ints_expected=False) self.assertRaises(ValueError, DerSequence().decode, der_bin2, only_ints_expected=True)
def testDecode8(self): # Only 2 other types der = DerSequence() der.decode(b('0\x06\x24\x02\xb6\x63\x12\x00')) self.assertEquals(len(der), 2) self.assertEquals(der[0], b('\x24\x02\xb6\x63')) self.assertEquals(der[1], b('\x12\x00')) self.assertEquals(der.hasInts(), 0) self.assertEquals(der.hasInts(False), 0) self.failIf(der.hasOnlyInts()) self.failIf(der.hasOnlyInts(False))
def _import_subjectPublicKeyInfo(encoded, passphrase, params): algoid, encoded_key, emb_params = _expand_subject_public_key_info(encoded) if algoid != oid: raise ValueError("No DSA subjectPublicKeyInfo") if params and emb_params: raise ValueError("Too many DSA parameters") y = DerInteger().decode(encoded_key).value p, q, g = list(DerSequence().decode(params or emb_params)) tup = (y, g, p, q) return construct(tup)
def verify(self, msg_hash, signature): """Verify that a certain DSS signature is authentic. This function checks if the party holding the private half of the key really signed the message. :Parameters: msg_hash : hash object The hash that was carried out over the message. This is an object belonging to the `Cryptodome.Hash` module. Under mode *'fips-186-3'*, the hash must be a FIPS approved secure hash (SHA-1 or a member of the SHA-2 family), of cryptographic strength appropriate for the DSA key. For instance, a 3072/256 DSA key can only be used in combination with SHA-512. signature : byte string The signature that needs to be validated. :Raise ValueError: If the signature is not authentic. """ if not self._valid_hash(msg_hash): raise ValueError("Hash does not belong to SHS") if self._encoding == 'binary': if len(signature) != (2 * self._order_bytes): raise ValueError("The signature is not authentic (length)") r_prime, s_prime = [ Integer.from_bytes(x) for x in (signature[:self._order_bytes], signature[self._order_bytes:]) ] else: try: der_seq = DerSequence().decode(signature) except (ValueError, IndexError): raise ValueError("The signature is not authentic (DER)") if len(der_seq) != 2 or not der_seq.hasOnlyInts(): raise ValueError( "The signature is not authentic (DER content)") r_prime, s_prime = der_seq[0], der_seq[1] if not (0 < r_prime < self._order) or not (0 < s_prime < self._order): raise ValueError("The signature is not authentic (d)") z = Integer.from_bytes(msg_hash.digest()[:self._order_bytes]) result = self._key._verify(z, (r_prime, s_prime)) if not result: raise ValueError("The signature is not authentic") # Make PyCryptodome code to fail return False
def test_verify(self): # Ecdsa signature is not unique, so we only test if we can verify it pri_key = ECC.generate(curve="P-256") key = pri_key.export_key(format="DER") pub_key = pri_key.public_key() signer = Sha256WithEcdsaSigner("/K/KEY/x", key) pkt = make_data("/test", MetaInfo(), b"test content", signer=signer) _, _, _, sig_ptrs = parse_data(pkt) # Test its format is ASN.1 der format DerSequence().decode(bytes(sig_ptrs.signature_value_buf)) validator = EccChecker.from_key( "/K/KEY/x", bytes(pub_key.export_key(format='DER'))) assert aio.run(validator(Name.from_str("/test"), sig_ptrs))
def testDecode1(self): # Empty sequence der = DerSequence() der.decode(b('0\x00')) self.assertEquals(len(der), 0) # One single-byte integer (zero) der.decode(b('0\x03\x02\x01\x00')) self.assertEquals(len(der), 1) self.assertEquals(der[0], 0) # Invariant der.decode(b('0\x03\x02\x01\x00')) self.assertEquals(len(der), 1) self.assertEquals(der[0], 0)
def verify(self, msg_hash, signature): """Check if a certain (EC)DSA signature is authentic. :parameter msg_hash: The hash that was carried out over the message. This is an object belonging to the :mod:`Cryptodome.Hash` module. Under mode *'fips-186-3'*, the hash must be a FIPS approved secure hash (SHA-1 or a member of the SHA-2 family), of cryptographic strength appropriate for the DSA key. For instance, a 3072/256 DSA key can only be used in combination with SHA-512. :type msg_hash: hash object :parameter signature: The signature that needs to be validated :type signature: byte string :raise ValueError: if the signature is not authentic """ if not self._valid_hash(msg_hash): raise ValueError("Hash is not sufficiently strong") if self._encoding == 'binary': if len(signature) != (2 * self._order_bytes): raise ValueError("The signature is not authentic (length)") r_prime, s_prime = [ Integer.from_bytes(x) for x in (signature[:self._order_bytes], signature[self._order_bytes:]) ] else: try: der_seq = DerSequence().decode(signature, strict=True) except (ValueError, IndexError): raise ValueError("The signature is not authentic (DER)") if len(der_seq) != 2 or not der_seq.hasOnlyInts(): raise ValueError( "The signature is not authentic (DER content)") r_prime, s_prime = Integer(der_seq[0]), Integer(der_seq[1]) if not (0 < r_prime < self._order) or not (0 < s_prime < self._order): raise ValueError("The signature is not authentic (d)") z = Integer.from_bytes(msg_hash.digest()[:self._order_bytes]) result = self._key._verify(z, (r_prime, s_prime)) if not result: raise ValueError("The signature is not authentic") # Make PyCryptodome code to fail return False
def testEncode2(self): # Indexing der = DerSequence() der.append(0) der[0] = 1 self.assertEquals(len(der), 1) self.assertEquals(der[0], 1) self.assertEquals(der[-1], 1) self.assertEquals(der.encode(), b('0\x03\x02\x01\x01')) # der[:] = [1] self.assertEquals(len(der), 1) self.assertEquals(der[0], 1) self.assertEquals(der.encode(), b('0\x03\x02\x01\x01'))
def testEncode1(self): # Empty sequence der = DerSequence() self.assertEquals(der.encode(), b('0\x00')) self.failIf(der.hasOnlyInts()) # One single-byte integer (zero) der.append(0) self.assertEquals(der.encode(), b('0\x03\x02\x01\x00')) self.assertEquals(der.hasInts(), 1) self.assertEquals(der.hasInts(False), 1) self.failUnless(der.hasOnlyInts()) self.failUnless(der.hasOnlyInts(False)) # Invariant self.assertEquals(der.encode(), b('0\x03\x02\x01\x00'))
def rsa_public_from_der_certificate(certificate): # Extract subject_public_key_info field from X.509 certificate (see RFC3280) try: # try to extract pubkey from scapy.layers.x509 X509Cert type in case # der_certificate is of type X509Cert # Note: der_certificate may not be of type X509Cert if it wasn't # received completely, in that case, we'll try to extract it anyway # using the old method. # TODO: get rid of the old method and always expect X509Cert obj ? return RSA.importKey( str(certificate.tbsCertificate.subjectPublicKeyInfo)) except AttributeError: pass # Fallback method, may pot. allow to extract pubkey from incomplete der streams cert = DerSequence() cert.decode(certificate) tbs_certificate = DerSequence() tbs_certificate.decode(cert[0]) # first DER SEQUENCE # search for pubkey OID: rsaEncryption: "1.2.840.113549.1.1.1" # hex: 06 09 2A 86 48 86 F7 0D 01 01 01 subject_public_key_info = None for seq in tbs_certificate: if not isinstance(seq, bytes) and not isinstance(seq, str): continue # skip numerics and non sequence stuff if b"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01" in seq: subject_public_key_info = seq if subject_public_key_info is None: raise ValueError( "could not find OID rsaEncryption 1.2.840.113549.1.1.1 in certificate" ) # Initialize RSA key return RSA.importKey(subject_public_key_info)