def getSecret(name, version="", region="us-east-1", table="credential-store"): ''' fetch and decrypt the secret called `name` ''' secretStore = Table(table, connection=boto.dynamodb2.connect_to_region(region)) if version == "": # do a consistent fetch of the credential with the highest version result_set = [x for x in secretStore.query_2(limit=1, reverse=True, consistent=True, name__eq=name)] if not result_set: raise ItemNotFound("Item {'name': '%s'} couldn't be found." % name) material = result_set[0] else: material = secretStore.get_item(name=name, version=version) kms = boto.kms.connect_to_region(region) # Check the HMAC before we decrypt to verify ciphertext integrity try: kms_response = kms.decrypt(b64decode(material['key'])) except: raise KmsError("Could not decrypt hmac key with KMS") key = kms_response['Plaintext'][:32] hmac_key = kms_response['Plaintext'][32:] hmac = HMAC(hmac_key, msg=b64decode(material['contents']), digestmod=SHA256) if hmac.hexdigest() != material['hmac']: raise IntegrityError("Computed HMAC on %s does not match stored HMAC" % name) dec_ctr = Counter.new(128) decryptor = AES.new(key, AES.MODE_CTR, counter=dec_ctr) plaintext = decryptor.decrypt(b64decode(material['contents'])) return plaintext
def test_decrypt__wrong_encryption_context(): kms = boto3.client('kms', region_name='us-west-2') key = kms.create_key() key_id = key['KeyMetadata']['KeyId'] encryption_context = {'Key': 'Value'} response = kms.encrypt(KeyId=key_id, Plaintext=b'my plaintext', EncryptionContext=encryption_context) ciphertext = response['CiphertextBlob'] key_id = response['KeyId'] with assert_raises(JSONResponseError): kms.decrypt(CiphertextBlob=ciphertext)
def getSecret(name, version="", region="us-east-1", table="credential-store", context=None): ''' fetch and decrypt the secret called `name` ''' if not context: context = {} secretStore = Table(table, connection=boto.dynamodb2.connect_to_region(region)) if version == "": # do a consistent fetch of the credential with the highest version result_set = [ x for x in secretStore.query_2( limit=1, reverse=True, consistent=True, name__eq=name) ] if not result_set: raise ItemNotFound("Item {'name': '%s'} couldn't be found." % name) material = result_set[0] else: material = secretStore.get_item(name=name, version=version) kms = boto3.client('kms', region_name=region) # Check the HMAC before we decrypt to verify ciphertext integrity try: kms_response = kms.decrypt(CiphertextBlob=b64decode(material['key']), EncryptionContext=context) except boto.kms.exceptions.InvalidCiphertextException: if context is None: msg = ("Could not decrypt hmac key with KMS. The credential may " "require that an encryption context be provided to decrypt " "it.") else: msg = ("Could not decrypt hmac key with KMS. The encryption " "context provided may not match the one used when the " "credential was stored.") raise KmsError(msg) except Exception as e: raise KmsError("Decryption error %s" % e) key = kms_response['Plaintext'][:32] hmac_key = kms_response['Plaintext'][32:] hmac = HMAC(hmac_key, msg=b64decode(material['contents']), digestmod=SHA256) if hmac.hexdigest() != material['hmac']: raise IntegrityError("Computed HMAC on %s does not match stored HMAC" % name) dec_ctr = Counter.new(128) decryptor = AES.new(key, AES.MODE_CTR, counter=dec_ctr) plaintext = decryptor.decrypt(b64decode( material['contents'])).decode("utf-8") return plaintext
def getSecret(name, version="", region="us-east-1", table="credential-store", context=None): ''' fetch and decrypt the secret called `name` ''' if not context: context = {} if version == "": # do a consistent fetch of the credential with the highest version # list all files matching pattern pass # if not result_set: # raise ItemNotFound("Item {'name': '%s'} couldn't be found." % name) # material = result_set[0] with open("{0}.{1}.json".format(name, version), 'r') as fp: material = json.load(fp) kms = boto3.client('kms', region_name=region) # Check the HMAC before we decrypt to verify ciphertext integrity try: kms_response = kms.decrypt(CiphertextBlob=b64decode(material['key']), EncryptionContext=context) except InvalidCiphertextException: if context is None: msg = ("Could not decrypt hmac key with KMS. The credential may " "require that an encryption context be provided to decrypt " "it.") else: msg = ("Could not decrypt hmac key with KMS. The encryption " "context provided may not match the one used when the " "credential was stored.") raise KmsError(msg) except Exception as e: raise KmsError("Decryption error %s" % e) key = kms_response['Plaintext'][:32] hmac_key = kms_response['Plaintext'][32:] hmac = HMAC(hmac_key, msg=b64decode(material['contents']), digestmod=SHA256) if hmac.hexdigest() != material['hmac']: raise IntegrityError("Computed HMAC on %s does not match stored HMAC" % name) dec_ctr = Counter.new(128) decryptor = AES.new(key, AES.MODE_CTR, counter=dec_ctr) plaintext = decryptor.decrypt(b64decode( material['contents'])).decode("utf-8") return plaintext
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): args = parse_kv(module_args) environment = args.get('environment') account_id = args.get('account_id') assume_role = args.get('assume_role') for name, val in (("environment", environment), ("account_id", account_id), ("assume_role", assume_role)): if val is None: result = dict(failed=True, msg="No {0} specified".format(name)) return ReturnData(conn=conn, comm_ok=True, result=result) source = template.template(self.runner.basedir, environment, inject) if '_original_file' in inject: source = utils.path_dwim_relative(inject['_original_file'], 'vars', source, self.runner.basedir) else: source = utils.path_dwim(self.runner.basedir, source) if os.path.exists(source): decrypted_data = {} data = json.load(open(source)) with assume(account_id, assume_role): kms = boto.kms.connect_to_region('ap-southeast-2') for key, val in data.items(): data_key = kms.decrypt(base64.b64decode( val['key']))["Plaintext"] content = base64.b64decode(val['content']) counter = Counter.new(128) decryptor = AES.new(data_key[:32], AES.MODE_CTR, counter=counter) decrypted_data[key] = decryptor.decrypt(content) result = dict(ansible_facts=decrypted_data) return ReturnData(conn=conn, comm_ok=True, result=result) else: result = dict(failed=True, msg="Couldn't find secrets!", file=source) return ReturnData(conn=conn, comm_ok=True, result=result)
def getSecret(name, version="", region="us-east-1", table="credential-store", context=None): ''' fetch and decrypt the secret called `name` ''' if not context: context = {} secretStore = Table(table, connection=boto.dynamodb2.connect_to_region(region)) if version == "": # do a consistent fetch of the credential with the highest version result_set = [x for x in secretStore.query_2(limit=1, reverse=True, consistent=True, name__eq=name)] if not result_set: raise ItemNotFound("Item {'name': '%s'} couldn't be found." % name) material = result_set[0] else: material = secretStore.get_item(name=name, version=version) kms = boto3.client('kms', region_name=region) # Check the HMAC before we decrypt to verify ciphertext integrity try: kms_response = kms.decrypt(CiphertextBlob=b64decode(material['key']), EncryptionContext=context) except boto.kms.exceptions.InvalidCiphertextException: if context is None: msg = ("Could not decrypt hmac key with KMS. The credential may " "require that an encryption context be provided to decrypt " "it.") else: msg = ("Could not decrypt hmac key with KMS. The encryption " "context provided may not match the one used when the " "credential was stored.") raise KmsError(msg) except Exception as e: raise KmsError("Decryption error %s" % e) key = kms_response['Plaintext'][:32] hmac_key = kms_response['Plaintext'][32:] hmac = HMAC(hmac_key, msg=b64decode(material['contents']), digestmod=SHA256) if hmac.hexdigest() != material['hmac']: raise IntegrityError("Computed HMAC on %s does not match stored HMAC" % name) dec_ctr = Counter.new(128) decryptor = AES.new(key, AES.MODE_CTR, counter=dec_ctr) plaintext = decryptor.decrypt(b64decode(material['contents'])).decode("utf-8") return plaintext
def getSecret(name, version="", region="us-east-1", table="credential-store", context=None): ''' fetch and decrypt the secret called `name` ''' if not context: context = {} if version == "": # do a consistent fetch of the credential with the highest version # list all files matching pattern pass # if not result_set: # raise ItemNotFound("Item {'name': '%s'} couldn't be found." % name) # material = result_set[0] with open("{0}.{1}.json".format(name, version), 'r') as fp: material = json.load(fp) kms = boto3.client('kms', region_name=region) # Check the HMAC before we decrypt to verify ciphertext integrity try: kms_response = kms.decrypt(CiphertextBlob=b64decode(material['key']), EncryptionContext=context) except InvalidCiphertextException: if context is None: msg = ("Could not decrypt hmac key with KMS. The credential may " "require that an encryption context be provided to decrypt " "it.") else: msg = ("Could not decrypt hmac key with KMS. The encryption " "context provided may not match the one used when the " "credential was stored.") raise KmsError(msg) except Exception as e: raise KmsError("Decryption error %s" % e) key = kms_response['Plaintext'][:32] hmac_key = kms_response['Plaintext'][32:] hmac = HMAC(hmac_key, msg=b64decode(material['contents']), digestmod=SHA256) if hmac.hexdigest() != material['hmac']: raise IntegrityError("Computed HMAC on %s does not match stored HMAC" % name) dec_ctr = Counter.new(128) decryptor = AES.new(key, AES.MODE_CTR, counter=dec_ctr) plaintext = decryptor.decrypt(b64decode(material['contents'])).decode("utf-8") return plaintext
def test_decrypt(): kms = boto3.client('kms', region_name='us-west-2') key = kms.create_key() key_id = key['KeyMetadata']['KeyId'] encryption_context = {'Key': 'Value'} response = kms.encrypt(KeyId=key_id, Plaintext=b'my plaintext', EncryptionContext=encryption_context) ciphertext = response['CiphertextBlob'] key_id = response['KeyId'] response = kms.decrypt(CiphertextBlob=ciphertext, EncryptionContext=encryption_context) plaintext = response['Plaintext'] response_key_id = response['KeyId'] assert response_key_id == key_id assert plaintext == b'my plaintext'
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): args = parse_kv(module_args) environment = args.get('environment') account_id = args.get('account_id') assume_role = args.get('assume_role') for name, val in (("environment", environment), ("account_id", account_id), ("assume_role", assume_role)): if val is None: result = dict(failed=True, msg="No {0} specified".format(name)) return ReturnData(conn=conn, comm_ok=True, result=result) source = template.template(self.runner.basedir, environment, inject) if '_original_file' in inject: source = utils.path_dwim_relative(inject['_original_file'], 'vars', source, self.runner.basedir) else: source = utils.path_dwim(self.runner.basedir, source) if os.path.exists(source): decrypted_data = {} data = json.load(open(source)) with assume(account_id, assume_role): kms = boto.kms.connect_to_region('ap-southeast-2') for key, val in data.items(): data_key = kms.decrypt(base64.b64decode(val['key']))["Plaintext"] content = base64.b64decode(val['content']) counter = Counter.new(128) decryptor = AES.new(data_key[:32], AES.MODE_CTR, counter=counter) decrypted_data[key] = decryptor.decrypt(content) result = dict(ansible_facts=decrypted_data) return ReturnData(conn=conn, comm_ok=True, result=result) else: result = dict(failed=True, msg="Couldn't find secrets!", file=source) return ReturnData(conn=conn, comm_ok=True, result=result)