def import_key(encoded, passphrase=None): """Import an ECC key (public or private). :Parameters: encoded : bytes or a (multi-line) string The ECC key to import. An ECC public key can be: - An X.509 certificate, binary (DER) or ASCII (PEM) - An X.509 ``subjectPublicKeyInfo``, binary (DER) or ASCII (PEM) - An OpenSSH line (e.g. the content of ``~/.ssh/id_ecdsa``, ASCII) An ECC private key can be: - In binary format (DER, see section 3 of `RFC5915`_ or `PKCS#8`_) - In ASCII format (PEM or OpenSSH) Private keys can be in the clear or password-protected. For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. :Keywords: passphrase : byte string The passphrase to use for decrypting a private key. Encryption may be applied protected at the PEM level or at the PKCS#8 level. This parameter is ignored if the key in input is not encrypted. :Return: An ECC key object (`EccKey`) :Raise ValueError: When the given key cannot be parsed (possibly because the pass phrase is wrong). .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt .. _RFC5915: http://www.ietf.org/rfc/rfc5915.txt .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt """ encoded = tobytes(encoded) if passphrase is not None: passphrase = tobytes(passphrase) # PEM if encoded.startswith(b('-----')): der_encoded, marker, enc_flag = PEM.decode(tostr(encoded), passphrase) if enc_flag: passphrase = None return _import_der(der_encoded, passphrase) # OpenSSH if encoded.startswith(b('ecdsa-sha2-')): return _import_openssh(encoded) # DER if bord(encoded[0]) == 0x30: return _import_der(encoded, passphrase) raise ValueError("ECC key format is not supported")
def __init__(self, stash_key, value, manager_provider, aws_profile=None, aws_region=None, aws_bucket=None, kms_key='alias/novastash'): check_latest_version() self._aws_manager = manager_provider.aws_manager(aws_profile, aws_region or 'us-east-1') if aws_bucket is None: deployment_bucket_name = 'novastash_%s' % self._aws_manager.account_alias else: deployment_bucket_name = aws_bucket if not self._aws_manager.kms_key_exists(kms_key): raise NovaError("Please setup the novastash KMS key.") self._aws_manager.create_bucket(deployment_bucket_name, "Creating novastash bucket '%s'" % deployment_bucket_name) # generate a a 64 byte key. # Half will be for data encryption, the other half for HMAC kms_response = self._aws_manager.kms_generate_data_key(kms_key, {}) data_key = tobytes(kms_response['Plaintext'][:32]) hmac_key = tobytes(kms_response['Plaintext'][32:]) wrapped_key = tobytes(kms_response['CiphertextBlob']) enc_ctr = Counter.new(128) encryptor = AES.new(data_key, AES.MODE_CTR, counter=enc_ctr) c_text = encryptor.encrypt(tobytes(value)) # compute an HMAC using the hmac key and the ciphertext hmac = HMAC(hmac_key, msg=c_text, digestmod=SHA256) b64hmac = hmac.hexdigest() key = "%s.txt.enc" % stash_key existing_stash = self._aws_manager.s3_head(deployment_bucket_name, key) if existing_stash is None: print(colored("Stashing '%s'" % stash_key)) self._aws_manager.s3_put( deployment_bucket_name, b64encode(c_text).decode('utf-8'), key, {'encryption-key': b64encode(wrapped_key).decode('utf-8'), 'hmac': b64hmac} ) else: perform_overwrite = query_yes_no("Stash '%s' already exists, want to overwrite?" % stash_key, default="no") if perform_overwrite: self._aws_manager.s3_put( deployment_bucket_name, b64encode(c_text).decode('utf-8'), key, {'encryption-key': b64encode(wrapped_key).decode('utf-8'), 'hmac': b64hmac} ) else: print(colored("Not stashing anything for key '%s'" % stash_key))
def setUp(self): # Convert DSA key components from hex strings to integers # Each key is (p, q, g, x, y, desc) from collections import namedtuple TestKey = namedtuple('TestKey', 'p q g x y') new_keys = {} for k in self.keys: tk = TestKey(*[ t2l(y) for y in k[:-1] ]) new_keys[k[-1]] = tk self.keys = new_keys # Convert signature encoding TestSig = namedtuple('TestSig', 'message nonce result module test_key') new_signatures = [] for message, nonce, r, s, module, test_key in self.signatures: tsig = TestSig( tobytes(message), t2l(nonce), t2b(r) + t2b(s), module, self.keys[test_key] ) new_signatures.append(tsig) self.signatures = new_signatures
def setUp(self): test_vector_file = pycryptodome_filename( ("Crypto", "SelfTest", "Hash", "test_vectors", self.name), self.name.lower() + "-test.txt") expected = "in" self.test_vectors = [] for line_number, line in enumerate(open(test_vector_file, "rt")): if line.strip() == "" or line.startswith("#"): continue res = re.match("%s:\t([0-9A-Fa-f]*)" % expected, line) if not res: raise ValueError("Incorrect test vector format (line %d)" % line_number) if res.group(1): bin_value = unhexlify(tobytes(res.group(1))) else: bin_value = b("") if expected == "in": input_data = bin_value expected = "key" elif expected == "key": key = bin_value expected = "hash" else: result = bin_value expected = "in" self.test_vectors.append((input_data, key, result))
def test_aes_encrypt(data=DATA, nonce=NONCE): """ AES Encrypt (256 Bit, CBC Mode, PKCS #7 Padding) """ size = AES.block_size - (len(data) % AES.block_size) data = tobytes(data) + (bchr(size) * size) data = AES.new(nonce[:32], AES.MODE_CBC, nonce[32:]).encrypt(data) return base64.b64encode(data), len(data)
def test_short_128(self): test_vectors = load_tests("SHA3", "ShortMsgKAT_SHAKE128.txt") for result, data, desc in test_vectors: data = tobytes(data) hobj = SHAKE128.new(data=data) assert(len(result) % 2 == 0) digest = hobj.read(len(result)//2) hexdigest = "".join(["%02x" % bord(x) for x in digest]) self.assertEqual(hexdigest, result)
def encrypt(self, data): nonce = Random.get_random_bytes(Pssst._Key.NONCE_SIZE) size = AES.block_size - (len(data) % AES.block_size) data = tobytes(data) + (bchr(size) * size) data = AES.new(nonce[:32], AES.MODE_CBC, nonce[32:]).encrypt(data) nonce = PKCS1_OAEP.new(self.key).encrypt(nonce) return (data, nonce)
def hexverify(self, hex_mac_tag): """Return the **printable** MAC tag of the message authenticated so far. :return: The MAC tag, computed over the data processed so far. Hexadecimal encoded. :rtype: string """ self.verify(unhexlify(tobytes(hex_mac_tag)))
def test_hex_digest(self): mac = keccak.new(digest_bits=512) digest = mac.digest() hexdigest = mac.hexdigest() # hexdigest is equivalent to digest self.assertEqual(hexlify(digest), tobytes(hexdigest)) # hexdigest does not change the state self.assertEqual(mac.hexdigest(), hexdigest) # hexdigest returns a string self.assertTrue(isinstance(hexdigest, type("digest")))
def test_hex_digest(self): mac = Poly1305.new(key=self.key, cipher=AES) digest = mac.digest() hexdigest = mac.hexdigest() # hexdigest is equivalent to digest self.assertEqual(hexlify(digest), tobytes(hexdigest)) # hexdigest does not change the state self.assertEqual(mac.hexdigest(), hexdigest) # hexdigest returns a string self.failUnless(isinstance(hexdigest, type("digest")))
def test_hex_digest(self): mac = self.BLAKE2.new(digest_bits=self.max_bits) digest = mac.digest() hexdigest = mac.hexdigest() # hexdigest is equivalent to digest self.assertEqual(hexlify(digest), tobytes(hexdigest)) # hexdigest does not change the state self.assertEqual(mac.hexdigest(), hexdigest) # hexdigest returns a string self.failUnless(isinstance(hexdigest, type("digest")))
def _export_openssh(self, compress): if self.has_private(): raise ValueError("Cannot export OpenSSH private keys") desc = self._curve.openssh modulus_bytes = self.pointQ.size_in_bytes() if compress: first_byte = 2 + self.pointQ.y.is_odd() public_key = (bchr(first_byte) + self.pointQ.x.to_bytes(modulus_bytes)) else: public_key = (b'\x04' + self.pointQ.x.to_bytes(modulus_bytes) + self.pointQ.y.to_bytes(modulus_bytes)) middle = desc.split("-")[2] comps = (tobytes(desc), tobytes(middle), public_key) blob = b"".join([struct.pack(">I", len(x)) + x for x in comps]) return desc + " " + tostr(binascii.b2a_base64(blob))
def setUp(self): test_dir, _ = os.path.split(os.path.abspath(__file__)) test_vector_file = os.path.join(test_dir, "test_vectors", self.name, "tv1.txt") self.test_vectors = [] for line_number, line in enumerate(open(test_vector_file, "rt")): if line.strip() == "" or line.startswith("#"): continue res = re.match("digest: ([0-9A-Fa-f]*)", line) if not res: raise ValueError("Incorrect test vector format (line %d)" % line_number) self.test_vectors.append(unhexlify(tobytes(res.group(1))))
def hexverify(self, hex_mac_tag): """Verify that a given **printable** MAC (computed by another party) is valid. :Parameters: hex_mac_tag : string The expected MAC of the message, as a hexadecimal string. :Raises ValueError: if the MAC does not match. It means that the message has been tampered with or that the MAC key is incorrect. """ self.verify(unhexlify(tobytes(hex_mac_tag)))
def runTest(self): tag = unhexlify(b"fb447350c4e868c52ac3275cf9d4327e") msg = b'' for msg_len in range(5000 + 1): key = tag + strxor_c(tag, 0xFF) nonce = tag[::-1] if msg_len > 0: msg = msg + tobytes(tag[0]) auth = Poly1305.new(key=key, nonce=nonce, cipher=AES, data=msg) tag = auth.digest() # Compare against output of original DJB's poly1305aes-20050218 self.assertEqual("CDFA436DDD629C7DC20E1128530BAED2", auth.hexdigest().upper())
def _export_openssh(self): assert not self.has_private() desc = "ecdsa-sha2-nistp256" # Uncompressed form order_bytes = _curve.order.size_in_bytes() public_key = (bchr(4) + self.pointQ.x.to_bytes(order_bytes) + self.pointQ.y.to_bytes(order_bytes)) comps = (tobytes(desc), b("nistp256"), public_key) blob = b("").join([ struct.pack(">I", len(x)) + x for x in comps]) return desc + " " + tostr(binascii.b2a_base64(blob))
def setUp(self): test_vector_file = pycryptodome_filename( ("Crypto", "SelfTest", "Hash", "test_vectors", self.name), "tv1.txt") self.test_vectors = [] for line_number, line in enumerate(open(test_vector_file, "rt")): if line.strip() == "" or line.startswith("#"): continue res = re.match("digest: ([0-9A-Fa-f]*)", line) if not res: raise ValueError("Incorrect test vector format (line %d)" % line_number) self.test_vectors.append(unhexlify(tobytes(res.group(1))))
def __init__(self, value): """Initialize the integer to the given value.""" self._mpz_p = new_mpz() self._initialized = False if isinstance(value, float): raise ValueError("A floating point type is not a natural number") self._initialized = True if isinstance(value, (int, long)): _gmp.mpz_init(self._mpz_p) result = _gmp.gmp_sscanf(tobytes(str(value)), b("%Zd"), self._mpz_p) if result != 1: raise ValueError("Error converting '%d'" % value) else: _gmp.mpz_init_set(self._mpz_p, value._mpz_p)
def _import_openssh(encoded): keystring = binascii.a2b_base64(encoded.split(b' ')[1]) keyparts = [] while len(keystring) > 4: lk = struct.unpack(">I", keystring[:4])[0] keyparts.append(keystring[4:4 + lk]) keystring = keystring[4 + lk:] for curve_name, curve in _curves.items(): middle = tobytes(curve.openssh.split("-")[2]) if keyparts[1] == middle: break else: raise ValueError("Unsupported ECC curve") return _import_public_der(curve.oid, keyparts[2])
def PBKDF1(password, salt, dkLen, count=1000, hashAlgo=None): """Derive one key from a password (or passphrase). This function performs key derivation according to an old version of the PKCS#5 standard (v1.5) or `RFC2898 <https://www.ietf.org/rfc/rfc2898.txt>`_. .. warning:: Newer applications should use the more secure and versatile :func:`PBKDF2` instead. Args: password (string): The secret password to generate the key from. salt (byte string): An 8 byte string to use for better protection from dictionary attacks. This value does not need to be kept secret, but it should be randomly chosen for each derivation. dkLen (integer): The length of the desired key. The default is 16 bytes, suitable for instance for :mod:`Crypto.Cipher.AES`. count (integer): The number of iterations to carry out. The recommendation is 1000 or more. hashAlgo (module): The hash algorithm to use, as a module or an object from the :mod:`Crypto.Hash` package. The digest length must be no shorter than ``dkLen``. The default algorithm is :mod:`Crypto.Hash.SHA1`. Return: A byte string of length ``dkLen`` that can be used as key. """ if not hashAlgo: hashAlgo = SHA1 password = tobytes(password) pHash = hashAlgo.new(password+salt) digest = pHash.digest_size if dkLen > digest: raise TypeError("Selected hash algorithm has a too short digest (%d bytes)." % digest) if len(salt) != 8: raise ValueError("Salt is not 8 bytes long (%d bytes instead)." % len(salt)) for i in xrange(count-1): pHash = pHash.new(pHash.digest()) return pHash.digest()[:dkLen]
def setUp(self): test_vector_file = pycryptodome_filename( ("Crypto", "SelfTest", "Hash", "test_vectors", self.name), "tv2.txt") self.test_vectors = [] with open(test_vector_file, "rt") as test_vector_fd: for line_number, line in enumerate(test_vector_fd): if line.strip() == "" or line.startswith("#"): continue res = re.match(r"digest\(([0-9]+)\): ([0-9A-Fa-f]*)", line) if not res: raise ValueError("Incorrect test vector format (line %d)" % line_number) key_size = int(res.group(1)) result = unhexlify(tobytes(res.group(2))) self.test_vectors.append((key_size, result))
def _export_openssh(self, compress): if self.has_private(): raise ValueError("Cannot export OpenSSH private keys") desc = "ecdsa-sha2-nistp256" order_bytes = _curve.order.size_in_bytes() if compress: first_byte = 2 + self.pointQ.y.is_odd() public_key = (bchr(first_byte) + self.pointQ.x.to_bytes(order_bytes)) else: public_key = (bchr(4) + self.pointQ.x.to_bytes(order_bytes) + self.pointQ.y.to_bytes(order_bytes)) comps = (tobytes(desc), b("nistp256"), public_key) blob = b("").join([ struct.pack(">I", len(x)) + x for x in comps]) return desc + " " + tostr(binascii.b2a_base64(blob))
def decode(pem_data, passphrase=None): """Decode a PEM block into binary. :Parameters: pem_data : string The PEM block. passphrase : byte string If given and the PEM block is encrypted, the key will be derived from the passphrase. :Returns: A tuple with the binary data, the marker string, and a boolean to indicate if decryption was performed. :Raises ValueError: If decoding fails, if the PEM file is encrypted and no passphrase has been provided or if the passphrase is incorrect. """ # Verify Pre-Encapsulation Boundary r = re.compile("\s*-----BEGIN (.*)-----\n") m = r.match(pem_data) if not m: raise ValueError("Not a valid PEM pre boundary") marker = m.group(1) # Verify Post-Encapsulation Boundary r = re.compile("-----END (.*)-----\s*$") m = r.search(pem_data) if not m or m.group(1) != marker: raise ValueError("Not a valid PEM post boundary") # Removes spaces and slit on lines lines = pem_data.replace(" ", '').split() # Decrypts, if necessary if lines[1].startswith('Proc-Type:4,ENCRYPTED'): if not passphrase: raise ValueError("PEM is encrypted, but no passphrase available") DEK = lines[2].split(':') if len(DEK) != 2 or DEK[0] != 'DEK-Info': raise ValueError("PEM encryption format not supported.") algo, salt = DEK[1].split(',') salt = unhexlify(tobytes(salt)) if algo == "DES-CBC": # This is EVP_BytesToKey in OpenSSL key = PBKDF1(passphrase, salt, 8, 1, MD5) objdec = DES.new(key, DES.MODE_CBC, salt) elif algo == "DES-EDE3-CBC": # Note that EVP_BytesToKey is note exactly the same as PBKDF1 key = PBKDF1(passphrase, salt, 16, 1, MD5) key += PBKDF1(key + passphrase, salt, 8, 1, MD5) objdec = DES3.new(key, DES3.MODE_CBC, salt) elif algo == "AES-128-CBC": key = PBKDF1(passphrase, salt[:8], 16, 1, MD5) objdec = AES.new(key, AES.MODE_CBC, salt) else: raise ValueError("Unsupport PEM encryption algorithm.") lines = lines[2:] else: objdec = None # Decode body data = a2b_base64(b(''.join(lines[1:-1]))) enc_flag = False if objdec: data = unpad(objdec.decrypt(data), objdec.block_size) enc_flag = True return (data, marker, enc_flag)
def export_key(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 = [func(x) for x in 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 write(self, data): data = tobytes(data) if self.parse_split_bytes: data += SPLIT_BYTES # logger.debug(data) self.socket.send(data)
def get_tag_random(tag, length): return SHAKE128.new(data=tobytes(tag)).read(length)
def import_key(extern_key, passphrase=None): """Import an RSA key (public or private). Args: extern_key (string or byte string): The RSA key to import. The following formats are supported for an RSA **public key**: - X.509 certificate (binary or PEM format) - X.509 ``subjectPublicKeyInfo`` DER SEQUENCE (binary or PEM encoding) - `PKCS#1`_ ``RSAPublicKey`` DER SEQUENCE (binary or PEM encoding) - An OpenSSH line (e.g. the content of ``~/.ssh/id_ecdsa``, ASCII) The following formats are supported for an RSA **private key**: - PKCS#1 ``RSAPrivateKey`` DER SEQUENCE (binary or PEM encoding) - `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo`` DER SEQUENCE (binary or PEM encoding) - OpenSSH (text format, introduced in `OpenSSH 6.5`_) For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. passphrase (string or byte string): For private keys only, the pass phrase that encrypts the key. Returns: An RSA key object (:class:`RsaKey`). Raises: ValueError/IndexError/TypeError: When the given key cannot be parsed (possibly because the pass phrase is wrong). .. _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 .. _`OpenSSH 6.5`: https://flak.tedunangst.com/post/new-openssh-key-format-and-bcrypt-pbkdf """ from Crypto.IO import PEM extern_key = tobytes(extern_key) if passphrase is not None: passphrase = tobytes(passphrase) if extern_key.startswith(b'-----BEGIN OPENSSH PRIVATE KEY'): text_encoded = tostr(extern_key) openssh_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase) result = _import_openssh_private_rsa(openssh_encoded, passphrase) return result if extern_key.startswith(b'-----'): # This is probably a PEM encoded key. (der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase) if enc_flag: passphrase = None return _import_keyDER(der, passphrase) if extern_key.startswith(b'ssh-rsa '): # This is probably an OpenSSH key keystring = binascii.a2b_base64(extern_key.split(b' ')[1]) keyparts = [] while len(keystring) > 4: length = struct.unpack(">I", keystring[:4])[0] keyparts.append(keystring[4:4 + length]) keystring = keystring[4 + length:] e = Integer.from_bytes(keyparts[1]) n = Integer.from_bytes(keyparts[2]) return construct([n, e]) if len(extern_key) > 0 and bord(extern_key[0]) == 0x30: # This is probably a DER encoded key return _import_keyDER(extern_key, passphrase) raise ValueError("RSA key format is not supported")
def import_key(extern_key, passphrase=None): """Import an RSA key (public or private half), encoded in standard form. Args: extern_key (string or byte string): The RSA key to import. The following formats are supported for an RSA **public key**: - X.509 certificate (binary or PEM format) - X.509 ``subjectPublicKeyInfo`` DER SEQUENCE (binary or PEM encoding) - `PKCS#1`_ ``RSAPublicKey`` DER SEQUENCE (binary or PEM encoding) - OpenSSH (textual public key only) The following formats are supported for an RSA **private key**: - PKCS#1 ``RSAPrivateKey`` DER SEQUENCE (binary or PEM encoding) - `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo`` DER SEQUENCE (binary or PEM encoding) - OpenSSH (textual public key only) For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. The private key may be encrypted by means of a certain pass phrase either at the PEM level or at the PKCS#8 level. passphrase (string): In case of an encrypted private key, this is the pass phrase from which the decryption key is derived. Returns: An RSA key object (:class:`RsaKey`). Raises: ValueError/IndexError/TypeError: When the given key cannot be parsed (possibly because the pass phrase is wrong). .. _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 """ extern_key = tobytes(extern_key) if passphrase is not None: passphrase = tobytes(passphrase) if extern_key.startswith(b('-----')): # This is probably a PEM encoded key. (der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase) if enc_flag: passphrase = None return _import_keyDER(der, passphrase) if extern_key.startswith(b('ssh-rsa ')): # This is probably an OpenSSH key keystring = binascii.a2b_base64(extern_key.split(b(' '))[1]) 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 _import_keyDER(extern_key, passphrase) raise ValueError("RSA key format is not supported")
def decode(pem_data, passphrase=None): """Decode a PEM block into binary. Args: pem_data (string): The PEM block. passphrase (byte string): If given and the PEM block is encrypted, the key will be derived from the passphrase. Returns: A tuple with the binary data, the marker string, and a boolean to indicate if decryption was performed. Raises: ValueError: if decoding fails, if the PEM file is encrypted and no passphrase has been provided or if the passphrase is incorrect. """ # Verify Pre-Encapsulation Boundary r = re.compile(r"\s*-----BEGIN (.*)-----\s+") m = r.match(pem_data) if not m: raise ValueError("Not a valid PEM pre boundary") marker = m.group(1) # Verify Post-Encapsulation Boundary r = re.compile(r"-----END (.*)-----\s*$") m = r.search(pem_data) if not m or m.group(1) != marker: raise ValueError("Not a valid PEM post boundary") # Removes spaces and slit on lines lines = pem_data.replace(" ", '').split() # Decrypts, if necessary if lines[1].startswith('Proc-Type:4,ENCRYPTED'): if not passphrase: raise ValueError("PEM is encrypted, but no passphrase available") DEK = lines[2].split(':') if len(DEK) != 2 or DEK[0] != 'DEK-Info': raise ValueError("PEM encryption format not supported.") algo, salt = DEK[1].split(',') salt = unhexlify(tobytes(salt)) padding = True if algo == "DES-CBC": key = _EVP_BytesToKey(passphrase, salt, 8) objdec = DES.new(key, DES.MODE_CBC, salt) elif algo == "DES-EDE3-CBC": key = _EVP_BytesToKey(passphrase, salt, 24) objdec = DES3.new(key, DES3.MODE_CBC, salt) elif algo == "AES-128-CBC": key = _EVP_BytesToKey(passphrase, salt[:8], 16) objdec = AES.new(key, AES.MODE_CBC, salt) elif algo == "AES-192-CBC": key = _EVP_BytesToKey(passphrase, salt[:8], 24) objdec = AES.new(key, AES.MODE_CBC, salt) elif algo == "AES-256-CBC": key = _EVP_BytesToKey(passphrase, salt[:8], 32) objdec = AES.new(key, AES.MODE_CBC, salt) elif algo.lower() == "id-aes256-gcm": key = _EVP_BytesToKey(passphrase, salt[:8], 32) objdec = AES.new(key, AES.MODE_GCM, nonce=salt) padding = False else: raise ValueError("Unsupport PEM encryption algorithm (%s)." % algo) lines = lines[2:] else: objdec = None # Decode body data = a2b_base64(''.join(lines[1:-1])) enc_flag = False if objdec: if padding: data = unpad(objdec.decrypt(data), objdec.block_size) else: # There is no tag, so we don't use decrypt_and_verify data = objdec.decrypt(data) enc_flag = True return (data, marker, enc_flag)
def export_key(self, **kwargs): """Export this ECC key. :Keywords: format : string The format to use for wrapping the key: - *'DER'*. The key will be encoded in an ASN.1 DER_ structure (binary). - *'PEM'*. The key will be encoded in a PEM_ envelope (ASCII). - *'OpenSSH'*. The key will be encoded in the OpenSSH_ format (ASCII, public keys only). passphrase : byte string or string The passphrase to use for protecting the private key. *If not provided, the private key will remain in clear form!* use_pkcs8 : boolean In case of a private key, whether the PKCS#8_ representation should be (internally) used. By default it will. Not using PKCS#8 when exporting a private key in password-protected PEM_ form means that the much weaker and unflexible `PEM encryption`_ mechanism will be used. PKCS#8 is therefore always recommended. protection : string In case of a private key being exported with password-protection and PKCS#8 (both ``DER`` and ``PEM`` formats), this parameter MUST be present and be a valid algorithm supported by `Crypto.IO.PKCS8`. It is recommended to use ``PBKDF2WithHMAC-SHA1AndAES128-CBC``. :Note: In case of a private key being exported with password-protection and PKCS#8_ (both ``DER`` and ``PEM`` formats), all additional parameters will be passed to `Crypto.IO.PKCS8`. .. _DER: http://www.ietf.org/rfc/rfc5915.txt .. _PEM: http://www.ietf.org/rfc/rfc1421.txt .. _`PEM encryption`: http://www.ietf.org/rfc/rfc1423.txt .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt .. _OpenSSH: http://www.openssh.com/txt/rfc5656.txt :Return: A multi-line string (for PEM and OpenSSH) or bytes (for DER) with the encoded key. """ args = kwargs.copy() ext_format = args.pop("format") if ext_format not in ("PEM", "DER", "OpenSSH"): raise ValueError("Unknown format '%s'" % ext_format) if self.has_private(): passphrase = args.pop("passphrase", None) if isinstance(passphrase, basestring): passphrase = tobytes(passphrase) if not passphrase: raise ValueError("Empty passphrase") use_pkcs8 = args.pop("use_pkcs8", True) if ext_format == "PEM": if use_pkcs8: if passphrase: return self._export_private_encrypted_pkcs8_in_clear_pem(passphrase, **args) else: return self._export_private_clear_pkcs8_in_clear_pem() else: return self._export_private_pem(passphrase, **args) elif ext_format == "DER": # DER if passphrase and not use_pkcs8: raise ValueError("Private keys can only be encrpyted with DER using PKCS#8") if use_pkcs8: return self._export_pkcs8(passphrase=passphrase, **args) else: return self._export_private_der() else: raise ValueError("Private keys cannot be exported in OpenSSH format") else: # Public key if args: raise ValueError("Unexpected parameters: '%s'" % args) if ext_format == "PEM": return self._export_public_pem() elif ext_format == "DER": return self._export_subjectPublicKeyInfo() else: return self._export_openssh()
def export_key(self, **kwargs): """Export this ECC key. Args: format (string): The format to use for encoding the key: - *'DER'*. The key will be encoded in ASN.1 DER format (binary). For a public key, the ASN.1 ``subjectPublicKeyInfo`` structure defined in `RFC5480`_ will be used. For a private key, the ASN.1 ``ECPrivateKey`` structure defined in `RFC5915`_ is used instead (possibly within a PKCS#8 envelope, see the ``use_pkcs8`` flag below). - *'PEM'*. The key will be encoded in a PEM_ envelope (ASCII). - *'OpenSSH'*. The key will be encoded in the OpenSSH_ format (ASCII, public keys only). passphrase (byte string or string): The passphrase to use for protecting the private key. use_pkcs8 (boolean): If ``True`` (default and recommended), the `PKCS#8`_ representation will be used. If ``False``, the much weaker `PEM encryption`_ mechanism will be used. protection (string): When a private key is exported with password-protection and PKCS#8 (both ``DER`` and ``PEM`` formats), this parameter MUST be present and be a valid algorithm supported by :mod:`Crypto.IO.PKCS8`. It is recommended to use ``PBKDF2WithHMAC-SHA1AndAES128-CBC``. compress (boolean): If ``True``, a more compact representation of the public key (X-coordinate only) is used. If ``False`` (default), the full public key (in both its coordinates) will be exported. .. warning:: If you don't provide a passphrase, the private key will be exported in the clear! .. note:: When exporting a private key with password-protection and `PKCS#8`_ (both ``DER`` and ``PEM`` formats), any extra parameters is passed to :mod:`Crypto.IO.PKCS8`. .. _PEM: http://www.ietf.org/rfc/rfc1421.txt .. _`PEM encryption`: http://www.ietf.org/rfc/rfc1423.txt .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt .. _OpenSSH: http://www.openssh.com/txt/rfc5656.txt .. _RFC5480: https://tools.ietf.org/html/rfc5480 .. _RFC5915: http://www.ietf.org/rfc/rfc5915.txt Returns: A multi-line string (for PEM and OpenSSH) or bytes (for DER) with the encoded key. """ args = kwargs.copy() ext_format = args.pop("format") if ext_format not in ("PEM", "DER", "OpenSSH"): raise ValueError("Unknown format '%s'" % ext_format) compress = args.pop("compress", False) if self.has_private(): passphrase = args.pop("passphrase", None) if is_string(passphrase): passphrase = tobytes(passphrase) if not passphrase: raise ValueError("Empty passphrase") use_pkcs8 = args.pop("use_pkcs8", True) if ext_format == "PEM": if use_pkcs8: if passphrase: return self._export_private_encrypted_pkcs8_in_clear_pem( passphrase, **args) else: return self._export_private_clear_pkcs8_in_clear_pem() else: return self._export_private_pem(passphrase, **args) elif ext_format == "DER": # DER if passphrase and not use_pkcs8: raise ValueError( "Private keys can only be encrpyted with DER using PKCS#8" ) if use_pkcs8: return self._export_pkcs8(passphrase=passphrase, **args) else: return self._export_private_der() else: raise ValueError( "Private keys cannot be exported in OpenSSH format") else: # Public key if args: raise ValueError("Unexpected parameters: '%s'" % args) if ext_format == "PEM": return self._export_public_pem(compress) elif ext_format == "DER": return self._export_subjectPublicKeyInfo(compress) else: return self._export_openssh(compress)
def import_key(encoded, passphrase=None): """Import an ECC key (public or private). Args: encoded (bytes or multi-line string): The ECC key to import. An ECC **public** key can be: - An X.509 certificate, binary (DER) or ASCII (PEM) - An X.509 ``subjectPublicKeyInfo``, binary (DER) or ASCII (PEM) - An OpenSSH line (e.g. the content of ``~/.ssh/id_ecdsa``, ASCII) An ECC **private** key can be: - In binary format (DER, see section 3 of `RFC5915`_ or `PKCS#8`_) - In ASCII format (PEM or OpenSSH) Private keys can be in the clear or password-protected. For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. passphrase (byte string): The passphrase to use for decrypting a private key. Encryption may be applied protected at the PEM level or at the PKCS#8 level. This parameter is ignored if the key in input is not encrypted. Returns: :class:`EccKey` : a new ECC key object Raises: ValueError: when the given key cannot be parsed (possibly because the pass phrase is wrong). .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt .. _RFC5915: http://www.ietf.org/rfc/rfc5915.txt .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt """ encoded = tobytes(encoded) if passphrase is not None: passphrase = tobytes(passphrase) # PEM if encoded.startswith(b'-----'): der_encoded, marker, enc_flag = PEM.decode(tostr(encoded), passphrase) if enc_flag: passphrase = None try: result = _import_der(der_encoded, passphrase) except UnsupportedEccFeature as uef: raise uef except ValueError: raise ValueError("Invalid DER encoding inside the PEM file") return result # OpenSSH if encoded.startswith(b'ecdsa-sha2-'): return _import_openssh(encoded) # DER if bord(encoded[0]) == 0x30: return _import_der(encoded, passphrase) raise ValueError("ECC key format is not supported")
def hexverify(self, hex_mac_tag): self.verify(unhexlify(tobytes(hex_mac_tag)))
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 PBKDF2(password, salt, dkLen=16, count=1000, prf=None, hmac_hash_module=None): """Derive one or more keys from a password (or passphrase). This function performs key derivation according to the PKCS#5 standard (v2.0). Args: password (string or byte string): The secret password to generate the key from. salt (string or byte string): A (byte) string to use for better protection from dictionary attacks. This value does not need to be kept secret, but it should be randomly chosen for each derivation. It is recommended to be at least 8 bytes long. dkLen (integer): The cumulative length of the desired keys. count (integer): The number of iterations to carry out. prf (callable): A pseudorandom function. It must be a function that returns a pseudorandom string from two parameters: a secret and a salt. If not specified, **HMAC-SHA1** is used. hmac_hash_module (module): A module from `Crypto.Hash` implementing a Merkle-Damgard cryptographic hash, which PBKDF2 must use in combination with HMAC. This parameter is mutually exclusive with ``prf``. Return: A byte string of length ``dkLen`` that can be used as key material. If you wanted multiple keys, just break up this string into segments of the desired length. """ password = tobytes(password) salt = tobytes(salt) if prf and hmac_hash_module: raise ValueError("'prf' and 'hmac_hash_module' are mutually exlusive") if prf is None and hmac_hash_module is None: hmac_hash_module = SHA1 if prf or not hasattr(hmac_hash_module, "_pbkdf2_hmac_assist"): # Generic (and slow) implementation if prf is None: prf = lambda p,s: HMAC.new(p, s, hmac_hash_module).digest() def link(s): s[0], s[1] = s[1], prf(password, s[1]) return s[0] key = b'' i = 1 while len(key)<dkLen: s = [ prf(password, salt + struct.pack(">I", i)) ] * 2 key += reduce(strxor, (link(s) for j in range(count)) ) i += 1 else: # Optimized implementation key = b'' i = 1 while len(key)<dkLen: base = HMAC.new(password, b"", hmac_hash_module) first_digest = base.copy().update(salt + struct.pack(">I", i)).digest() key += base._pbkdf2_hmac_assist(first_digest, count) i += 1 return key[:dkLen]
def import_key(extern_key, passphrase=None): """Import a DSA key. Args: extern_key (string or byte string): The DSA key to import. The following formats are supported for a DSA **public** key: - X.509 certificate (binary DER or PEM) - X.509 ``subjectPublicKeyInfo`` (binary DER or PEM) - OpenSSH (ASCII one-liner, see `RFC4253`_) The following formats are supported for a DSA **private** key: - `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo`` DER SEQUENCE (binary or PEM) - OpenSSL/OpenSSH custom format (binary or PEM) For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. passphrase (string): In case of an encrypted private key, this is the pass phrase from which the decryption key is derived. Encryption may be applied either at the `PKCS#8`_ or at the PEM level. Returns: :class:`DsaKey` : a DSA key object Raises: ValueError : when the given key cannot be parsed (possibly because the pass phrase is wrong). .. _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 """ extern_key = tobytes(extern_key) if passphrase is not None: passphrase = tobytes(passphrase) if extern_key.startswith(b'-----'): # This is probably a PEM encoded key (der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase) if enc_flag: passphrase = None return _import_key_der(der, passphrase, None) if extern_key.startswith(b'ssh-dss '): # This is probably a public OpenSSH key keystring = binascii.a2b_base64(extern_key.split(b' ')[1]) keyparts = [] while len(keystring) > 4: length = struct.unpack(">I", keystring[:4])[0] keyparts.append(keystring[4:4 + length]) keystring = keystring[4 + length:] if keyparts[0] == b"ssh-dss": tup = [Integer.from_bytes(keyparts[x]) for x in (4, 3, 1, 2)] return construct(tup) if len(extern_key) > 0 and bord(extern_key[0]) == 0x30: # This is probably a DER encoded key return _import_key_der(extern_key, passphrase, None) raise ValueError("DSA key format is not supported")
def PBKDF2(password, salt, dkLen=16, count=1000, prf=None, hmac_hash_module=None): """Derive one or more keys from a password (or passphrase). This function performs key derivation according to the PKCS#5 standard (v2.0). Args: password (string or byte string): The secret password to generate the key from. salt (string or byte string): A (byte) string to use for better protection from dictionary attacks. This value does not need to be kept secret, but it should be randomly chosen for each derivation. It is recommended to use at least 16 bytes. dkLen (integer): The cumulative length of the keys to produce. Due to a flaw in the PBKDF2 design, you should not request more bytes than the ``prf`` can output. For instance, ``dkLen`` should not exceed 20 bytes in combination with ``HMAC-SHA1``. count (integer): The number of iterations to carry out. The higher the value, the slower and the more secure the function becomes. You should find the maximum number of iterations that keeps the key derivation still acceptable on the slowest hardware you must support. Although the default value is 1000, **it is recommended to use at least 1000000 (1 million) iterations**. prf (callable): A pseudorandom function. It must be a function that returns a pseudorandom byte string from two parameters: a secret and a salt. The slower the algorithm, the more secure the derivation function. If not specified, **HMAC-SHA1** is used. hmac_hash_module (module): A module from ``Crypto.Hash`` implementing a Merkle-Damgard cryptographic hash, which PBKDF2 must use in combination with HMAC. This parameter is mutually exclusive with ``prf``. Return: A byte string of length ``dkLen`` that can be used as key material. If you want multiple keys, just break up this string into segments of the desired length. """ password = tobytes(password) salt = tobytes(salt) if prf and hmac_hash_module: raise ValueError("'prf' and 'hmac_hash_module' are mutually exlusive") if prf is None and hmac_hash_module is None: hmac_hash_module = SHA1 if prf or not hasattr(hmac_hash_module, "_pbkdf2_hmac_assist"): # Generic (and slow) implementation if prf is None: prf = lambda p, s: HMAC.new(p, s, hmac_hash_module).digest() def link(s): s[0], s[1] = s[1], prf(password, s[1]) return s[0] key = b'' i = 1 while len(key) < dkLen: s = [prf(password, salt + struct.pack(">I", i))] * 2 key += reduce(strxor, (link(s) for j in range(count))) i += 1 else: # Optimized implementation key = b'' i = 1 while len(key) < dkLen: base = HMAC.new(password, b"", hmac_hash_module) first_digest = base.copy().update(salt + struct.pack(">I", i)).digest() key += base._pbkdf2_hmac_assist(first_digest, count) i += 1 return key[:dkLen]
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 xl(text): return tostr(hexlify(tobytes(text)))
class SHAKEVectors(unittest.TestCase): pass test_vectors_128 = load_tests(("Crypto", "SelfTest", "Hash", "test_vectors", "SHA3"), "ShortMsgKAT_SHAKE128.txt", "Short Messages KAT SHAKE128", { "len" : lambda x: int(x) } ) for idx, tv in enumerate(test_vectors_128): if tv.len == 0: data = b("") else: data = tobytes(tv.msg) def new_test(self, data=data, result=tv.md): hobj = SHAKE128.new(data=data) digest = hobj.read(len(result)) self.assertEqual(digest, result) setattr(SHAKEVectors, "test_128_%d" % idx, new_test) test_vectors_256 = load_tests(("Crypto", "SelfTest", "Hash", "test_vectors", "SHA3"), "ShortMsgKAT_SHAKE256.txt", "Short Messages KAT SHAKE256", { "len" : lambda x: int(x) } ) for idx, tv in enumerate(test_vectors_256):
def __init__(self, stash_key, value, manager_provider, aws_profile=None, aws_region=None, aws_bucket=None, kms_key='alias/novastash'): check_latest_version() self._aws_manager = manager_provider.aws_manager( aws_profile, aws_region or 'us-east-1') if aws_bucket is None: deployment_bucket_name = 'novastash_%s' % self._aws_manager.account_alias else: deployment_bucket_name = aws_bucket if not self._aws_manager.kms_key_exists(kms_key): raise NovaError("Please setup the novastash KMS key.") self._aws_manager.create_bucket( deployment_bucket_name, "Creating novastash bucket '%s'" % deployment_bucket_name) # generate a a 64 byte key. # Half will be for data encryption, the other half for HMAC kms_response = self._aws_manager.kms_generate_data_key(kms_key, {}) data_key = tobytes(kms_response['Plaintext'][:32]) hmac_key = tobytes(kms_response['Plaintext'][32:]) wrapped_key = tobytes(kms_response['CiphertextBlob']) enc_ctr = Counter.new(128) encryptor = AES.new(data_key, AES.MODE_CTR, counter=enc_ctr) c_text = encryptor.encrypt(tobytes(value)) # compute an HMAC using the hmac key and the ciphertext hmac = HMAC(hmac_key, msg=c_text, digestmod=SHA256) b64hmac = hmac.hexdigest() key = "%s.txt.enc" % stash_key existing_stash = self._aws_manager.s3_head(deployment_bucket_name, key) if existing_stash is None: print(colored("Stashing '%s'" % stash_key)) self._aws_manager.s3_put( deployment_bucket_name, b64encode(c_text).decode('utf-8'), key, { 'encryption-key': b64encode(wrapped_key).decode('utf-8'), 'hmac': b64hmac }) else: perform_overwrite = query_yes_no( "Stash '%s' already exists, want to overwrite?" % stash_key, default="no") if perform_overwrite: self._aws_manager.s3_put( deployment_bucket_name, b64encode(c_text).decode('utf-8'), key, { 'encryption-key': b64encode(wrapped_key).decode('utf-8'), 'hmac': b64hmac }) else: print(colored("Not stashing anything for key '%s'" % stash_key))