def get_service_id(private_key_file=None, cert=None): ''' service_id is the first half of the sha1 of the rsa public key encoded in base32 ''' if private_key_file: with open(private_key_file, 'rb') as fd: private_key = fd.read() public_key = RSA.importKey(private_key).publickey().exportKey('DER')[22:] # compute sha1 of public key and encode first half in base32 service_id = base64.b32encode(hashlib.sha1(public_key).digest()[:10]).lower().decode() ''' # compute public key from priate key and export in DER format # ignoring the SPKI header(22 bytes) key = load_privatekey(FILETYPE_PEM, private_key) cert = X509() cert.set_pubkey(key) public_key = dump_privatekey(FILETYPE_ASN1, cert.get_pubkey())[22:] # compute sha1 of public key and encode first half in base32 service_id = base64.b32encode(hashlib.sha1(public_key).digest()[:10]).lower().decode() ''' elif cert: # compute sha1 of public key and encode first half in base32 key = load_certificate(FILETYPE_ASN1, cert).get_pubkey() pub_der = DerSequence() pub_der.decode(dump_privatekey(FILETYPE_ASN1, key)) public_key = RSA.construct((pub_der._seq[1], pub_der._seq[2])).exportKey('DER')[22:] service_id = base64.b32encode(hashlib.sha1(public_key).digest()[:10]).lower().decode() return service_id
def testDecode8(self): # Only 2 other types der = DerSequence() der.decode('0\x06\x24\x02\xb6\x63\x12\x00') self.assertEquals(len(der),2) self.assertEquals(der[0],'\x24\x02\xb6\x63') self.assertEquals(der[1],'\x12\x00')
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 testDecode4(self): # One very long integer der = DerSequence() der.decode('0\x82\x01\x05' '\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x00\x00') self.assertEquals(len(der),1) self.assertEquals(der[0],2**2048)
def testDecode6(self): # Two integers der = DerSequence() der.decode('0\x08\x02\x02\x01\x80\x02\x02\x00\xff') self.assertEquals(len(der),2) self.assertEquals(der[0],0x180L) self.assertEquals(der[1],0xFFL)
def testDecode7(self): # One integer and 2 other types der = DerSequence() der.decode('0\x0A\x02\x02\x01\x80\x24\x02\xb6\x63\x12\x00') self.assertEquals(len(der),3) self.assertEquals(der[0],0x180L) self.assertEquals(der[1],'\x24\x02\xb6\x63') self.assertEquals(der[2],'\x12\x00')
def get_service_id(key): ''' service_id is the first half of the sha1 of the rsa public key encoded in base32 ''' # compute sha1 of public key and encode first half in base32 pub_der = DerSequence() pub_der.decode(dump_privatekey(FILETYPE_ASN1, key)) public_key = RSA.construct((pub_der._seq[1], pub_der._seq[2])).exportKey('DER')[22:] service_id = base64.b32encode(hashlib.sha1(public_key).digest()[:10]).lower().decode() return service_id
def exportKey(self, format='PEM'): """Export the RSA key. A string is returned with the encoded public or the private half under the selected format. format: 'DER' (PKCS#1) or 'PEM' (RFC1421) """ der = DerSequence() if self.has_private(): keyType = "RSA PRIVATE" der[:] = [ 0, self.n, self.e, self.d, self.p, self.q, self.d % (self.p-1), self.d % (self.q-1), self.u ] else: keyType = "PUBLIC" der.append(b('\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00')) bitmap = DerObject('BIT STRING') derPK = DerSequence() derPK[:] = [ self.n, self.e ] bitmap.payload = b('\x00') + derPK.encode() der.append(bitmap.encode()) if format=='DER': return der.encode() if format=='PEM': pem = b("-----BEGIN %s KEY-----\n" % keyType) binaryKey = der.encode() # Each BASE64 line can take up to 64 characters (=48 bytes of data) chunks = [ binascii.b2a_base64(binaryKey[i:i+48]) for i in range(0, len(binaryKey), 48) ] pem += b('').join(chunks) pem += b("-----END %s KEY-----" % keyType) return pem return ValueError("")
def exportKey(self, format='PEM', public=False, type=None): """Export the RSA key. A string is returned with the encoded public or the private half under the selected format. format: 'DER' (PKCS#1) or 'PEM' (RFC1421) """ if type == 'ssh-rsa' and public: return ''.join(binascii.b2a_base64('\x00\x00\x00\x07ssh-rsa\x00\x00\x00\x03' + '\x00\x00\x01\x01\x00'.join([long_to_bytes(self.e), long_to_bytes(self.n)])).split("\n")) der = DerSequence() if not public and self.has_private(): keyType = "RSA PRIVATE" der[:] = [ 0, self.n, self.e, self.d, self.p, self.q, self.d % (self.p-1), self.d % (self.q-1), self.u ] else: keyType = "PUBLIC" der.append('\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00') bitmap = DerObject('BIT STRING') derPK = DerSequence() derPK[:] = [ self.n, self.e ] bitmap.payload = '\x00' + derPK.encode() der.append(bitmap.encode()) if format=='DER': return der.encode() if format=='PEM': pem = "-----BEGIN %s KEY-----\n" % keyType binaryKey = der.encode() # Each BASE64 line can take up to 64 characters (=48 bytes of data) chunks = [ binascii.b2a_base64(binaryKey[i:i+48]) for i in range(0, len(binaryKey), 48) ] pem += ''.join(chunks) pem += "-----END %s KEY-----" % keyType return pem return ValueError("")
def _importKeyDER(self, externKey): der = DerSequence() der.decode(externKey, True) if len(der)==9 and der.hasOnlyInts() and der[0]==0: # ASN.1 RSAPrivateKey element del der[6:] # Remove d mod (p-1), d mod (q-1), and q^{-1} mod p der.append(inverse(der[4],der[5])) # Add p^{-1} mod q del der[0] # Remove version return self.construct(der[:]) if len(der)==2: # The DER object is a SEQUENCE with two elements: # a SubjectPublicKeyInfo SEQUENCE and an opaque BIT STRING. # # The first element is always the same: # 0x30 0x0D SEQUENCE, 12 bytes of payload # 0x06 0x09 OBJECT IDENTIFIER, 9 bytes of payload # 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x01 0x01 # rsaEncryption (1 2 840 113549 1 1 1) (PKCS #1) # 0x05 0x00 NULL # # The second encapsulates the actual ASN.1 RSAPublicKey element. if der[0]==b('\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00'): bitmap = DerObject() bitmap.decode(der[1], True) if bitmap.typeTag==b('\x03')[0] and bitmap.payload[0]==b('\x00')[0]: der.decode(bitmap.payload[1:], True) if len(der)==2 and der.hasOnlyInts(): return self.construct(der[:]) raise ValueError("RSA key format is not supported")
def get_pubkey_ssh2_fingerprint(pubkey): # This is the format that EC2 shows for public key fingerprints in its # KeyPair mgmt API if not pycrypto_available: raise RuntimeError('pycrypto is not available') k = importKey(pubkey) derPK = DerSequence([k.n, k.e]) bitmap = DerObject('BIT STRING') bitmap.payload = bchr(0x00) + derPK.encode() der = DerSequence([algorithmIdentifier, bitmap.encode()]) return _to_md5_fingerprint(der.encode())
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 `Crypto.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). signature : byte string The signature that needs to be validated. :Raise ValueError: If the signature is not authentic. """ if not self._deterministic: if self._n > msg_hash.digest_size * 8: raise ValueError("Hash is not long enough") if not hash_is_shs(msg_hash): raise ValueError("Hash does not belong to SHS") if self._encoding == 'binary': if len(signature) != (2 * self._n): raise ValueError("The signature is not authentic") r_prime, s_prime = [bytes_to_long(x) for x in (signature[:self._n], signature[self._n:])] else: try: der_seq = DerSequence() der_seq.decode(signature) except (ValueError, IndexError): raise ValueError("The signature is not authentic") if len(der_seq) != 2 or not der_seq.hasOnlyInts(): raise ValueError("The signature is not authentic") r_prime, s_prime = der_seq[0], der_seq[1] if not (0 < r_prime < self._key.q) or not (0 < s_prime < self._key.q): raise ValueError("The signature is not authentic") z = bytes_to_long(msg_hash.digest()[:self._n]) result = self._key._verify(z, (r_prime, s_prime)) if not result: raise ValueError("The signature is not authentic") # Make PyCrypto code to fail return False
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 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 `Crypto.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 PyCrypto code to fail return False
def exportKey(self, format="PEM"): """Export the RSA key. A string is returned with the encoded public or the private half under the selected format. format: 'DER' (PKCS#1) or 'PEM' (RFC1421) """ der = DerSequence() if self.has_private(): keyType = "RSA PRIVATE" der[:] = [0, self.n, self.e, self.d, self.p, self.q, self.d % (self.p - 1), self.d % (self.q - 1), self.u] else: keyType = "PUBLIC" der.append("\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00") bitmap = DerObject("BIT STRING") derPK = DerSequence() derPK[:] = [self.n, self.e] bitmap.payload = "\x00" + derPK.encode() der.append(bitmap.encode()) if format == "DER": return der.encode() if format == "PEM": pem = "-----BEGIN %s KEY-----\n" % keyType binaryKey = der.encode() # Each BASE64 line can take up to 64 characters (=48 bytes of data) chunks = [] for i in range(0, len(binaryKey), 48): chunks.append(binascii.b2a_base64(binaryKey[i : i + 48])) pem += "".join(chunks) pem += "-----END %s KEY-----" % keyType return pem if format == "SSH": # Create public key. ssh_rsa = "00000007" + base64.b16encode("ssh-rsa") # Exponent. exponent = "%x" % (self.key.e,) if len(exponent) % 2: exponent = "0" + exponent ssh_rsa += "%08x" % (len(exponent) / 2,) ssh_rsa += exponent modulus = "%x" % (self.key.n,) if len(modulus) % 2: modulus = "0" + modulus if modulus[0] in "89abcdef": modulus = "00" + modulus ssh_rsa += "%08x" % (len(modulus) / 2,) ssh_rsa += modulus return "ssh-rsa %s" % (base64.b64encode(base64.b16decode(ssh_rsa.upper())),) return ValueError("")
def testEncode6(self): # Two integers der = DerSequence() der.append(0x180L) der.append(0xFFL) self.assertEquals(der.encode(), '0\x08\x02\x02\x01\x80\x02\x02\x00\xff') self.failUnless(der.hasOnlyInts()) # der.append(0x01) der[1:] = [9,8] self.assertEquals(len(der),3) self.assertEqual(der[1:],[9,8]) self.assertEqual(der[1:-1],[9]) self.assertEquals(der.encode(), '0\x0A\x02\x02\x01\x80\x02\x01\x09\x02\x01\x08')
def testEncode2(self): # Indexing der = DerSequence() der.append(0) der[0] = 1 self.assertEqual(len(der),1) self.assertEqual(der[0],1) self.assertEqual(der[-1],1) self.assertEqual(der.encode(), b('0\x03\x02\x01\x01')) # der[:] = [1] self.assertEqual(len(der),1) self.assertEqual(der[0],1) self.assertEqual(der.encode(), b('0\x03\x02\x01\x01'))
def sign(self, msg_hash): """Produce the DSS signature of a message. :Parameters: msg_hash : hash object The hash that was carried out over the message. The object belongs to the `Crypto.Hash` package. Under mode *'fips-186-3'*, the hash must be a FIPS approved secure hash (SHA-1 or a member of the SHA-2 family). :Return: The signature encoded as a byte string. :Raise ValueError: If the hash algorithm is incompatible to the DSA key. :Raise TypeError: If the DSA key has no private half. """ # Generate the nonce k (critical!) if self._deterministic: nonce = self._compute_nonce(msg_hash) else: if self._n > msg_hash.digest_size * 8: raise ValueError("Hash is not long enough") if not hash_is_shs(msg_hash): raise ValueError("Hash does not belong to SHS") rng = StrongRandom(randfunc=self._randfunc) nonce = rng.randint(1, self._key.q - 1) # Perform signature using the raw API z = bytes_to_long(msg_hash.digest()[:self._n]) sig_pair = self._key._sign(z, nonce) # Encode the signature into a single byte string if self._encoding == 'binary': output = b("").join([long_to_bytes(x, self._n) for x in sig_pair]) else: # Dss-sig ::= SEQUENCE { # r OCTET STRING, # s OCTET STRING # } der_seq = DerSequence(sig_pair) output = der_seq.encode() return output
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:`Crypto.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 PyCrypto code to fail return False
def testEncode7(self): # One integer and another type (no matter what it is) der = DerSequence() der.append(0x180) der.append(b('\x00\x02\x00\x00')) self.assertEqual(der.encode(), b('0\x08\x02\x02\x01\x80\x00\x02\x00\x00')) self.assertFalse(der.hasOnlyInts())
def _importKeyDER(extern_key, passphrase, verify_x509_cert): """Import an RSA key (public or private half), encoded in DER form.""" try: der = DerSequence().decode(extern_key) # Try PKCS#1 first, for a private key if len(der) == 9 and der.hasOnlyInts() and der[0] == 0: # ASN.1 RSAPrivateKey element del der[6:] # Remove d mod (p-1), # d mod (q-1), and # q^{-1} mod p der.append(Integer(der[4]).inverse(der[5])) # Add p^{-1} mod q del der[0] # Remove version return construct(der[:]) # Keep on trying PKCS#1, but now for a public key if len(der) == 2: try: # The DER object is an RSAPublicKey SEQUENCE with # two elements if der.hasOnlyInts(): return construct(der[:]) # The DER object is a SubjectPublicKeyInfo SEQUENCE # with two elements: an 'algorithmIdentifier' and a # 'subjectPublicKey'BIT STRING. # 'algorithmIdentifier' takes the value given at the # module level. # 'subjectPublicKey' encapsulates the actual ASN.1 # RSAPublicKey element. if der[0] == algorithmIdentifier: bitmap = DerBitString().decode(der[1]) rsaPub = DerSequence().decode(bitmap.value) if len(rsaPub) == 2 and rsaPub.hasOnlyInts(): return construct(rsaPub[:]) except (ValueError, EOFError): pass # Try to see if this is an X.509 DER certificate # (Certificate ASN.1 type) if len(der) == 3: from Crypto.PublicKey import _extract_sp_info try: sp_info = _extract_sp_info(der) if verify_x509_cert: raise NotImplementedError("X.509 certificate validation is not supported") return _importKeyDER(sp_info, passphrase, False) except ValueError: pass # Try PKCS#8 (possibly encrypted) k = PKCS8.unwrap(extern_key, passphrase) if k[0] == oid: return _importKeyDER(k[1], passphrase, False) except (ValueError, EOFError): pass raise ValueError("RSA key format is not supported")
def testEncode8(self): # One integer and another type (yet to encode) der = DerSequence() der.append(0x180) der.append(DerSequence([5])) self.assertEqual(der.encode(), b('0\x09\x02\x02\x01\x800\x03\x02\x01\x05')) self.assertFalse(der.hasOnlyInts())
def testEncode7(self): # One integer and another type (already encoded) der = DerSequence() der.append(0x180) der.append(b('0\x03\x02\x01\x05')) self.assertEqual(der.encode(), b('0\x09\x02\x02\x01\x800\x03\x02\x01\x05')) self.assertFalse(der.hasOnlyInts())
def _extract_sp_info(x509_certificate): """Extract subjectPublicKeyInfo from a DER X.509 certificate.""" from Crypto.Util.asn1 import DerSequence, DerInteger try: # This code will partially parse tbsCertificate # to get to subjectPublicKeyInfo. # # However, the first 2 elements of tbsCertificate are: # # version [0] Version DEFAULT v1, # serialNumber CertificateSerialNumber, # # where: # # Version ::= INTEGER { v1(0), v2(1), v3(2) } # CertificateSerialNumber ::= INTEGER # # In order to know the position of subjectPublicKeyInfo # in the tbsCertificate SEQUENCE, we try to see if the # first element is an untagged INTEGER (that is, the # certificate serial number). x509_tbs_cert = DerSequence() x509_tbs_cert.decode(x509_certificate[0]) index = -1 # Sentinel try: _ = x509_tbs_cert[0] + 1 # Still here? There was no version then index = 5 except TypeError: # Landed here? Version was there x509_version = DerInteger(explicit=0) x509_version.decode(x509_tbs_cert[0]) index = 6 if index in (5, 6): return x509_tbs_cert[index] except (TypeError, IndexError, ValueError, EOFError): pass raise ValueError("Cannot extract subjectPublicKeyInfo")
def testEncode6(self): # One integer and another type (no matter what it is) der = DerSequence() der.append(0x180L) der.append('\x00\x02\x00\x00') self.assertEquals(der.encode(), '0\x08\x02\x02\x01\x80\x00\x02\x00\x00') self.failIf(der.hasOnlyInts())
def testEncode1(self): # Empty sequence der = DerSequence() self.assertEqual(der.encode(), b('0\x00')) self.assertFalse(der.hasOnlyInts()) # One single-byte integer (zero) der.append(0) self.assertEqual(der.encode(), b('0\x03\x02\x01\x00')) self.assertTrue(der.hasOnlyInts()) # Invariant self.assertEqual(der.encode(), b('0\x03\x02\x01\x00'))
def testEncode1(self): # Empty sequence der = DerSequence() self.assertEquals(der.encode(), '0\x00') self.failIf(der.hasOnlyInts()) # One single-byte integer (zero) der.append(0) self.assertEquals(der.encode(), '0\x03\x02\x01\x00') self.failUnless(der.hasOnlyInts()) # Invariant self.assertEquals(der.encode(), '0\x03\x02\x01\x00')
def get_cert_moduli(self, derCert): # convert PEM to DER pem = derCert.decode() lines = pem.replace(" ",'').split() der = binascii.a2b_base64(''.join(lines[1:-1])) # get Subject Public Key cert = DerSequence() b = cert.decode(der) tbsCertificate = DerSequence() tbsCertificate.decode(cert[0]) try: subjectPublicKeyInfo = tbsCertificate[6] except IndexError: return "unkown", "unkown" rsa_key = RSA.importKey(subjectPublicKeyInfo) # rsa_key.n = modulus, rsa_key.e = public exponent # increment size with 1 as the Python counts from 0 (duh) return (hex(rsa_key.n), rsa_key.key.size() + 1)
def get_spki(self): """Get the Subject PublicKey info, DER encoded.""" der = DerSequence() der.decode(self.DER) cert = DerSequence() cert.decode(der[0]) return cert[6]
def forge(certificate_path: str, key_pem: str): """ given a valid certificate_path and key_pem create a forged key """ public_key_point = get_public_key(certificate_path) Q = Point(int(public_key_point[0:96], 16), int(public_key_point[96:], 16), curve=P384) # Generate rogue generator privkey_inv = 2 # we take the private key as being the inverse of 2 modulo the curve order private_key = gmpy2.invert(privkey_inv, P384.q) # pylint: disable=c-extension-no-member private_key = unhexlify(f"{private_key:x}".encode()) # we multply our public key Q with the inverse of our chosen private key value roug_g = privkey_inv * Q roug_g = unhexlify(b"04" + f"{roug_g.x:x}".encode() + f"{roug_g.y:x}".encode()) # Generate the file with explicit parameters with open(key_pem, mode="rt") as handle: keyfile = PEM.decode(handle.read()) seq_der = DerSequence() der = seq_der.decode(keyfile[0]) # Replace private key octet_der = DerOctetString(private_key) der[1] = octet_der.encode() # Replace public key bits_der = DerBitString(unhexlify(b"04" + public_key_point)) der[3] = b"\xa1\x64" + bits_der.encode() # Replace the generator seq_der = DerSequence() s = seq_der.decode(der[2][4:]) # pylint: disable=invalid-name octet_der = DerOctetString(roug_g) s[3] = octet_der.encode() der[2] = der[2][:4] + s.encode() return PEM.encode(der.encode(), "EC PRIVATE KEY")
def CRYPTO_EMSA_PKCS1_V1_5_ENCODE(M, emLen): msg_hash = SHA256.new(M) digestAlgo = DerSequence([DerObjectId(msg_hash.oid).encode()]) print(digestAlgo) digestAlgo.append(DerNull().encode()) digest = DerOctetString(msg_hash.digest()) digestInfo = DerSequence([digestAlgo.encode(), digest.encode()]).encode() print("%x" % int.from_bytes(digestInfo, byteorder='big')) print("%x" % int.from_bytes(digestAlgo.encode(), byteorder='big')) print("%x" % int.from_bytes(digest.encode(), byteorder='big')) print("%x" % int.from_bytes(msg_hash.digest(), byteorder='big')) #b91d0b7a09f57c109926a449647283adb5dc213c0fdb0cf2b219e064cc132273 2004 00 0501020403650148866009060d30 3130 # 501020403650148866009060d30 #b91d0b7a09f57c109926a449647283adb5dc213c0fdb0cf2b219e064cc132273 2004 #b91d0b7a09f57c109926a449647283adb5dc213c0fdb0cf2b219e064cc132273 #b91d0b7a09f57c109926a449647283adb5dc213c0fdb0cf2b219e064cc1322732004000501020403650148866009060d30313000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0100 #3031 300d06096086480165030402010500 0420 732213cc64e019b2f20cdb0f3c21dcb5ad83726449a42699107cf5097a0b1db9 # 300d06096086480165030402010500 # 0420 732213cc64e019b2f20cdb0f3c21dcb5ad83726449a42699107cf5097a0b1db9 # 732213cc64e019b2f20cdb0f3c21dcb5ad83726449a42699107cf5097a0b1db9 #0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420732213cc64e019b2f20cdb0f3c21dcb5ad83726449a42699107cf5097a0b1db9 # We need at least 11 bytes for the remaining data: 3 fixed bytes and # at least 8 bytes of padding). if emLen < len(digestInfo) + 11: raise TypeError( "Selected hash algorith has a too long digest (%d bytes)." % len(digest)) PS = b'\xFF' * (emLen - len(digestInfo) - 3) out = b'\x00\x01' + PS + b'\x00' + digestInfo print("%x" % int.from_bytes(out, byteorder='big')) return out
def generatePublicKey(cert_file): osw = OpenSSLWrapper() cert_str = osw.read_str_from_file(cert_file) cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_str) pub_key = cert.get_pubkey() src = crypto.dump_privatekey(crypto.FILETYPE_ASN1, pub_key) pub_der = DerSequence() pub_der.decode(src) pub_key_rsa = RSA.construct((long(pub_der._seq[1]), long(pub_der._seq[2]))) pemSeq = DerSequence() pemSeq[:] = [pub_key_rsa.key.n, pub_key_rsa.key.e] s = pub_key_str = b64encode(pemSeq.encode()) pem_src = '-----BEGIN RSA PUBLIC KEY-----\n' while True: pem_src += s[:64] + '\n' s = s[64:] if s == '': break pem_src += '-----END RSA PUBLIC KEY-----' jwks = { "keys": [{ "use": "enc", "e": "AQAB", "kty": "RSA", "n": pub_key_str }, { "use": "sig", "e": "AQAB", "kty": "RSA", "n": pub_key_str }] } jwks_str = json.dumps(jwks) osw.write_str_to_file("./static/jwks.json", jwks_str)
def pkcs1_v1_5_encode(msg_hash: SHA256.SHA256Hash, emLen: int) -> bytes: # this code is copied from EMSA_PKCS1_V1_5_ENCODE # https://github.com/dlitz/pycrypto/blob/v2.7a1/lib/Crypto/Signature/PKCS1_v1_5.py#L173 digestAlgo = DerSequence([ DerObjectId(msg_hash.oid).encode() ]) #if with_hash_parameters: if True: digestAlgo.append(DerNull().encode()) digest = DerOctetString(msg_hash.digest()) digestInfo = DerSequence([ digestAlgo.encode(), digest.encode() ]).encode() # We need at least 11 bytes for the remaining data: 3 fixed bytes and # at least 8 bytes of padding). if emLen<len(digestInfo)+11: raise TypeError("Selected hash algorith has a too long digest (%d bytes)." % len(digest)) PS = b'\xFF' * (emLen - len(digestInfo) - 3) return b'\x00\x01' + PS + b'\x00' + digestInfo
def testInit1(self): der = DerSequence([1, DerInteger(2), b('0\x00')]) self.assertEquals(der.encode(), b('0\x08\x02\x01\x01\x02\x01\x020\x00'))
def testEncode5(self): # One single-byte integer (looks negative) der = DerSequence() der.append(0xFFL) self.assertEquals(der.encode(), '0\x04\x02\x02\x00\xff')
def testEncode3(self): # One multi-byte integer (non-zero) der = DerSequence() der.append(0x180L) self.assertEquals(der.encode(), '0\x04\x02\x02\x01\x80')
except ValueError: error_str = "PBES1[Invalid]" if not found: try: p8_private_key = PBES2.decrypt(p8_private_key, passphrase) found = True except PbesError, e: error_str += ",PBES2[%s]" % str(e) except ValueError: error_str += ",PBES2[Invalid]" if not found: raise ValueError("Error decoding PKCS#8 (%s)" % error_str) pk_info = DerSequence().decode(p8_private_key, nr_elements=(2, 3, 4)) if len(pk_info) == 2 and not passphrase: raise ValueError("Not a valid clear PKCS#8 structure " "(maybe it is encrypted?)") # # PrivateKeyInfo ::= SEQUENCE { # version Version, # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, # privateKey PrivateKey, # attributes [0] IMPLICIT Attributes OPTIONAL # } # Version ::= INTEGER if pk_info[0] != 0: raise ValueError("Not a valid PrivateKeyInfo SEQUENCE")
def testEncode6(self): # Two positive integers der = DerSequence() der.append(0x180L) der.append(0xFFL) self.assertEquals(der.encode(), b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff')) self.failUnless(der.hasOnlyInts()) self.failUnless(der.hasOnlyInts(False)) # Two mixed integers der = DerSequence() der.append(2) der.append(-2) self.assertEquals(der.encode(), b('0\x06\x02\x01\x02\x02\x01\xFE')) self.assertEquals(der.hasInts(), 1) self.assertEquals(der.hasInts(False), 2) self.failIf(der.hasOnlyInts()) self.failUnless(der.hasOnlyInts(False)) # der.append(0x01) der[1:] = [9, 8] self.assertEquals(len(der), 3) self.assertEqual(der[1:], [9, 8]) self.assertEqual(der[1:-1], [9]) self.assertEquals(der.encode(), b('0\x09\x02\x01\x02\x02\x01\x09\x02\x01\x08'))
def testDecode5(self): # One single-byte integer (looks negative) der = DerSequence() der.decode('0\x04\x02\x02\x00\xff') self.assertEquals(len(der),1) self.assertEquals(der[0],0xFFL)
def testDecode3(self): # One multi-byte integer (non-zero) der = DerSequence() der.decode('0\x04\x02\x02\x01\x80') self.assertEquals(len(der),1) self.assertEquals(der[0],0x180L)
def dump_signature(data): if data[0:2] == b'\x30\x82': slen = struct.unpack('>H', data[2:4])[0] total = slen + 4 cert = struct.unpack('<%ds' % total, data[0:total])[0] der = DerSequence() der.decode(cert) cert0 = DerSequence() cert0.decode(bytes(der[1])) pk = DerSequence() pk.decode(bytes(cert0[0])) subjectPublicKeyInfo = pk[6] meta = DerSequence() meta.decode(der[3]) print(der[3]) name = meta[0][2:] length = meta[1] signature = bytes(der[4])[4:0x104] pub_key = RSA.importKey(subjectPublicKeyInfo) hash=extract_hash(pub_key,signature) return [name,length,hash,pub_key,bytes(der[3])[1:2]]
def encrypt(data, passphrase, protection, prot_params=None, randfunc=None): """Encrypt a piece of data using a passphrase and *PBES2*. :Parameters: data : byte string The piece of data to encrypt. passphrase : byte string The passphrase to use for encrypting the data. protection : string The identifier of the encryption algorithm to use. The default value is '``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``'. prot_params : dictionary Parameters of the protection algorithm. +------------------+-----------------------------------------------+ | Key | Description | +==================+===============================================+ | iteration_count | The KDF algorithm is repeated several times to| | | slow down brute force attacks on passwords | | | (called *N* or CPU/memory cost in scrypt). | | | | | | The default value for PBKDF2 is 1 000. | | | The default value for scrypt is 16 384. | +------------------+-----------------------------------------------+ | salt_size | Salt is used to thwart dictionary and rainbow | | | attacks on passwords. The default value is 8 | | | bytes. | +------------------+-----------------------------------------------+ | block_size | *(scrypt only)* Memory-cost (r). The default | | | value is 8. | +------------------+-----------------------------------------------+ | parallelization | *(scrypt only)* CPU-cost (p). The default | | | value is 1. | +------------------+-----------------------------------------------+ randfunc : callable Random number generation function; it should accept a single integer N and return a string of random data, N bytes long. If not specified, a new RNG will be instantiated from ``Crypto.Random``. :Returns: The encrypted data, as a binary string. """ if prot_params is None: prot_params = {} if randfunc is None: randfunc = Random.new().read if protection == 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC': key_size = 24 module = DES3 cipher_mode = DES3.MODE_CBC enc_oid = _OID_DES_EDE3_CBC elif protection in ('PBKDF2WithHMAC-SHA1AndAES128-CBC', 'scryptAndAES128-CBC'): key_size = 16 module = AES cipher_mode = AES.MODE_CBC enc_oid = _OID_AES128_CBC elif protection in ('PBKDF2WithHMAC-SHA1AndAES192-CBC', 'scryptAndAES192-CBC'): key_size = 24 module = AES cipher_mode = AES.MODE_CBC enc_oid = _OID_AES192_CBC elif protection in ('PBKDF2WithHMAC-SHA1AndAES256-CBC', 'scryptAndAES256-CBC'): key_size = 32 module = AES cipher_mode = AES.MODE_CBC enc_oid = _OID_AES256_CBC else: raise ValueError("Unknown PBES2 mode") # Get random data iv = randfunc(module.block_size) salt = randfunc(prot_params.get("salt_size", 8)) # Derive key from password if protection.startswith('PBKDF2'): count = prot_params.get("iteration_count", 1000) key = PBKDF2(passphrase, salt, key_size, count) kdf_info = DerSequence([ DerObjectId(_OID_PBKDF2), # PBKDF2 DerSequence([DerOctetString(salt), DerInteger(count)]) ]) else: # It must be scrypt count = prot_params.get("iteration_count", 16384) scrypt_r = prot_params.get('block_size', 8) scrypt_p = prot_params.get('parallelization', 1) key = scrypt(passphrase, salt, key_size, count, scrypt_r, scrypt_p) kdf_info = DerSequence([ DerObjectId(_OID_SCRYPT), # scrypt DerSequence([ DerOctetString(salt), DerInteger(count), DerInteger(scrypt_r), DerInteger(scrypt_p) ]) ]) # Create cipher and use it cipher = module.new(key, cipher_mode, iv) encrypted_data = cipher.encrypt(pad(data, cipher.block_size)) enc_info = DerSequence([DerObjectId(enc_oid), DerOctetString(iv)]) # Result enc_private_key_info = DerSequence([ # encryptionAlgorithm DerSequence([ DerObjectId(_OID_PBES2), DerSequence([kdf_info, enc_info]), ]), DerOctetString(encrypted_data) ]) return enc_private_key_info.encode()
def exportKey(self, format='PEM', passphrase=None, pkcs=1, protection=None, randfunc=None): """Export this RSA key. Args: format (string): The format to use for wrapping the key: - *'PEM'*. (*Default*) Text encoding, done according to `RFC1421`_/`RFC1423`_. - *'DER'*. Binary encoding. - *'OpenSSH'*. Textual encoding, done according to OpenSSH specification. Only suitable for public keys (not private keys). passphrase (string): (*For private keys only*) The pass phrase used for protecting the output. pkcs (integer): (*For private keys only*) The ASN.1 structure to use for serializing the key. Note that even in case of PEM encoding, there is an inner ASN.1 DER structure. With ``pkcs=1`` (*default*), the private key is encoded in a simple `PKCS#1`_ structure (``RSAPrivateKey``). With ``pkcs=8``, the private key is encoded in a `PKCS#8`_ structure (``PrivateKeyInfo``). .. note:: This parameter is ignored for a public key. For DER and PEM, an ASN.1 DER ``SubjectPublicKeyInfo`` structure is always used. protection (string): (*For private keys only*) The encryption scheme to use for protecting the private key. If ``None`` (default), the behavior depends on :attr:`format`: - For *'DER'*, the *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC* scheme is used. The following operations are performed: 1. A 16 byte Triple DES key is derived from the passphrase using :func:`Crypto.Protocol.KDF.PBKDF2` with 8 bytes salt, and 1 000 iterations of :mod:`Crypto.Hash.HMAC`. 2. The private key is encrypted using CBC. 3. The encrypted key is encoded according to PKCS#8. - For *'PEM'*, the obsolete PEM encryption scheme is used. It is based on MD5 for key derivation, and Triple DES for encryption. Specifying a value for :attr:`protection` is only meaningful for PKCS#8 (that is, ``pkcs=8``) and only if a pass phrase is present too. The supported schemes for PKCS#8 are listed in the :mod:`Crypto.IO.PKCS8` module (see :attr:`wrap_algo` parameter). randfunc (callable): A function that provides random bytes. Only used for PEM encoding. The default is :func:`Crypto.Random.get_random_bytes`. Returns: byte string: the encoded key Raises: ValueError:when the format is unknown or when you try to encrypt a private key with *DER* format and PKCS#1. .. warning:: If you don't provide a pass phrase, the private key will be exported in the clear! .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt .. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt """ if passphrase is not None: passphrase = tobytes(passphrase) if randfunc is None: randfunc = Random.get_random_bytes if format == 'OpenSSH': e_bytes, n_bytes = [x.to_bytes() for x in (self._e, self._n)] if bord(e_bytes[0]) & 0x80: e_bytes = bchr(0) + e_bytes if bord(n_bytes[0]) & 0x80: n_bytes = bchr(0) + n_bytes keyparts = [b('ssh-rsa'), e_bytes, n_bytes] keystring = b('').join( [struct.pack(">I", len(kp)) + kp for kp in keyparts]) return b('ssh-rsa ') + binascii.b2a_base64(keystring)[:-1] # DER format is always used, even in case of PEM, which simply # encodes it into BASE64. if self.has_private(): binary_key = DerSequence([ 0, self.n, self.e, self.d, self.p, self.q, self.d % (self.p - 1), self.d % (self.q - 1), Integer(self.q).inverse(self.p) ]).encode() if pkcs == 1: key_type = 'RSA PRIVATE KEY' if format == 'DER' and passphrase: raise ValueError("PKCS#1 private key cannot be encrypted") else: # PKCS#8 if format == 'PEM' and protection is None: key_type = 'PRIVATE KEY' binary_key = PKCS8.wrap(binary_key, oid, None) else: key_type = 'ENCRYPTED PRIVATE KEY' if not protection: protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' binary_key = PKCS8.wrap(binary_key, oid, passphrase, protection) passphrase = None else: key_type = "PUBLIC KEY" binary_key = _create_subject_public_key_info( oid, DerSequence([self.n, self.e])) if format == 'DER': return binary_key if format == 'PEM': pem_str = PEM.encode(binary_key, key_type, passphrase, randfunc) return tobytes(pem_str) raise ValueError( "Unknown key format '%s'. Cannot export the RSA key." % format)
def exportKey(self, format='PEM', pkcs8=None, passphrase=None, protection=None, randfunc=None): """Export this DSA key. Args: format (string): The encoding for the output: - *'PEM'* (default). ASCII as per `RFC1421`_/ `RFC1423`_. - *'DER'*. Binary ASN.1 encoding. - *'OpenSSH'*. ASCII one-liner as per `RFC4253`_. Only suitable for public keys, not for private keys. passphrase (string): *Private keys only*. The pass phrase to protect the output. pkcs8 (boolean): *Private keys only*. If ``True`` (default), the key is encoded with `PKCS#8`_. If ``False``, it is encoded in the custom OpenSSL/OpenSSH container. protection (string): *Only in combination with a pass phrase*. The encryption scheme to use to protect the output. If :data:`pkcs8` takes value ``True``, this is the PKCS#8 algorithm to use for deriving the secret and encrypting the private DSA key. For a complete list of algorithms, see :mod:`Crypto.IO.PKCS8`. The default is *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC*. If :data:`pkcs8` is ``False``, the obsolete PEM encryption scheme is used. It is based on MD5 for key derivation, and Triple DES for encryption. Parameter :data:`protection` is then ignored. The combination ``format='DER'`` and ``pkcs8=False`` is not allowed if a passphrase is present. randfunc (callable): A function that returns random bytes. By default it is :func:`Crypto.Random.get_random_bytes`. Returns: byte string : the encoded key Raises: ValueError : when the format is unknown or when you try to encrypt a private key with *DER* format and OpenSSL/OpenSSH. .. warning:: If you don't provide a pass phrase, the private key will be exported in the clear! .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt .. _RFC4253: http://www.ietf.org/rfc/rfc4253.txt .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt """ if passphrase is not None: passphrase = tobytes(passphrase) if randfunc is None: randfunc = Random.get_random_bytes if format == 'OpenSSH': tup1 = [self._key[x].to_bytes() for x in ('p', 'q', 'g', 'y')] def func(x): if (bord(x[0]) & 0x80): return bchr(0) + x else: return x tup2 = list(map(func, tup1)) keyparts = [b('ssh-dss')] + tup2 keystring = b('').join( [struct.pack(">I", len(kp)) + kp for kp in keyparts]) return b('ssh-dss ') + binascii.b2a_base64(keystring)[:-1] # DER format is always used, even in case of PEM, which simply # encodes it into BASE64. params = DerSequence([self.p, self.q, self.g]) if self.has_private(): if pkcs8 is None: pkcs8 = True if pkcs8: if not protection: protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' private_key = DerInteger(self.x).encode() binary_key = PKCS8.wrap(private_key, oid, passphrase, protection, key_params=params, randfunc=randfunc) if passphrase: key_type = 'ENCRYPTED PRIVATE' else: key_type = 'PRIVATE' passphrase = None else: if format != 'PEM' and passphrase: raise ValueError("DSA private key cannot be encrypted") ints = [0, self.p, self.q, self.g, self.y, self.x] binary_key = DerSequence(ints).encode() key_type = "DSA PRIVATE" else: if pkcs8: raise ValueError("PKCS#8 is only meaningful for private keys") binary_key = _create_subject_public_key_info( oid, DerInteger(self.y), params) key_type = "PUBLIC" if format == 'DER': return binary_key if format == 'PEM': pem_str = PEM.encode(binary_key, key_type + " KEY", passphrase, randfunc) return tobytes(pem_str) raise ValueError( "Unknown key format '%s'. Cannot export the DSA key." % format)
def testErrDecode2(self): der = DerSequence() # Too much data self.assertRaises(ValueError, der.decode, b('\x30\x00\x00'))
def testDecode9(self): # Verify that decode returns itself der = DerSequence() self.assertEqual(der, der.decode(b('0\x06\x24\x02\xb6\x63\x12\x00')))
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 testDecode2(self): # One single-byte integer (non-zero) der = DerSequence() der.decode('0\x03\x02\x01\x7f') self.assertEquals(len(der),1) self.assertEquals(der[0],127)
def testErrDecode1(self): # Not a sequence der = DerSequence() self.assertRaises(ValueError, der.decode, '') self.assertRaises(ValueError, der.decode, '\x00') self.assertRaises(ValueError, der.decode, '\x30')
def decrypt(data, passphrase): """Decrypt a piece of data using a passphrase and *PBES2*. 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, nr_elements=2) enc_algo = DerSequence().decode(enc_private_key_info[0]) encrypted_data = DerOctetString().decode( enc_private_key_info[1]).payload pbe_oid = DerObjectId().decode(enc_algo[0]).value if pbe_oid != _OID_PBES2: raise PbesError("Not a PBES2 object") pbes2_params = DerSequence().decode(enc_algo[1], nr_elements=2) ### Key Derivation Function selection kdf_info = DerSequence().decode(pbes2_params[0], nr_elements=2) kdf_oid = DerObjectId().decode(kdf_info[0]).value kdf_key_length = None # We only support PBKDF2 or scrypt if kdf_oid == _OID_PBKDF2: pbkdf2_params = DerSequence().decode(kdf_info[1], nr_elements=(2, 3, 4)) salt = DerOctetString().decode(pbkdf2_params[0]).payload iteration_count = pbkdf2_params[1] left = len(pbkdf2_params) - 2 idx = 2 if left > 0: try: kdf_key_length = pbkdf2_params[idx] - 0 left -= 1 idx += 1 except TypeError: pass # Default is HMAC-SHA1 pbkdf2_prf_oid = "1.2.840.113549.2.7" if left > 0: pbkdf2_prf_algo_id = DerSequence().decode(pbkdf2_params[idx]) pbkdf2_prf_oid = DerObjectId().decode( pbkdf2_prf_algo_id[0]).value elif kdf_oid == _OID_SCRYPT: scrypt_params = DerSequence().decode(kdf_info[1], nr_elements=(4, 5)) salt = DerOctetString().decode(scrypt_params[0]).payload iteration_count, scrypt_r, scrypt_p = [ scrypt_params[x] for x in (1, 2, 3) ] if len(scrypt_params) > 4: kdf_key_length = scrypt_params[4] else: kdf_key_length = None else: raise PbesError("Unsupported PBES2 KDF") ### Cipher selection enc_info = DerSequence().decode(pbes2_params[1]) enc_oid = DerObjectId().decode(enc_info[0]).value if enc_oid == _OID_DES_EDE3_CBC: # DES_EDE3_CBC ciphermod = DES3 key_size = 24 elif enc_oid == _OID_AES128_CBC: # AES128_CBC ciphermod = AES key_size = 16 elif enc_oid == _OID_AES192_CBC: # AES192_CBC ciphermod = AES key_size = 24 elif enc_oid == _OID_AES256_CBC: # AES256_CBC ciphermod = AES key_size = 32 else: raise PbesError("Unsupported PBES2 cipher") if kdf_key_length and kdf_key_length != key_size: raise PbesError("Mismatch between PBES2 KDF parameters" " and selected cipher") IV = DerOctetString().decode(enc_info[1]).payload # Create cipher if kdf_oid == _OID_PBKDF2: if pbkdf2_prf_oid == _OID_HMAC_SHA1: hmac_hash_module = SHA1 elif pbkdf2_prf_oid == _OID_HMAC_SHA224: hmac_hash_module = SHA224 elif pbkdf2_prf_oid == _OID_HMAC_SHA256: hmac_hash_module = SHA256 elif pbkdf2_prf_oid == _OID_HMAC_SHA384: hmac_hash_module = SHA384 elif pbkdf2_prf_oid == _OID_HMAC_SHA512: hmac_hash_module = SHA512 else: raise PbesError("Unsupported HMAC %s" % pbkdf2_prf_oid) key = PBKDF2(passphrase, salt, key_size, iteration_count, hmac_hash_module=hmac_hash_module) else: key = scrypt(passphrase, salt, key_size, iteration_count, scrypt_r, scrypt_p) cipher = ciphermod.new(key, ciphermod.MODE_CBC, IV) # Decrypt data pt = cipher.decrypt(encrypted_data) return unpad(pt, cipher.block_size)
def testErrDecode3(self): # Wrong length format der = DerSequence() self.assertRaises(ValueError, der.decode, '\x30\x04\x02\x01\x01\x00') self.assertRaises(ValueError, der.decode, '\x30\x81\x03\x02\x01\x01') self.assertRaises(ValueError, der.decode, '\x30\x04\x02\x81\x01\x01')
def _importKeyDER(key_data, passphrase, params): """Import a DSA key (public or private half), encoded in DER form.""" try: # # Dss-Parms ::= SEQUENCE { # p OCTET STRING, # q OCTET STRING, # g OCTET STRING # } # # Try a simple private key first if params: x = DerInteger().decode(key_data).value p, q, g = list(DerSequence().decode(params)) # Dss-Parms tup = (pow(g, x, p), g, p, q, x) return construct(tup) der = DerSequence().decode(key_data) # Try OpenSSL format for private keys if len(der) == 6 and der.hasOnlyInts() and der[0] == 0: tup = [der[comp] for comp in (4, 3, 1, 2, 5)] return construct(tup) # Try SubjectPublicKeyInfo if len(der) == 2: try: algo = DerSequence().decode(der[0]) algo_oid = DerObjectId().decode(algo[0]).value params = DerSequence().decode(algo[1]) # Dss-Parms if algo_oid == oid and len(params) == 3 and\ params.hasOnlyInts(): bitmap = DerBitString().decode(der[1]) pub_key = DerInteger().decode(bitmap.value) tup = [pub_key.value] tup += [params[comp] for comp in (2, 0, 1)] return construct(tup) except (ValueError, EOFError): pass # Try to see if this is an X.509 DER certificate # (Certificate ASN.1 type) if len(der) == 3: from Crypto.PublicKey import _extract_sp_info try: sp_info = _extract_sp_info(der) return _importKeyDER(sp_info, passphrase, None) except ValueError: pass # Try unencrypted PKCS#8 p8_pair = PKCS8.unwrap(key_data, passphrase) if p8_pair[0] == oid: return _importKeyDER(p8_pair[1], passphrase, p8_pair[2]) except (ValueError, EOFError): pass raise ValueError("DSA key format is not supported")
def testEncode5(self): der = DerSequence() der += 1 der += b('\x30\x00') self.assertEquals(der.encode(), b('\x30\x05\x02\x01\x01\x30\x00'))
if bord(externKey[0])==0x30: # This is probably a DER encoded key return self._importKeyDER(externKey) raise ValueError("RSA key format is not supported") #: This is the ASN.1 DER object that qualifies an algorithm as #: compliant to PKCS#1 (that is, the standard RSA). # It is found in all 'algorithm' fields (also called 'algorithmIdentifier'). # It is a SEQUENCE with the oid assigned to RSA and with its parameters (none). # 0x06 0x09 OBJECT IDENTIFIER, 9 bytes of payload # 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x01 0x01 # rsaEncryption (1 2 840 113549 1 1 1) (PKCS #1) # 0x05 0x00 NULL algorithmIdentifier = DerSequence( [ b('\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01'), DerNull().encode() ] ).encode() _impl = RSAImplementation() #: #: Randomly generate a fresh, new RSA key object. #: #: See `RSAImplementation.generate`. #: generate = _impl.generate #: #: Construct an RSA key object from a tuple of valid RSA components. #: #: See `RSAImplementation.construct`. #: construct = _impl.construct
def exportKey(self, format='PEM', passphrase=None, pkcs=1): """Export this RSA key. :Parameter format: The format to use for wrapping the key. - *'DER'*. Binary encoding, always unencrypted. - *'PEM'*. Textual encoding, done according to `RFC1421`_/`RFC1423`_. Unencrypted (default) or encrypted. - *'OpenSSH'*. Textual encoding, done according to OpenSSH specification. Only suitable for public keys (not private keys). :Type format: string :Parameter passphrase: In case of PEM, the pass phrase to derive the encryption key from. :Type passphrase: string :Parameter pkcs: The PKCS standard to follow for assembling the key. You have two choices: - with **1**, the public key is embedded into an X.509 `SubjectPublicKeyInfo` DER SEQUENCE. The private key is embedded into a `PKCS#1`_ `RSAPrivateKey` DER SEQUENCE. This mode is the default. - with **8**, the private key is embedded into a `PKCS#8`_ `PrivateKeyInfo` DER SEQUENCE. This mode is not available for public keys. PKCS standards are not relevant for the *OpenSSH* format. :Type pkcs: integer :Return: A byte string with the encoded public or private half. :Raise ValueError: When the format is unknown. .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt .. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt """ if passphrase is not None: passphrase = tobytes(passphrase) if format=='OpenSSH': eb = long_to_bytes(self.e) nb = long_to_bytes(self.n) if bord(eb[0]) & 0x80: eb=bchr(0x00)+eb if bord(nb[0]) & 0x80: nb=bchr(0x00)+nb keyparts = [ b('ssh-rsa'), eb, nb ] keystring = b('').join([ struct.pack(">I",len(kp))+kp for kp in keyparts]) return b('ssh-rsa ')+binascii.b2a_base64(keystring)[:-1] # DER format is always used, even in case of PEM, which simply # encodes it into BASE64. der = DerSequence() if self.has_private(): keyType= { 1: 'RSA PRIVATE', 8: 'PRIVATE' }[pkcs] der[:] = [ 0, self.n, self.e, self.d, self.p, self.q, self.d % (self.p-1), self.d % (self.q-1), inverse(self.q, self.p) ] if pkcs==8: derkey = der.encode() der = DerSequence([0]) der.append(algorithmIdentifier) der.append(DerObject('OCTET STRING', derkey).encode()) else: keyType = "PUBLIC" der.append(algorithmIdentifier) bitmap = DerObject('BIT STRING') derPK = DerSequence( [ self.n, self.e ] ) bitmap.payload = bchr(0x00) + derPK.encode() der.append(bitmap.encode()) if format=='DER': return der.encode() if format=='PEM': pem = b("-----BEGIN " + keyType + " KEY-----\n") objenc = None if passphrase and keyType.endswith('PRIVATE'): # We only support 3DES for encryption import Crypto.Hash.MD5 from Crypto.Cipher import DES3 from Crypto.Protocol.KDF import PBKDF1 salt = self._randfunc(8) key = PBKDF1(passphrase, salt, 16, 1, Crypto.Hash.MD5) key += PBKDF1(key+passphrase, salt, 8, 1, Crypto.Hash.MD5) objenc = DES3.new(key, Crypto.Cipher.DES3.MODE_CBC, salt) pem += b('Proc-Type: 4,ENCRYPTED\n') pem += b('DEK-Info: DES-EDE3-CBC,') + binascii.b2a_hex(salt).upper() + b('\n\n') binaryKey = der.encode() if objenc: # Add PKCS#7-like padding padding = objenc.block_size-len(binaryKey)%objenc.block_size binaryKey = objenc.encrypt(binaryKey+bchr(padding)*padding) # Each BASE64 line can take up to 64 characters (=48 bytes of data) chunks = [ binascii.b2a_base64(binaryKey[i:i+48]) for i in range(0, len(binaryKey), 48) ] pem += b('').join(chunks) pem += b("-----END " + keyType + " KEY-----") return pem return ValueError("Unknown key format '%s'. Cannot export the RSA key." % format)
def testErrDecode2(self): # Wrong payload type der = DerSequence() self.assertRaises(ValueError, der.decode, '\x30\x00\x00', True)
def _importKeyDER(self, externKey): """Import an RSA key (public or private half), encoded in DER form.""" try: der = DerSequence() der.decode(externKey, True) # Try PKCS#1 first, for a private key if len(der)==9 and der.hasOnlyInts() and der[0]==0: # ASN.1 RSAPrivateKey element del der[6:] # Remove d mod (p-1), d mod (q-1), and q^{-1} mod p der.append(inverse(der[4],der[5])) # Add p^{-1} mod q del der[0] # Remove version return self.construct(der[:]) # Keep on trying PKCS#1, but now for a public key if len(der)==2: # The DER object is an RSAPublicKey SEQUENCE with two elements if der.hasOnlyInts(): return self.construct(der[:]) # The DER object is a SubjectPublicKeyInfo SEQUENCE with two elements: # an 'algorithm' (or 'algorithmIdentifier') SEQUENCE and a 'subjectPublicKey' BIT STRING. # 'algorithm' takes the value given a few lines above. # 'subjectPublicKey' encapsulates the actual ASN.1 RSAPublicKey element. if der[0]==algorithmIdentifier: bitmap = DerObject() bitmap.decode(der[1], True) if bitmap.isType('BIT STRING') and bord(bitmap.payload[0])==0x00: der.decode(bitmap.payload[1:], True) if len(der)==2 and der.hasOnlyInts(): return self.construct(der[:]) # Try unencrypted PKCS#8 if der[0]==0: # The second element in the SEQUENCE is algorithmIdentifier. # It must say RSA (see above for description). if der[1]==algorithmIdentifier: privateKey = DerObject() privateKey.decode(der[2], True) if privateKey.isType('OCTET STRING'): return self._importKeyDER(privateKey.payload) except (ValueError, IndexError): pass raise ValueError("RSA key format is not supported")
def wrap(private_key, key_oid, passphrase=None, protection=None, prot_params=None, key_params=None, randfunc=None): """Wrap a private key into a PKCS#8 blob (clear or encrypted). :Parameters: private_key : byte string The private key encoded in binary form. The actual encoding is algorithm specific. In most cases, it is DER. key_oid : string The object identifier (OID) of the private key to wrap. It is a dotted string, like "``1.2.840.113549.1.1.1``" (for RSA keys). passphrase : (binary) string The secret passphrase from which the wrapping key is derived. Set it only if encryption is required. protection : string The identifier of the algorithm to use for securely wrapping the key. The default value is '``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``'. prot_params : dictionary Parameters for the protection algorithm. +------------------+-----------------------------------------------+ | Key | Description | +==================+===============================================+ | iteration_count | The KDF algorithm is repeated several times to| | | slow down brute force attacks on passwords | | | (called *N* or CPU/memory cost in scrypt). | | | | | | The default value for PBKDF2 is 1 000. | | | The default value for scrypt is 16 384. | +------------------+-----------------------------------------------+ | salt_size | Salt is used to thwart dictionary and rainbow | | | attacks on passwords. The default value is 8 | | | bytes. | +------------------+-----------------------------------------------+ | block_size | *(scrypt only)* Memory-cost (r). The default | | | value is 8. | +------------------+-----------------------------------------------+ | parallelization | *(scrypt only)* CPU-cost (p). The default | | | value is 1. | +------------------+-----------------------------------------------+ key_params : DER object The algorithm parameters associated to the private key. It is required for algorithms like DSA, but not for others like RSA. randfunc : callable Random number generation function; it should accept a single integer N and return a string of random data, N bytes long. If not specified, a new RNG will be instantiated from ``Crypto.Random``. :Return: The PKCS#8-wrapped private key (possibly encrypted), as a binary string. """ if key_params is None: key_params = DerNull() # # PrivateKeyInfo ::= SEQUENCE { # version Version, # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, # privateKey PrivateKey, # attributes [0] IMPLICIT Attributes OPTIONAL # } # pk_info = DerSequence([ 0, DerSequence([DerObjectId(key_oid), key_params]), DerOctetString(private_key) ]) pk_info_der = pk_info.encode() if passphrase is None: return pk_info_der if not passphrase: raise ValueError("Empty passphrase") # Encryption with PBES2 passphrase = tobytes(passphrase) if protection is None: protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' return PBES2.encrypt(pk_info_der, passphrase, protection, prot_params, randfunc)
keyparts = [] while len(keystring) > 4: l = struct.unpack(">I", keystring[:4])[0] keyparts.append(keystring[4:4 + l]) keystring = keystring[4 + l:] e = Integer.from_bytes(keyparts[1]) n = Integer.from_bytes(keyparts[2]) return construct([n, e]) if bord(extern_key[0]) == 0x30: # This is probably a DER encoded key return _importKeyDER(extern_key, passphrase) raise ValueError("RSA key format is not supported") #: `Object ID`_ for the RSA encryption algorithm. This OID often indicates #: a generic RSA key, even when such key will be actually used for digital #: signatures. #: #: .. _`Object ID`: http://www.alvestrand.no/objectid/1.2.840.113549.1.1.1.html oid = "1.2.840.113549.1.1.1" #: This is the standard DER object that qualifies a cryptographic algorithm #: in ASN.1-based data structures (e.g. X.509 certificates). algorithmIdentifier = DerSequence([ DerObjectId(oid).encode(), # algorithm field DerNull().encode() ] # parameters field ).encode()